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 027 * (APE). Note that you need the file "ape.exe" (which can be compiled from the Attempto APE 028 * distribution) and that 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 030 * path. This can be achieved by a Java VM argument which looks like this (for Mac OS X): 031 * 032 * <blockquote><code> 033 * -Djava.library.path=/opt/local/lib/swipl-5.6.45/lib/i386-darwin8.10.1 034 * </code></blockquote> 035 * 036 * Under Linux, the following environment variable has to be set additionally: 037 * 038 * <blockquote><code> 039 * LD_PRELOAD=/usr/lib/pl-5.6.45/lib/i386-linux/libjpl.so 040 * </code></blockquote> 041 * 042 * The exact paths are most probably different on your machine. Just look for the directory that 043 * contains the file or symbolic link <em>libjpl.jnilib</em> (under Mac OS X), <em>jpl.dll</em> 044 * (under Windows), or <em>libjpl.so</em> (under Unix). If you get the error message 045 * 046 * <blockquote><code> 047 * java.lang.UnsatisfiedLinkError: no jpl in java.library.path 048 * </code></blockquote> 049 * 050 * then this is a strong indication that the SWI Prolog JPL libraries are not found. 051 * 052 * 053 * @author Tobias Kuhn 054 */ 055 public class APELocal extends ACEParser { 056 057 private static APELocal apeLocal; 058 059 /** 060 * Creates a new parser object. You can create at most one such object per JVM. If you 061 * try to create more than one such object or if you called the init method before 062 * then a runtime exception is thrown. 063 * 064 * @param apeExeFile The path (with filename) of the file "ape.exe". 065 */ 066 public APELocal(String apeExeFile) { 067 if (apeLocal != null) { 068 throw new RuntimeException("Only one APELocal object can be created."); 069 } 070 071 // A problem was reported that might be solved by using the --nosignals option. 072 // Otherwise, it seems to have no effect in our case. 073 // The first argument "swipl" has no effect and could be any other string. 074 JPL.init(new String[] {"swipl", "-x", apeExeFile, "-g", "true", "--nosignals"}); 075 076 apeLocal = this; 077 } 078 079 /** 080 * Creates a new parser object. You can create at most one such object per JVM. If you 081 * try to create more than one such object or if you called the init method before 082 * then a runtime exception is thrown. 083 * <br> 084 * This method is deprecated because the {@code prologCommand} argument is actually not needed. 085 * Use {@link #APELocal(String)} instead. 086 * 087 * @param prologCommand The command to run the SWI Prolog interpreter. 088 * On Windows this is usually "plcon", on Linux "pl", and on Mac "swipl". 089 * @param apeExeFile The path (with filename) of the file "ape.exe". 090 */ 091 @Deprecated 092 public APELocal(String prologCommand, String apeExeFile) { 093 this(apeExeFile); 094 } 095 096 /** 097 * Returns the singleton APELocal instance. Null is returned if the APELocal instance has not yet 098 * been initialized by the constructor or the init method. 099 * 100 * @return The singleton APELocal instance. 101 */ 102 public static APELocal getInstance() { 103 return apeLocal; 104 } 105 106 /** 107 * Initializes the APELocal singleton instance. This method can be called at most once. 108 * If you call it twice or if you called the constructor before then a runtime exception 109 * is thrown. 110 * 111 * @param apeExeFile The path (with filename) of the file "ape.exe". 112 */ 113 public static void init(String apeExeFile) { 114 new APELocal(apeExeFile); 115 } 116 117 /** 118 * Initializes the APELocal singleton instance. This method can be called at most once. 119 * If you call it twice or if you called the constructor before then a runtime exception 120 * is thrown. 121 * <br> 122 * This method is deprecated because the {@code prologCommand} argument is actually not needed. 123 * Use {@link #init(String)} instead. 124 * 125 * @param prologCommand The command to run the SWI Prolog interpreter. 126 * On Windows this is usually "plcon", on Linux "pl", and on Mac "swipl". 127 * @param apeExeFile The path (with filename) of the file "ape.exe". 128 */ 129 @Deprecated 130 public static void init(String prologCommand, String apeExeFile) { 131 new APELocal(prologCommand, apeExeFile); 132 } 133 134 /** 135 * Checks whether the singleton instance has already been initialized. 136 * 137 * @return true if the singleton instance has been initialized. 138 */ 139 public static boolean isInitialized() { 140 return apeLocal != null; 141 } 142 143 public synchronized String getSoloOutput(String text, Lexicon lexicon, OutputType outputType) throws ACEParserException { 144 clearMessages(); 145 String ulextext = ""; 146 if (lexicon != null) { 147 ulextext = ",ulextext=" + PrologUtils.escape(lexicon.toString()); 148 } 149 Term input = Util.textToTerm("[text=" + PrologUtils.escape(text) + ulextext + ",solo=" + outputType.toString().toLowerCase() + getOptions() + "]"); 150 Query q = new Query("get_ape_results", new Term[] {input, new Variable("Result")}); 151 Atom result = (Atom) q.oneSolution().get("Result"); 152 String s = result.name(); 153 154 return checkForErrors(s); 155 } 156 157 public synchronized ACEParserResult getMultiOutput(String text, Lexicon lexicon, OutputType... outputTypes) { 158 clearMessages(); 159 String outputs = ""; 160 for (OutputType t : outputTypes) { 161 outputs += ",c" + t.toString().toLowerCase() + "=on"; 162 } 163 String ulextext = ""; 164 if (lexicon != null) { 165 ulextext = ",ulextext=" + PrologUtils.escape(lexicon.toString()); 166 } 167 Term input = Util.textToTerm("[text=" + PrologUtils.escape(text) + ulextext + outputs + getOptions() + "]"); 168 Query q = new Query("get_ape_results", new Term[] {input, new Variable("Result")}); 169 Atom result = (Atom) q.oneSolution().get("Result"); 170 return new ACEParserResult(result.name()); 171 } 172 173 /** 174 * Loads the lexicon by adding all lexicon entries of the lexicon. Note that these lexicon entries 175 * are automatically discarded the first time you call getSoloOutput or getMultiOutput with a lexicon 176 * parameter that is not null. 177 * 178 * @param lexicon The lexicon to be loaded. 179 * @see #addLexiconEntry 180 * @see #discardLexicon 181 */ 182 public synchronized void addLexicon(Lexicon lexicon) { 183 clearMessages(); 184 Query q = new Query(new Compound("add_lexicon_entries", new Term[] { Util.textToTerm(lexicon.toList()) })); 185 q.oneSolution(); 186 } 187 188 /** 189 * Adds a new lexicon entry. Note that this lexicon entry is automatically discarded the first time 190 * you call getSoloOutput or getMultiOutput with a lexicon parameter that is not null. 191 * 192 * @param lexiconEntry The lexicon entry to be added. 193 * @see #addLexicon 194 * @see #discardLexicon 195 */ 196 public synchronized void addLexiconEntry(LexiconEntry lexiconEntry) { 197 clearMessages(); 198 Query q = new Query(new Compound("add_lexicon_entry", new Term[] { Util.textToTerm(lexiconEntry.toString()) }) ); 199 q.oneSolution(); 200 } 201 202 /** 203 * Discards the dynamically added lexicon entries. Note that the lexicon entries that are complied into 204 * the SWI Prolog executable are not affected by this operation. 205 * 206 * @see #addLexiconEntry 207 * @see #addLexicon 208 */ 209 public synchronized void discardLexicon() { 210 clearMessages(); 211 Query q = new Query("discard_ulex"); 212 q.oneSolution(); 213 } 214 215 private void clearMessages() { 216 Query q = new Query("clear_messages"); 217 q.oneSolution(); 218 } 219 }