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"});
065                    apeLocal = this;
066            }
067            
068            /**
069             * Returns the singleton APELocal instance. Null is returned if the APELocal instance has not yet
070             * been initialized by the constructor or the init method.
071             * 
072             * @return The singleton APELocal instance.
073             */
074            public static APELocal getInstance() {
075                    return apeLocal;
076            }
077            
078            /**
079             * Initializes the APELocal singleton instance. This method can be called at most once.
080             * If you call it twice or if you called the constructor before then a runtime exception
081             * is thrown.
082             * 
083             * @param prologCommand The command to run the SWI Prolog interpreter.
084             *     On Windows this is usually "plcon", on Linux "pl", and on Mac "swipl".
085             * @param apeExeFile The path (with filename) of the file "ape.exe".
086             */
087            public static void init(String prologCommand, String apeExeFile) {
088                    new APELocal(prologCommand, apeExeFile);
089            }
090            
091            /**
092             * Checks whether the singleton instance has already been initialized.
093             * 
094             * @return true if the singleton instance has been initialized.
095             */
096            public static boolean isInitialized() {
097                    return apeLocal != null;
098            }
099    
100            public synchronized String getSoloOutput(String text, Lexicon lexicon, OutputType outputType) throws ACEParserException {
101                    clearMessages();
102                    String ulextext = "";
103                    if (lexicon != null) {
104                            ulextext = ",ulextext=" + PrologUtils.escape(lexicon.toString());
105                    }
106                    Term input = Util.textToTerm("[text=" + PrologUtils.escape(text) + ulextext + ",solo=" + outputType.toString().toLowerCase() + getOptions() + "]");
107                    Query q = new Query("get_ape_results", new Term[] {input, new Variable("Result")});
108                    Atom result = (Atom) q.oneSolution().get("Result");
109                    String s = result.name();
110    
111                    return checkForErrors(s);
112            }
113    
114            public synchronized ACEParserResult getMultiOutput(String text, Lexicon lexicon, OutputType... outputTypes) {
115                    clearMessages();
116                    String outputs = "";
117                    for (OutputType t : outputTypes) {
118                            outputs += ",c" + t.toString().toLowerCase() + "=on";
119                    }
120                    String ulextext = "";
121                    if (lexicon != null) {
122                            ulextext = ",ulextext=" + PrologUtils.escape(lexicon.toString());
123                    }
124                    Term input = Util.textToTerm("[text=" + PrologUtils.escape(text) + ulextext + outputs + getOptions() + "]");
125                    Query q = new Query("get_ape_results", new Term[] {input, new Variable("Result")});
126                    Atom result = (Atom) q.oneSolution().get("Result");
127                    return new ACEParserResult(result.name());
128            }
129    
130            /**
131             * Loads the lexicon by adding all lexicon entries of the lexicon. Note that these lexicon entries
132             * are automatically discarded the first time you call getSoloOutput or getMultiOutput with a lexicon
133             * parameter that is not null.
134             * 
135             * @param lexicon The lexicon to be loaded.
136             * @see #addLexiconEntry
137             * @see #discardLexicon
138             */
139            public synchronized void addLexicon(Lexicon lexicon) {
140                    clearMessages();
141                    Query q = new Query(new Compound("add_lexicon_entries", new Term[] { Util.textToTerm(lexicon.toList()) }));
142                    q.oneSolution();
143            }
144    
145            /**
146             * Adds a new lexicon entry. Note that this lexicon entry is automatically discarded the first time
147             * you call getSoloOutput or getMultiOutput with a lexicon parameter that is not null.
148             * 
149             * @param lexiconEntry The lexicon entry to be added.
150             * @see #addLexicon
151             * @see #discardLexicon
152             */
153            public synchronized void addLexiconEntry(LexiconEntry lexiconEntry) {
154                    clearMessages();
155                    Query q = new Query(new Compound("add_lexicon_entry", new Term[] { Util.textToTerm(lexiconEntry.toString()) }) );
156                    q.oneSolution();
157            }
158    
159            /**
160             * Discards the dynamically added lexicon entries. Note that the lexicon entries that are complied into
161             * the SWI Prolog executable are not affected by this operation.
162             *
163             * @see #addLexiconEntry
164             * @see #addLexicon
165             */
166            public synchronized void discardLexicon() {
167                    clearMessages();
168                    Query q = new Query("discard_ulex");
169                    q.oneSolution();
170            }
171    
172            private void clearMessages() {
173                    Query q = new Query("clear_messages");
174                    q.oneSolution();
175            }
176    }