initial commit
| 1 | /* |
| 2 | Copyright 2008 Olaf Hartig |
| 3 | |
| 4 | This file is part of SQUIN. |
| 5 | |
| 6 | SQUIN is free software: you can redistribute it and/or modify |
| 7 | it under the terms of the GNU General Public License as published by |
| 8 | the Free Software Foundation, either version 3 of the License, or |
| 9 | (at your option) any later version. |
| 10 | |
| 11 | SQUIN is distributed in the hope that it will be useful, |
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | GNU General Public License for more details. |
| 15 | |
| 16 | You should have received a copy of the GNU General Public License |
| 17 | along with SQUIN. If not, see <http://www.gnu.org/licenses/>. |
| 18 | */ |
| 19 | package org.squin.servlet; |
| 20 | |
| 21 | import java.io.IOException; |
| 22 | import java.io.OutputStream; |
| 23 | import java.io.UnsupportedEncodingException; |
| 24 | |
| 25 | import java.net.URLDecoder; |
| 26 | |
| 27 | import java.util.Arrays; |
| 28 | import java.util.HashMap; |
| 29 | import java.util.Iterator; |
| 30 | import java.util.List; |
| 31 | import java.util.Map; |
| 32 | |
| 33 | import javax.naming.Context; |
| 34 | import javax.naming.InitialContext; |
| 35 | import javax.naming.NameNotFoundException; |
| 36 | import javax.naming.NamingException; |
| 37 | import javax.servlet.http.HttpServlet; |
| 38 | import javax.servlet.http.HttpServletRequest; |
| 39 | import javax.servlet.http.HttpServletResponse; |
| 40 | |
| 41 | import org.apache.commons.logging.Log; |
| 42 | import org.apache.commons.logging.LogFactory; |
| 43 | |
| 44 | import com.hp.hpl.jena.util.FileManager; |
| 45 | import com.hp.hpl.jena.query.Query; |
| 46 | import com.hp.hpl.jena.query.QueryException; |
| 47 | import com.hp.hpl.jena.query.QueryExecution; |
| 48 | import com.hp.hpl.jena.query.QueryExecutionFactory; |
| 49 | import com.hp.hpl.jena.query.QueryFactory; |
| 50 | import com.hp.hpl.jena.query.ResultSet; |
| 51 | import com.hp.hpl.jena.query.ResultSetFormatter; |
| 52 | import com.hp.hpl.jena.sparql.resultset.ResultSetMem; |
| 53 | import com.hp.hpl.jena.sparql.util.Utils; |
| 54 | |
| 55 | import de.fuberlin.wiwiss.ng4j.semwebclient.SemanticWebClient; |
| 56 | |
| 57 | |
| 58 | /** |
| 59 | * The servlet that processes requests to the SQUIN service. |
| 60 | * |
| 61 | * @author Olaf Hartig |
| 62 | */ |
| 63 | public class Servlet extends HttpServlet |
| 64 | { |
| 65 | // members |
| 66 | |
| 67 | static private Log log = LogFactory.getLog( Servlet.class ); |
| 68 | |
| 69 | static final public String MIME_TYPE_RESULT_XML = "application/sparql-results+xml"; |
| 70 | static final public String MIME_TYPE_RESULT_JSON = "application/sparql-results+json"; |
| 71 | static final public String MIME_TYPE_XML1 = "application/xml"; |
| 72 | static final public String MIME_TYPE_XML2 = "text/xml"; |
| 73 | static final public String MIME_TYPE_JSON = "application/json"; |
| 74 | |
| 75 | static private Context namingContext = null; |
| 76 | |
| 77 | |
| 78 | // initialization |
| 79 | |
| 80 | public Servlet () |
| 81 | { |
| 82 | } |
| 83 | |
| 84 | |
| 85 | // implementation of the HttpServlet interface |
| 86 | |
| 87 | protected void doGet ( HttpServletRequest req, HttpServletResponse resp ) |
| 88 | { |
| 89 | log.info( "Start processing request " + req.hashCode() + "." ); |
| 90 | // log.info( "real path: " + getServletContext().getRealPath("WW") ); |
| 91 | log.info( "getInitialFilesDirectory: " + getInitialFilesDirectory() ); |
| 92 | |
| 93 | String accept = req.getHeader( "ACCEPT" ); |
| 94 | if ( accept != null |
| 95 | && ! accept.contains(MIME_TYPE_RESULT_XML) |
| 96 | && ! accept.contains(MIME_TYPE_XML1) |
| 97 | && ! accept.contains(MIME_TYPE_XML2) |
| 98 | && ! accept.contains(MIME_TYPE_RESULT_JSON) |
| 99 | && ! accept.contains(MIME_TYPE_JSON) |
| 100 | && ! accept.contains("application/*") |
| 101 | && ! accept.contains("*/*") ) |
| 102 | { |
| 103 | log.info( "NOT ACCEPTABLE for request " + req.hashCode() + " (ACCEPT header field: " + accept + ")" ); |
| 104 | |
| 105 | try { |
| 106 | resp.sendError( HttpServletResponse.SC_NOT_ACCEPTABLE, "Your client does not seem to accept '" + MIME_TYPE_RESULT_XML + "'." ); |
| 107 | } catch ( IOException e ) { |
| 108 | log.error( "Sending the error reponse to request " + req.hashCode() + " caused a " + Utils.className(e) + ": " + e.getMessage(), e ); |
| 109 | } |
| 110 | |
| 111 | return; |
| 112 | } |
| 113 | |
| 114 | // get (and check) the request parameters |
| 115 | String errorMsgs = ""; |
| 116 | // - the SPARQL query |
| 117 | Query query = null; |
| 118 | String queryString = req.getParameter("query"); |
| 119 | if ( queryString == null || queryString.isEmpty() ) |
| 120 | { |
| 121 | errorMsgs += "Query not specified. "; |
| 122 | } |
| 123 | else |
| 124 | { |
| 125 | try |
| 126 | { |
| 127 | query = QueryFactory.create( queryString ); |
| 128 | if ( ! query.isSelectType() ) { |
| 129 | errorMsgs += "Query must be a SELECT query. "; |
| 130 | } |
| 131 | } |
| 132 | catch ( QueryException e ) { |
| 133 | errorMsgs += e.getMessage() + " "; |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | // - the output type |
| 138 | String responseContentType = null; |
| 139 | String output = req.getParameter("output"); |
| 140 | if ( output != null ) |
| 141 | { |
| 142 | if ( output.equals("json") ) { |
| 143 | responseContentType = MIME_TYPE_RESULT_JSON; |
| 144 | } else if ( output.equals("xml") ) { |
| 145 | responseContentType = MIME_TYPE_RESULT_XML; |
| 146 | } else { |
| 147 | errorMsgs += "Unsupported output format requested. "; |
| 148 | } |
| 149 | } |
| 150 | else |
| 151 | { |
| 152 | if ( accept != null |
| 153 | && ( accept.contains(MIME_TYPE_RESULT_JSON) |
| 154 | || accept.contains(MIME_TYPE_RESULT_JSON) ) ) { |
| 155 | responseContentType = MIME_TYPE_RESULT_JSON; |
| 156 | } else { |
| 157 | responseContentType = MIME_TYPE_RESULT_XML; |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | if ( ! errorMsgs.isEmpty() ) |
| 162 | { |
| 163 | log.info( "BAD REQUEST for request " + req.hashCode() + ": " + errorMsgs ); |
| 164 | |
| 165 | try { |
| 166 | resp.sendError( HttpServletResponse.SC_BAD_REQUEST, errorMsgs ); |
| 167 | } catch ( IOException e ) { |
| 168 | log.error( "Sending the error reponse to request " + req.hashCode() + " caused a " + Utils.className(e) + ": " + e.getMessage(), e ); |
| 169 | } |
| 170 | |
| 171 | return; |
| 172 | } |
| 173 | |
| 174 | // execute the query |
| 175 | log.info( "Start executing request " + req.hashCode() + " with query:" ); |
| 176 | log.info( queryString ); |
| 177 | QueryExecution qe = QueryExecutionFactory.create( query, |
| 178 | getSemanticWebClient().asJenaModel("default") ); |
| 179 | ResultSetMem rs = new ResultSetMem( qe.execSelect() ); |
| 180 | // ResultSet rs = qe.execSelect(); |
| 181 | |
| 182 | log.info( "Created the result set (size: " + rs.size() + ") for request " + req.hashCode() + "." ); |
| 183 | |
| 184 | // create the response |
| 185 | OutputStream out = null; |
| 186 | try { |
| 187 | out = resp.getOutputStream(); |
| 188 | } |
| 189 | catch ( IOException e ) |
| 190 | { |
| 191 | log.error( "Getting the response output stream for request " + req.hashCode() + " caused a " + Utils.className(e) + ": " + e.getMessage(), e ); |
| 192 | |
| 193 | try { |
| 194 | resp.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR ); |
| 195 | } catch ( IOException e2 ) { |
| 196 | log.error( "Sending the error reponse for request " + req.hashCode() + " caused a " + Utils.className(e2) + ": " + e2.getMessage(), e2 ); |
| 197 | } |
| 198 | |
| 199 | return; |
| 200 | } |
| 201 | |
| 202 | // write the response |
| 203 | resp.setContentType( responseContentType ); |
| 204 | try |
| 205 | { |
| 206 | if ( responseContentType == MIME_TYPE_RESULT_JSON ) { |
| 207 | ResultSetFormatter.outputAsJSON( out, rs ); |
| 208 | } else { |
| 209 | ResultSetFormatter.outputAsXML( out, rs ); |
| 210 | } |
| 211 | |
| 212 | log.info( "Result written to the response stream for request " + req.hashCode() + "." ); |
| 213 | } |
| 214 | catch ( Exception e ) |
| 215 | { |
| 216 | log.error( "Writing the model to the response stream for request " + req.hashCode() + " caused a " + Utils.className(e) + ": " + e.getMessage() ); |
| 217 | try { |
| 218 | resp.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR ); |
| 219 | } catch ( IOException e2 ) { |
| 220 | log.error( "Sending an error response for request " + req.hashCode() + " caused a " + Utils.className(e2) + ": " + e2.getMessage(), e2 ); |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | // finish |
| 225 | try |
| 226 | { |
| 227 | out.flush(); |
| 228 | resp.flushBuffer(); |
| 229 | log.info( "Response buffer for request " + req.hashCode() + " flushed." ); |
| 230 | } |
| 231 | catch ( IOException e ) |
| 232 | { |
| 233 | log.error( "Flushing the response buffer for request " + req.hashCode() + " caused a " + Utils.className(e) + ": " + e.getMessage(), e ); |
| 234 | } |
| 235 | |
| 236 | log.info( "Finished processing request " + req.hashCode() + "." ); |
| 237 | } |
| 238 | |
| 239 | |
| 240 | // helper methods |
| 241 | |
| 242 | private SemanticWebClient getSemanticWebClient () |
| 243 | { |
| 244 | SemanticWebClient semweb = (SemanticWebClient) getServletContext().getAttribute( "org.squin.servlet.Servlet.semanticWebClient" ); |
| 245 | if ( semweb == null ) |
| 246 | { |
| 247 | semweb = createSemanticWebClient(); |
| 248 | getServletContext().setAttribute( "org.squin.servlet.Servlet.semanticWebClient", semweb ); |
| 249 | } |
| 250 | |
| 251 | return semweb; |
| 252 | } |
| 253 | |
| 254 | private SemanticWebClient createSemanticWebClient () |
| 255 | { |
| 256 | log.debug( "Creating new SemanticWebClient object for the servlet." ); |
| 257 | |
| 258 | SemanticWebClient semweb = new SemanticWebClient(); |
| 259 | |
| 260 | semweb.setConfig( SemanticWebClient.CONFIG_MAXTHREADS, "50" ); |
| 261 | semweb.setConfig( SemanticWebClient.CONFIG_MAXSTEPS, "5" ); |
| 262 | semweb.setConfig( SemanticWebClient.CONFIG_DEREF_CONNECT_TIMEOUT, "9000" ); |
| 263 | semweb.setConfig( SemanticWebClient.CONFIG_DEREF_READ_TIMEOUT, "9000" ); |
| 264 | |
| 265 | return semweb; |
| 266 | } |
| 267 | |
| 268 | // static private void loadInitialGraphs ( SemanticWebClient semweb ) |
| 269 | // { |
| 270 | // |
| 271 | // |
| 272 | // FileManager fm = new FileManager(); |
| 273 | // fm.addLocatorFile( "tests" + FileManager.filePathSeparator + "data" ); |
| 274 | // |
| 275 | // try { |
| 276 | // dataModel = fm.loadModel( "data1.n3" ); |
| 277 | // } catch ( Exception e ) { |
| 278 | // throw new Exception( "Loading the file with our test data caused a " + Utils.className(e) + ": " + e.getMessage(), e ); |
| 279 | // } |
| 280 | // |
| 281 | // } |
| 282 | // |
| 283 | |
| 284 | static protected String getInitialFilesDirectory () |
| 285 | { |
| 286 | Context nCtx = getNamingContext(); |
| 287 | |
| 288 | try { |
| 289 | return (String) nCtx.lookup( "InitialFilesDirectory" ); |
| 290 | } catch ( NameNotFoundException e ) { |
| 291 | return null; |
| 292 | } catch ( NamingException e ) { |
| 293 | throw new Error( "Looking up the object named 'InitialFilesDirectory' caused a " + Utils.className(e) + ": " + e.getMessage(), e ); |
| 294 | } |
| 295 | } |
| 296 | |
| 297 | static protected Context getNamingContext () |
| 298 | { |
| 299 | if ( namingContext == null ) |
| 300 | { |
| 301 | try { |
| 302 | namingContext = (Context) ( new InitialContext() ).lookup( "java:comp/env" ); |
| 303 | } catch ( NamingException e ) { |
| 304 | throw new Error( "Looking up the application naming context caused a " + Utils.className(e) + ": " + e.getMessage(), e ); |
| 305 | } |
| 306 | } |
| 307 | |
| 308 | return namingContext; |
| 309 | } |
| 310 | |
| 311 | } |
Copyright © 2010 Geeknet, Inc. All rights reserved. Terms of Use