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 }