Java tutorial
/* begin license * * * The Meresco Owlim package consists out of a HTTP server written in Java that * provides access to an Owlim Triple store, as well as python bindings to * communicate as a client with the server. * * Copyright (C) 2011-2014 Seecr (Seek You Too B.V.) http://seecr.nl * Copyright (C) 2011 Seek You Too B.V. (CQ2) http://www.cq2.nl * * This file is part of "Meresco Owlim" * * "Meresco Owlim" is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * "Meresco Owlim" is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with "Meresco Owlim"; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * end license */ package org.meresco.triplestore; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.Headers; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.io.IOException; import java.io.BufferedWriter; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.concurrent.ExecutorService; import java.util.ArrayList; import java.net.URI; import org.apache.commons.lang3.StringEscapeUtils; import org.openrdf.query.resultio.TupleQueryResultFormat; import org.openrdf.rio.RDFParseException; import org.openrdf.model.Namespace; import org.openrdf.model.Value; import org.openrdf.model.impl.URIImpl; import org.openrdf.model.impl.LiteralImpl; import org.openrdf.repository.RepositoryException; import org.openrdf.query.MalformedQueryException; import org.openrdf.query.QueryLanguage; import org.openrdf.query.parser.ParsedQuery; import org.openrdf.query.parser.ParsedGraphQuery; import org.openrdf.query.parser.QueryParserUtil; import org.openrdf.rio.Rio; import org.openrdf.rio.RDFFormat; public class HttpHandler implements com.sun.net.httpserver.HttpHandler { Triplestore tripleStore; RdfValidator validator; List<String> allowed_contenttypes; public HttpHandler(Triplestore tripleStore) { this.tripleStore = tripleStore; this.validator = new RdfValidator(); } public void handle(HttpExchange exchange) throws IOException { OutputStream outputStream = exchange.getResponseBody(); URI requestURI = exchange.getRequestURI(); String path = requestURI.getPath(); String rawQueryString = requestURI.getRawQuery(); Headers requestHeaders = exchange.getRequestHeaders(); try { QueryParameters httpArguments = Utils.parseQS(rawQueryString); if ("/add".equals(path)) { String body = Utils.read(exchange.getRequestBody()); try { addData(httpArguments, requestHeaders, body); } catch (RDFParseException e) { exchange.sendResponseHeaders(400, 0); _writeResponse(e.toString(), outputStream); return; } } else if ("/update".equals(path)) { String body = Utils.read(exchange.getRequestBody()); try { updateData(httpArguments, requestHeaders, body); } catch (RDFParseException e) { exchange.sendResponseHeaders(400, 0); _writeResponse(e.toString(), outputStream); return; } } else if ("/delete".equals(path)) { deleteData(httpArguments); } else if ("/addTriple".equals(path)) { String body = Utils.read(exchange.getRequestBody()); addTriple(body); } else if ("/removeTriple".equals(path)) { String body = Utils.read(exchange.getRequestBody()); removeTriple(body); } else if ("/query".equals(path)) { String response = ""; Headers responseHeaders = exchange.getResponseHeaders(); try { long start = System.currentTimeMillis(); String query = httpArguments.singleValue("query"); List<String> responseTypes = getResponseTypes(requestHeaders, httpArguments); if (query != null) { ParsedQuery p = QueryParserUtil.parseQuery(QueryLanguage.SPARQL, query, null); if (p instanceof ParsedGraphQuery) { response = executeGraphQuery(query, responseTypes, responseHeaders); } else { response = executeTupleQuery(query, responseTypes, responseHeaders); } } long indexQueryTime = System.currentTimeMillis() - start; if (response == null || response == "") { String responseBody = "Supported formats SELECT query:\n"; Iterator<TupleQueryResultFormat> i = TupleQueryResultFormat.values().iterator(); while (i.hasNext()) { responseBody += "- " + i.next() + "\n"; } responseBody += "\nSupported formats DESCRIBE query:\n"; Iterator<RDFFormat> j = RDFFormat.values().iterator(); while (j.hasNext()) { responseBody += "- " + j.next() + "\n"; } responseHeaders.set("Content-Type", "text/plain"); exchange.sendResponseHeaders(406, 0); _writeResponse(responseBody, outputStream); return; } responseHeaders.set("X-Meresco-Triplestore-QueryTime", String.valueOf(indexQueryTime)); if (httpArguments.containsKey("outputContentType")) { responseHeaders.set("Content-Type", httpArguments.singleValue("outputContentType")); } exchange.sendResponseHeaders(200, 0); _writeResponse(response, outputStream); } catch (MalformedQueryException e) { exchange.sendResponseHeaders(400, 0); _writeResponse(e.toString(), outputStream); } return; } else if ("/sparql".equals(path)) { String response = sparqlForm(httpArguments); Headers headers = exchange.getResponseHeaders(); headers.set("Content-Type", "text/html"); exchange.sendResponseHeaders(200, 0); _writeResponse(response, outputStream); } else if ("/validate".equals(path)) { String body = Utils.read(exchange.getRequestBody()); exchange.sendResponseHeaders(200, 0); try { validateRDF(httpArguments, body); _writeResponse("Ok", outputStream); } catch (RDFParseException e) { _writeResponse("Invalid\n" + e.toString(), outputStream); } } else if ("/export".equals(path)) { export(httpArguments); } else if ("/import".equals(path)) { String body = Utils.read(exchange.getRequestBody()); importTrig(body); } else { exchange.sendResponseHeaders(404, 0); return; } exchange.sendResponseHeaders(200, 0); } catch (IllegalArgumentException e) { exchange.sendResponseHeaders(400, 0); _writeResponse(e.toString(), outputStream); } catch (RuntimeException e) { e.printStackTrace(); exchange.sendResponseHeaders(500, 0); String response = Utils.getStackTrace(e); //System.out.println(response); _writeResponse(response, outputStream); return; } catch (Error e) { e.printStackTrace(); exchange.sendResponseHeaders(500, 0); _writeResponse(e.getMessage(), outputStream); exchange.getHttpContext().getServer().stop(0); ((ExecutorService) exchange.getHttpContext().getServer().getExecutor()).shutdownNow(); return; } finally { exchange.close(); } } private void _writeResponse(String response, OutputStream stream) { try { Writer writer = new BufferedWriter(new OutputStreamWriter(stream, "UTF-8")); writer.write(response, 0, response.length()); writer.close(); } catch (Exception e) { e.printStackTrace(); } } private RDFFormat getRdfFormat(Headers requestHeaders) { String accept = requestHeaders.getFirst("Content-Type"); return RDFFormat.forMIMEType(accept, RDFFormat.RDFXML); } public synchronized void updateData(QueryParameters httpArguments, Headers requestHeaders, String httpBody) throws RDFParseException { String identifier = httpArguments.singleValue("identifier"); this.tripleStore.delete(identifier); this.tripleStore.add(identifier, httpBody, getRdfFormat(requestHeaders)); } public synchronized void addData(QueryParameters httpArguments, Headers requestHeaders, String httpBody) throws RDFParseException { String identifier = httpArguments.singleValue("identifier"); this.tripleStore.add(identifier, httpBody, getRdfFormat(requestHeaders)); } public synchronized void addTriple(String httpBody) { this.tripleStore.addTriple(httpBody); } public synchronized void deleteData(QueryParameters httpArguments) { String identifier = httpArguments.singleValue("identifier"); this.tripleStore.delete(identifier); } public synchronized void removeTriple(String httpBody) { this.tripleStore.removeTriple(httpBody); } public List<String> getResponseTypes(Headers requestHeaders, QueryParameters httpArguments) { if (httpArguments.containsKey("mimeType")) { return httpArguments.get("mimeType"); } else if (requestHeaders.containsKey("Accept")) { return Arrays.asList(requestHeaders.getFirst("Accept").replace(", ", ",").split(",")); } return new ArrayList<String>(0); } public String executeTupleQuery(String query, List<String> responseTypes, Headers responseHeaders) throws MalformedQueryException { TupleQueryResultFormat resultFormat = TupleQueryResultFormat.JSON; for (String responseType : responseTypes) { TupleQueryResultFormat format = TupleQueryResultFormat.forMIMEType(responseType); if (format != null) { resultFormat = format; break; } } responseHeaders.set("Content-Type", resultFormat.getDefaultMIMEType()); return this.tripleStore.executeTupleQuery(query, resultFormat); } public String executeGraphQuery(String query, List<String> responseTypes, Headers responseHeaders) throws MalformedQueryException { RDFFormat resultFormat = RDFFormat.RDFXML; for (String responseType : responseTypes) { RDFFormat format = Rio.getParserFormatForMIMEType(responseType); if (format != null) { resultFormat = format; break; } } responseHeaders.set("Content-Type", resultFormat.getDefaultMIMEType()); return this.tripleStore.executeGraphQuery(query, resultFormat); } public void validateRDF(QueryParameters httpArguments, String httpBody) throws RDFParseException { validator.validate(httpBody); } public void export(QueryParameters httpArguments) { String identifier = httpArguments.singleValue("identifier"); this.tripleStore.export(identifier); } public synchronized void importTrig(String trig) { this.tripleStore.importTrig(trig); } public String sparqlForm(QueryParameters httpArguments) { String query; if (httpArguments.containsKey("query")) { query = httpArguments.singleValue("query"); } else { query = ""; for (Namespace namespace : this.tripleStore.getNamespaces()) { query += "PREFIX " + namespace.getPrefix() + ": <" + namespace.getName() + ">\n"; } query += "\nSELECT ?subject ?predicate ?object\n"; query += "WHERE { ?subject ?predicate ?object }\n"; query += "LIMIT 50"; } return "<html><head><title>Meresco Triplestore Sparql Form</title></head>\n" + "<body><form action=\"/query\">\n" + "<textarea cols=\"100\" rows=\"20\" name=\"query\">" + StringEscapeUtils.escapeXml(query) + "</textarea><br/>\n" + "<input type=\"hidden\" name=\"outputContentType\" value=\"application/json\"/>\n" + "Format: <select name=\"mimeType\">\n" + "<option value=\"application/sparql-results+json\">json</option>\n" + "<option value=\"application/xml\">xml</option>\n" + "</select><br />\n" + "<input type=\"submit\">\n" + "</form>\n</body></html>"; } }