001    /***************************************************************************/
002    /*  Copyright (C) 2010-2011, Sebastian Hellmann                            */
003    /*  Note: If you need parts of NLP2RDF in another licence due to licence   */
004    /*  incompatibility, please mail hellmann@informatik.uni-leipzig.de        */
005    /*                                                                         */
006    /*  This file is part of NLP2RDF.                                          */
007    /*                                                                         */
008    /*  NLP2RDF is free software; you can redistribute it and/or modify        */
009    /*  it under the terms of the GNU General Public License as published by   */
010    /*  the Free Software Foundation; either version 3 of the License, or      */
011    /*  (at your option) any later version.                                    */
012    /*                                                                         */
013    /*  NLP2RDF is distributed in the hope that it will be useful,             */
014    /*  but WITHOUT ANY WARRANTY; without even the implied warranty of         */
015    /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the           */
016    /*  GNU General Public License for more details.                           */
017    /*                                                                         */
018    /*  You should have received a copy of the GNU General Public License      */
019    /*  along with this program. If not, see <http://www.gnu.org/licenses/>.   */
020    /***************************************************************************/
021    
022    package org.nlp2rdf.webservice;
023    
024    import com.hp.hpl.jena.ontology.OntModel;
025    import com.hp.hpl.jena.ontology.OntModelSpec;
026    import com.hp.hpl.jena.rdf.model.ModelFactory;
027    import com.hp.hpl.jena.shared.JenaException;
028    import eu.lod2.nlp2rdf.schema.str.Document;
029    import org.apache.commons.lang.StringUtils;
030    import org.slf4j.Logger;
031    import org.slf4j.LoggerFactory;
032    
033    import javax.servlet.http.HttpServletRequest;
034    import java.io.ByteArrayInputStream;
035    import java.net.URLEncoder;
036    import java.security.InvalidParameterException;
037    import java.util.HashMap;
038    import java.util.List;
039    import java.util.Map;
040    
041    /**
042     * User: Sebastian Hellmann
043     * See    http://nlp2rdf.org/nif-1-0#toc-parameters
044     * A simple wrapper for the common options in NIF Services
045     * Use the following to retrieve the input variable:
046     * if (nifParameters.inputWasText()) {
047     * String text =  nifParameters.getInputAsText() ;
048     * }else {
049     * OntModel model = getInputAsOntModel();
050     * }
051     */
052    public class NIFParameters {
053        private static Logger log = LoggerFactory.getLogger(NIFParameters.class);
054    
055        //can be String or OntModel
056        private final Object input;
057        private final Map<String, String> parameterMap;
058    
059        private final String prefix;
060        private final String uriRecipe;
061        private final int contextLength;
062    
063        private final String format;
064    
065        //not in nif 1.0 diff or full
066        private final String output;
067    
068        public NIFParameters(Object input, Map<String, String> parameterMap, String prefix, String uriRecipe, int contextLength, String format, String output) {
069            this.input = input;
070            this.parameterMap = parameterMap;
071            this.prefix = prefix;
072            this.uriRecipe = uriRecipe;
073            this.contextLength = contextLength;
074            this.format = format;
075            this.output = output;
076        }
077    
078        /**
079         * Tests whether the input was text in opposition to inputWasRDF()
080         *
081         * @return true if the input is an instance of String
082         */
083        public boolean inputWasText() {
084            return input instanceof String;
085        }
086    
087        /**
088         * Tests whether the input was RDF in opposition to inputWasText()
089         *
090         * @return true if the input is an instance of OntModel
091         */
092        public boolean inputWasRDF() {
093            return input instanceof OntModel;
094        }
095    
096        /**
097         * Casts the input var to String
098         *
099         * @return the text of the input variable
100         * @throws ClassCastException
101         */
102        public String getInputAsText() throws ClassCastException {
103            return (String) input;
104        }
105    
106        /**
107         * Casts the input var to OntModel
108         *
109         * @return the OntModel  from the input variable
110         * @throws ClassCastException
111         */
112        public OntModel getInputAsOntModel() throws ClassCastException {
113            return (OntModel) input;
114        }
115    
116    
117        /**
118         * Factory method
119         *
120         * @param httpServletRequest
121         * @return
122         */
123        public static NIFParameters getInstance(HttpServletRequest httpServletRequest) {
124            String requestUrl = httpServletRequest.getRequestURL().toString();
125            try {
126    
127                //required Parameter input-type
128                String input_type = requiredParameter("input-type", httpServletRequest, "text", "nif-owl");
129    
130                if (!isSet("input", httpServletRequest)) {
131                    throw new IllegalArgumentException("Missing parameter: input is required. ");
132                }
133                //optional parameters
134                //note that nif=true is intentionally left out here, because it would be too late
135                String prefix = "http://nlp2rdf.lod2.eu/nif/";
136                String format = "rdfxml";
137                String urirecipe = "offset";
138                int contextLength = 10;
139                //this is not in the nif 1.0 spec
140                String output = "full";
141    
142                //prefix
143                if (isSet("prefix", httpServletRequest)) {
144                    prefix = httpServletRequest.getParameter("prefix");
145                }
146    
147                //format
148                if (isSet("format", httpServletRequest)) {
149                    format = requiredParameter("format", httpServletRequest, "rdfxml", "turtle", "json", "ntriples", "n3");
150                }
151                //urirecipe
152                if (isSet("urirecipe", httpServletRequest)) {
153                    urirecipe = requiredParameter("urirecipe", httpServletRequest, "offset", "context-hash");
154                }
155                //contextLength
156                if (isSet("context-length", httpServletRequest)) {
157                    contextLength = Integer.parseInt(httpServletRequest.getParameter("context-length"));
158                }
159                //output
160                if (isSet("output", httpServletRequest)) {
161                    output = requiredParameter("output", httpServletRequest, "full", "diff");
162                }
163    
164                Object input;
165                //normalize input, i.e. fill the variables for text and model
166                if (input_type.equals("text")) {
167                    log.trace("Handling type text");
168                    // read the text
169                    input = httpServletRequest.getParameter("input");
170                    //make a NIF model to work on
171                    //URIGenerator uriGenerator = ModelHelper.determineGenerator(urirecipe);
172                    //inputModel = new Text2RDF().processAsDocument(prefix, text, new FakeTokenizer(), uriGenerator);
173    
174                    /**********************
175                     * NOTE that parsing another NIF model is a little bit harder than just the output so this reference implementation is not yet complete.
176                     * *********************/
177                } else if (input_type.equals("nif-owl")) {
178                    // Read the model directly from the input
179                    OntModel inputModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_DL_MEM, ModelFactory.createDefaultModel());
180                    ByteArrayInputStream bais = new ByteArrayInputStream(httpServletRequest.getParameter("input").getBytes());
181                    try {
182                        inputModel.read(bais, "");
183                    } catch (JenaException e) {
184                        throw new InvalidParameterException("Jena could not read the presented nif-owl in RDF/XML format.\nFor the conversion of text \"input-type=text\" has to be set.");
185                    }
186                    input = inputModel;
187                } else {
188                    throw new InvalidParameterException("third way in a binary path: maybe");
189                }
190    
191                NIFParameters nifParameters = new NIFParameters(input, copyParameterMap(httpServletRequest), prefix, urirecipe, contextLength, format, output);
192                log.trace("created NIFParameters instance from " + input_type + ": " + nifParameters.toString());
193                return nifParameters;
194    
195            } catch (InvalidParameterException ipe) {
196                throw new InvalidParameterException(ipe.getMessage() + getDocumentation(requestUrl));
197            }
198        }
199    
200    
201        @Override
202        public String toString() {
203            return "NIFParameters{" +
204                    "input=" + input +
205                    ", parameterMap=" + parameterMap +
206                    ", prefix='" + prefix + '\'' +
207                    ", uriRecipe='" + uriRecipe + '\'' +
208                    ", format='" + format + '\'' +
209                    ", output='" + output + '\'' +
210                    '}';
211        }
212    
213        public Map<String, String> getParameterMap() {
214            return parameterMap;
215        }
216    
217        public String getPrefix() {
218            return prefix;
219        }
220    
221        public String getUriRecipe() {
222            return uriRecipe;
223        }
224    
225        public String getFormat() {
226            return format;
227        }
228    
229        public String getOutput() {
230            return output;
231        }
232    
233        public int getContextLength() {
234            return contextLength;
235        }
236    
237        public static String requiredParameter(String parameterName, HttpServletRequest hsr) {
238    
239            if (!isSet(parameterName, hsr)) {
240                throw new IllegalArgumentException("Missing parameter: " + parameterName + " is required. ");
241            }
242            return hsr.getParameter(parameterName);
243        }
244    
245        public static String requiredParameter(String parameterName, HttpServletRequest hsr, String... requiredValues) {
246            String value = requiredParameter(parameterName, hsr);
247            if (!oneOf(value, requiredValues)) {
248                throw new InvalidParameterException("Wrong value for parameter " + parameterName + ", value was: " + value + ", but must be one of ( " + StringUtils.join(requiredValues, ", ") + " ) ");
249            }
250            return value;
251        }
252    
253    
254        public static String getDocumentation(String serviceUrl) {
255            String doc = "";
256            try {
257                doc = "\nExample1: \n " + serviceUrl + "?input=" + URLEncoder.encode("That's a lot of nuts! That'll be four bucks, baby! You want fries with that? ", "UTF-8") + "&type=text";
258                doc += "\nExample2: \n " + serviceUrl + "?input=" + URLEncoder.encode("That's a lot of nuts! That's a lot of nuts! ", "UTF-8") + "&type=text";
259            } catch (Exception e) {
260                log.error("", e);
261            }
262            return doc;
263        }
264    
265        public static boolean oneOf(String value, String... possibleValues) {
266            for (String s : possibleValues) {
267                if (s.equals(value)) {
268                    return true;
269                }
270            }
271            return false;
272        }
273    
274        public static boolean isSet(String parameterName, HttpServletRequest hsr) {
275            boolean retVal = hsr.getParameterValues(parameterName) != null && hsr.getParameterValues(parameterName).length == 1 && hsr.getParameter(parameterName).length() > 0;
276            if (log.isTraceEnabled()) {
277                log.trace("Parameter " + parameterName + " isSet: " + retVal + " with value: " + hsr.getParameter(parameterName) + ")");
278            }
279            return retVal;
280        }
281    
282        public static Map<String, String> copyParameterMap(HttpServletRequest httpServletRequest) {
283            Map<String, String> ret = new HashMap<String, String>();
284            for (Object key : httpServletRequest.getParameterMap().keySet()) {
285                ret.put((String) key, httpServletRequest.getParameter((String) key));
286            }
287            return ret;
288        }
289    
290    }