Java tutorial
/** * Copyright (C) 2009-2010, LinkedGeoData team at the MOLE research * group at AKSW / University of Leipzig * * This file is part of LinkedGeoData. * * LinkedGeoData 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 3 of the License, or * (at your option) any later version. * * LinkedGeoData 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 this program. If not, see <http://www.gnu.org/licenses/>. * */ package org.aksw.resparql; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.lang.reflect.Method; import java.net.InetSocketAddress; import java.net.URI; import java.sql.Connection; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.activation.UnsupportedDataTypeException; import javax.mail.internet.ContentType; import javax.mail.internet.ParseException; import org.aksw.commons.sparql.core.SparqlEndpoint; import org.aksw.commons.sparql.core.impl.HttpSparqlEndpoint; import org.aksw.commons.util.strings.StringUtils; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.GnuParser; import org.apache.commons.cli.Options; import org.apache.commons.collections15.MultiMap; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.hibernate.Session; import org.linkedgeodata.core.ILGDVocab; import org.linkedgeodata.core.LGDVocab; import org.linkedgeodata.dao.HibernateSessionProvider; import org.linkedgeodata.dao.IConnectionFactory; import org.linkedgeodata.dao.ISessionProvider; import org.linkedgeodata.dao.JDBCConnectionProvider; import org.linkedgeodata.dao.LGDDAO; import org.linkedgeodata.dao.LGDRDFDAO; import org.linkedgeodata.dao.TagMapperDAO; import org.linkedgeodata.dao.gragh.RdfGraphDaoGraph; import org.linkedgeodata.jtriplify.methods.DefaultCoercions; import org.linkedgeodata.jtriplify.methods.IInvocable; import org.linkedgeodata.jtriplify.methods.Pair; import org.linkedgeodata.osm.mapping.CachingTagMapper; import org.linkedgeodata.osm.mapping.ITagMapper; import org.linkedgeodata.osm.mapping.TagMappingDB; import org.linkedgeodata.util.ConnectionConfig; import org.linkedgeodata.util.ExceptionUtil; import org.linkedgeodata.util.HTMLJenaWriter; import org.linkedgeodata.util.ModelUtil; import org.linkedgeodata.util.StreamUtil; import org.linkedgeodata.util.StringUtil; import org.linkedgeodata.util.URIUtil; import com.hp.hpl.jena.graph.Graph; import com.hp.hpl.jena.graph.compose.Union; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.RDFWriter; import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.rdf.model.ResourceFactory; import com.sun.net.httpserver.Headers; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; interface IMyHandler { /** * * @param x * @return true if accepted, false otherwise */ boolean handle(HttpExchange x) throws Exception; } class MyHttpHandler implements HttpHandler { private static final Logger logger = Logger.getLogger(MyHttpHandler.class); private List<IMyHandler> subHandlers = new ArrayList<IMyHandler>(); public List<IMyHandler> getSubHandlers() { return subHandlers; } @Override public void handle(HttpExchange x) { try { _handle(x); } catch (Throwable t) { logger.error(ExceptionUtil.toString(t)); } } public void _handle(HttpExchange x) throws Exception { for (IMyHandler item : subHandlers) { if (item.handle(x)) { return; } } String msg = "Internal server error. Maybe a misspelled or non-existent resource was requested?"; MyHandler.sendResponse(x, 500, "text/plain", msg); } } class DataHandler implements IMyHandler { private static final Logger logger = Logger.getLogger(DataHandler.class); private RegexInvocationContainer ric = new RegexInvocationContainer(); /* public Model2Handler(RegexInvocationContainer ric) { this.ric = ric; } */ public RegexInvocationContainer getRIC() { return ric; } @Override public boolean handle(HttpExchange x) { try { return _handle(x); } catch (Exception e) { throw new RuntimeException(e); } } public static String generateHTMLRepresentation(String body) { String cssPath = MyBeanFactory.getSingleton().get("triplifyCSSFile", String.class); /* ByteArrayOutputStream baos = new ByteArrayOutputStream(); HTMLJenaWriter writer = new HTMLJenaWriter(); writer.write(model, baos, ""); */ String content = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" " + "\"http://www.w3.org/TR/html4/loose.dtd\">\n" + "<html>\n" + "<head>\n" + "<title></title>\n" + "<link rel='stylesheet' type='text/css' href='" + cssPath + "' />\n" + "</head>\n" + "<body>\n" + body + "</body>\n" + "</html>\n"; return content; } private boolean isDataUri(String uri) { return uri.contains("/data"); } private boolean _handle(HttpExchange x) throws Exception { System.out.println("Request method = " + x.getRequestMethod()); System.out.println("Request body = " + StreamUtil.toString(x.getRequestBody())); // Check whether we have a data or page URI Map.Entry<String, ContentType> resultType; Map<String, ContentType> accepts = MyHandler.getPreferredFormats(x.getRequestHeaders()); String requestURI = x.getRequestURI().toString(); if (isDataUri(requestURI)) { accepts.remove("HTML"); } String extension = MyHandler.getExtension(x.getRequestURI().toString()); String requestedFormat = null; if (extension != null) { requestedFormat = MyHandler.getFormatFromExtension(extension); // Assume no extension if the extension is unknown if (requestedFormat == null) { extension = null; } /* if(requestedFormat == null) { MyHandler.sendResponse(x, 500, "text/plain", "Unknown extension: '" + extension + "'"); return true; } */ } //String requestedFormat = MyHandler.getJenaFormatByExtension(x.getRequestURI()); String qsFormat = MyHandler.getJenaFormatByQueryString(x.getRequestURI()); requestedFormat = StringUtil.coalesce(requestedFormat, qsFormat); resultType = MyHandler.getContentType(requestedFormat, accepts); if (requestURI.contains("triplify")) { String targetURL = (resultType.getValue().match("text/html")) ? requestURI.replace("triplify", "page") : requestURI.replace("triplify", "data"); MyHandler.sendRedirect(x, targetURL); return true; } // Check whether we need to do a redirect on the URI // (this is the case when the URI contains a 'triplify'/'resource' // Cut off extensions of the request uri if (requestURI.endsWith("/")) { requestURI = requestURI.substring(0, requestURI.length() - 1); } if (extension != null) { requestURI = requestURI.substring(0, requestURI.length() - extension.length() - 1); } if (isDataUri(requestURI) && extension == null) { resultType = Pair.create("RDF/XML", MyHandler.jenaFormatToContentType.get("RDF/XML")); } Model model = null; try { model = (Model) ric.invoke(requestURI); } catch (Throwable t) { logger.error(ExceptionUtil.toString(t)); } if (model == null) return false; RDFWriter writer = MyHandler.getWriter(resultType.getKey()); String body = ModelUtil.toString(model, writer); if ("HTML".equalsIgnoreCase(resultType.getKey())) { // FIXME For now prepensd an info to the html doc String url = requestURI; String note = "" + "<p>" + "You are viewing the html representation of this document." + "<br />Other formats: " + "<a href='" + url + ".rdf'>rdf/xml</a> " + "<a href='" + url + ".nt'>n-triples</a> " + "<a href='" + url + ".ttl'>turtle</a> " + "<a href='" + url + ".n3'>n3</a> " + "</p>"; body = note + body; body = generateHTMLRepresentation(body); } if (resultType != null) { MyHandler.sendResponse(x, 200, resultType.getValue().toString(), body); return true; } return false; } /* * * This is tho old version which had a page and data namespace * (analogous to dbpedia) * private boolean _handle(HttpExchange x) throws Exception { System.out.println("Request method = " + x.getRequestMethod()); System.out.println("Request body = " + StreamUtil.toString(x.getRequestBody())); // Check whether we have a data or page URI Map.Entry<String, ContentType> resultType; if(x.getRequestURI().toString().contains("page")) { resultType = new Pair<String, ContentType>("HTML", new ContentType("text/html; charset=utf-8")); } else { Map<String, ContentType> accepts = MyHandler.getPreferredFormats(x.getRequestHeaders()); // Remove text/html accept - as we are requesting data if(x.getRequestURI().toString().contains("data")) { Iterator<Map.Entry<String, ContentType>> it = accepts.entrySet().iterator(); while(it.hasNext()) { if(it.next().getValue().match(new ContentType("text/html"))) it.remove(); } } String requestedFormat = MyHandler.getJenaFormatByExtension(x.getRequestURI()); String qsFormat = MyHandler.getJenaFormatByQueryString(x.getRequestURI()); requestedFormat = StringUtil.coalesce(requestedFormat, qsFormat); resultType = MyHandler.getContentType(requestedFormat, accepts); } // Check whether we need to do a redirect on the URI // (this is the case when the URI contains a 'triplify'/'resource' String requestURI = x.getRequestURI().toString(); if(requestURI.contains("triplify")) { String targetURL = (resultType.getValue().match("text/html")) ? requestURI.replace("triplify", "page") : requestURI.replace("triplify", "data"); MyHandler.sendRedirect(x, targetURL); return true; } //String //x.getRequestURI() // Check if the content negotiation is ok Model model = null; try { model = (Model)ric.invoke(x.getRequestURI().toString()); } catch(Throwable t) { logger.error(ExceptionUtil.toString(t)); } if(model == null) return false; RDFWriter writer = MyHandler.getWriter(resultType.getKey()); String body = ModelUtil.toString(model, writer); if("HTML".equalsIgnoreCase(resultType.getKey())) { body = generateHTMLRepresentation(body); } if(resultType != null) { MyHandler.sendResponse(x, 200, resultType.getValue().toString(), body); return true; } return false; //return true; } */ } /* class PageHandler implements IMyHandler { private static final Logger logger = Logger.getLogger(DataHandler.class); private RegexInvocationContainer ric = new RegexInvocationContainer(); /* public Model3Handler(RegexInvocationContainer ric) { this.ric = ric; }* / public RegexInvocationContainer getRIC() { return ric; } @Override public boolean handle(HttpExchange x) { try { return _handle(x); } catch(Exception e) { throw new RuntimeException(e); } } private boolean _handle(HttpExchange x) throws Exception { // Check if the content negotiation is ok Map<String, ContentType> accepts = MyHandler.getPreferredFormats(x.getRequestHeaders()); String requestedFormat = MyHandler.getJenaFormatByQueryString(x.getRequestURI()); Map.Entry<String, ContentType> resultType = MyHandler.getContentType(requestedFormat, accepts); Model model = null; try { model = (Model)ric.invoke(x.getRequestURI().toString()); } catch(Throwable t) { logger.error(ExceptionUtil.toString(t)); } if(model == null) { return false; } String body = ModelUtil.toString(model, resultType.getKey()); if(resultType.getValue().match("text/html")) //body = StringEscapeUtils.escapeHtml(body); body = DataHandler.generateHTMLRepresentation(model); if(resultType != null) { MyHandler.sendResponse(x, 200, resultType.getValue().toString(), body); return true; } return false; } } */ class ICPair { private IInvocable invocable; private Object[] argMap; public ICPair(IInvocable invocable, Object[] argMap) { this.invocable = invocable; this.argMap = argMap; } public IInvocable getInvocable() { return invocable; } public Object[] getArgMap() { return argMap; } } class RedirectInvocable implements IInvocable { private String pattern; public RedirectInvocable(String pattern) { this.pattern = pattern; } @Override public String invoke(Object... args) throws Exception { String url = pattern; for (int i = 0; i < args.length; ++i) { url = url.replace("$" + i, args[i] == null ? "" : args[i].toString()); } return url; } } class LinkedDataRedirectHandler implements IMyHandler { private RegexInvocationContainer pageRIC = new RegexInvocationContainer(); private RegexInvocationContainer dataRIC = new RegexInvocationContainer(); public RegexInvocationContainer getPageRIC() { return pageRIC; } public RegexInvocationContainer getDataRIC() { return dataRIC; } /* public LinkedDataRedirectHandler(RegexInvocationContainer pageRic, RegexInvocationContainer dataRic) { this.pageRic = pageRic; this.dataRic = dataRic; } */ @Override public boolean handle(HttpExchange x) throws Exception { Map<String, ContentType> accepts = MyHandler.getPreferredFormats(x.getRequestHeaders()); if (accepts.isEmpty()) return false; //Map.Entry<String, ContentType> type = accepts.entrySet().iterator().next(); RegexInvocationContainer ric = accepts.containsValue(new ContentType("text/html")) ? pageRIC : dataRIC; String targetURL = (String) ric.invoke(x.getRequestURI().toString()); if (targetURL == null) { return false; } MyHandler.sendRedirect(x, targetURL); return true; } } /* class RDFResultFormat { private String contentType; private String jenaFormat; public RDFResultFormat() { } } */ class SimpleResponse { private int statusCode; private Map<String, List<String>> header = new HashMap<String, List<String>>(); private String contentType; private String body; public SimpleResponse() { } public SimpleResponse(int statusCode) { this.statusCode = statusCode; } public static SimpleResponse redirect(String url) { SimpleResponse result = new SimpleResponse(303); result.getHeader().put("Location", Collections.singletonList(url)); return result; } public SimpleResponse(int statusCode, String contentType, String body) { this.statusCode = statusCode; this.header.put("Content-Type", Collections.singletonList(contentType)); this.body = body; } public int getStatusCode() { return statusCode; } public String getContentType() { return contentType; } public String getBody() { return body; } public Map<String, List<String>> getHeader() { return header; } } class HTTPErrorException extends Exception { /** * */ private static final long serialVersionUID = 1L; private int errorCode; public HTTPErrorException(int errorCode) { this.errorCode = errorCode; } public int getErrorCode() { return errorCode; } } class MyHandler // implements HttpHandler { private static final Logger logger = Logger.getLogger(JTriplifyServer.class); private RegexInvocationContainer ric = null; //private static Map<String, RDFWriter> rdfFormatToWriter = new HashMap<String, RDFWriter>(); private static Map<ContentType, String> contentTypeToJenaFormat = new HashMap<ContentType, String>(); public static Map<String, ContentType> jenaFormatToContentType = new HashMap<String, ContentType>(); private static Map<String, String> formatToJenaFormat = new HashMap<String, String>(); private static Map<String, String> extensionToJenaFormat = new HashMap<String, String>(); public static RDFWriter getWriter(String format) { // FIXME The Jena writer needs to be configurable (e.g. css path) // Probably use ApplicationContext for that if ("HTML".equalsIgnoreCase(format)) return new HTMLJenaWriter(); RDFWriter writer = ModelFactory.createDefaultModel().getWriter(format); /* if(writer instanceof BaseXMLWriter) { writer.setProperty("showXMLDeclaration","true"); } */ //return ModelFactory.createDefaultModel().getWriter(format); return writer; } { //contentTypeToJenaFormat.put("text/plain", "N3"); //contentTypeToJenaFormat.put("text/html", "N3"); try { Model model = ModelFactory.createDefaultModel(); /* rdfFormatToWriter.put("N-TRIPLE", model.getWriter("N-TRIPLE")); rdfFormatToWriter.put("RDF/XML", model.getWriter("RDF/XML")); rdfFormatToWriter.put("TURTLE", model.getWriter("TURTLE")); rdfFormatToWriter.put("N3", model.getWriter("N3")); */ //rdfFormatToWriter.put("HTML", new HTMLJenaWriter()); //Values take from http://www.w3.org/2008/01/rdf-media-types contentTypeToJenaFormat.put(new ContentType("text/html"), "HTML"); contentTypeToJenaFormat.put(new ContentType("application/rdf+xml"), "RDF/XML"); //text/plain -> N-TRIPLE contentTypeToJenaFormat.put(new ContentType("application/x-turtle"), "TURTLE"); contentTypeToJenaFormat.put(new ContentType("text/turtle"), "TURTLE"); contentTypeToJenaFormat.put(new ContentType("text/n3;"), "N3"); contentTypeToJenaFormat.put(new ContentType("text/rdf+n3"), "N3"); //jenaFormatToContentType.put("RDF/XML", new ContentType("application/rdf+xml; charset=utf-8")); //jenaFormatToContentType.put("RDF/XML", new ContentType("application/rdf+xml")); jenaFormatToContentType.put("RDF/XML", new ContentType("application/rdf+xml")); jenaFormatToContentType.put("TURTLE", new ContentType("application/x-turtle; charset=utf-8")); jenaFormatToContentType.put("N3", new ContentType("text/rdf+n3; charset=utf-8")); } catch (Exception e) { logger.fatal(ExceptionUtil.toString(e)); System.exit(1); } formatToJenaFormat.put("rdfxml", "RDF/XML"); formatToJenaFormat.put("n3", "N3"); formatToJenaFormat.put("nt", "N-TRIPLE"); formatToJenaFormat.put("turtle", "TURTLE"); extensionToJenaFormat.put("rdfxml", "RDF/XML"); extensionToJenaFormat.put("rdf", "RDF/XML"); extensionToJenaFormat.put("n3", "N3"); extensionToJenaFormat.put("nt", "N-TRIPLE"); extensionToJenaFormat.put("ttl", "TURTLE"); extensionToJenaFormat.put("htm", "HTML"); extensionToJenaFormat.put("html", "HTML"); } public void setInvocationMap(RegexInvocationContainer ric) { this.ric = ric; } public static <T> T getFirst(Iterable<T> iterable) { if (iterable == null) return null; Iterator<T> it = iterable.iterator(); if (!it.hasNext()) return null; T result = it.next(); return result; } /** * The question is whether a specifically requested format is conforming to the * formats of the content type - therefore: This method returns a list * of RDF formats in * @throws ParseException * * **/ /** * .rdf, .n3, .ttl, .nt, .html * */ public static String getExtension(String str) { int index = str.lastIndexOf('.'); if (index == -1) return null; return str.substring(index + 1); } public static String getFormatFromExtension(String ext) { if (ext == null) return null; //System.out.println(extensionToJenaFormat); //System.out.println(formatToJenaFormat); String result = extensionToJenaFormat.get(ext); return result; } public static Map<String, ContentType> getPreferredFormats(Headers requestHeaders) throws ParseException { // Content negotiation List<String> accepts = requestHeaders.get("Accept"); if (accepts == null) accepts = Collections.emptyList(); logger.info("Accept header: " + accepts); Map<String, ContentType> result = new HashMap<String, ContentType>(); int acceptCounter = 0; for (String accept : accepts) { String[] items = accept.split(","); for (String item : items) { ++acceptCounter; ContentType ct = null; try { ct = new ContentType(item); } catch (Exception e) { logger.warn("Error parsing content type", e); continue; } // FIXME Would be nice if this was configurable if (ct.match("text/plain") || ct.match("text/html") || ct.match("*/*")) { if (!result.containsKey("N-TRIPLE")) { //result.put("N-TRIPLE", ct); // We serve N-Triples by default result.put("N-TRIPLE", new ContentType("text/plain")); } //responseContentType = "text/plain; charset=UTF-8"; } for (Map.Entry<ContentType, String> entry : contentTypeToJenaFormat.entrySet()) { if (!ct.match(entry.getKey())) continue; String tmp = entry.getValue(); if (tmp != null) { // If a format was specified in the query string, we also need // a compatible content type // E.g. if format=N3, but accept=rdf+xml we can't use that accept type if (!result.containsKey(tmp)) { result.put(tmp, ct); } } } } } return result; } /* return null; if(acceptCounter == 0) if(acceptCounter == 0) { logger.info("No accept header. Defaulting to 'text/plain'"); contentFormat = StringUtil.coalesce(requestFormat, "N-TRIPLE"); responseContentType = "text/plain"; }*/ /** * Returns a pair of serializiation format and content-type * */ public static Map.Entry<String, ContentType> getContentType(String requestedFormat, Map<String, ContentType> accepts) throws ParseException { if (requestedFormat == null) { if (accepts.isEmpty()) { return new Pair<String, ContentType>("N-TRIPLE", new ContentType("text/plain; charset=utf-8")); } else { return accepts.entrySet().iterator().next(); } } else if (!accepts.containsKey(requestedFormat)) { //return null; //return new SimpleResponse(406, "text/plain", "Requested " + requestedFormat + " but accept-header " + formats + " is not compatible."); //} ContentType contentType = StringUtils.coalesce(jenaFormatToContentType.get(requestedFormat), new ContentType("text/plain; charset=utf-8")); return new Pair<String, ContentType>(requestedFormat, contentType); } else { return new Pair<String, ContentType>(requestedFormat, accepts.get(requestedFormat)); //return new Pair<String, ContentType>(requestedFormat, new ContentType("text/plain; charset=utf-8")); } } public static SimpleResponse respondModel(Model model, Map.Entry<String, ContentType> contentType) { String response = ModelUtil.toString(model, contentType.getKey()); SimpleResponse result = new SimpleResponse(200, contentType.getValue().toString(), response); return result; } private SimpleResponse process(HttpExchange t) throws Exception { String request = t.getRequestURI().toString(); Object o = ric.invoke(request); if (o instanceof SimpleResponse) return (SimpleResponse) o; throw new UnsupportedDataTypeException(); } public static String getJenaFormatByExtension(URI uri) { // FIXME not correct String host = uri.toString(); String ext = getExtension(host); String result = getFormatFromExtension(ext); return result; } public static String getJenaFormatByQueryString(URI uri) { // Check if a particular format was requested via the query string // As this excludes some of the content types that may be used String query = uri.getQuery(); MultiMap<String, String> params = URIUtil.getQueryMap(query); String rawFormat = getFirst(params.get("format")); rawFormat = rawFormat == null ? null : rawFormat.trim().toLowerCase(); String requestFormat = formatToJenaFormat.get(rawFormat); if (rawFormat != null && requestFormat == null) { // FIXME Respect the accept header when returning an error //return new SimpleResponse(400, "text/plain", "Unsupported format"); return null; } return requestFormat; } public static void sendRedirect(HttpExchange x, String targetURL) throws IOException { x.getResponseHeaders().set("Location", targetURL); x.sendResponseHeaders(303, -1); } public static void sendResponse(HttpExchange x, int statusCode, String contentType, String body) throws IOException { try { //System.out.println(x.getRequestMethod()); //System.out.println(x.getRequestHeaders()); //System.out.println(StreamUtil.toString(x.getRequestBody())); Model model = ModelFactory.createDefaultModel(); Resource r = ResourceFactory.createResource("http://ex.org/resource/a"); Property p = ResourceFactory.createProperty("http://ex.org/ontology/b"); model.add(r, p, r); //x.getResponseHeaders().set("Content-Type", "application/rdf+xml"); x.getResponseHeaders().set("Content-Type", contentType); x.sendResponseHeaders(200, 0); OutputStream out = x.getResponseBody(); String str = ModelUtil.toString(model, "RDF/XML"); out.write(body.getBytes()); out.close(); } catch (Throwable t) { t.printStackTrace(); } } public static void sendResponseX(HttpExchange x, int statusCode, String contentType, String body) throws IOException { if (contentType == null) contentType = "text/plain"; //byte[] bodyBytes = body == null ? null : body.getBytes("UTF8"); int responseLength = 0; if (body == null) { responseLength = -1; } /* else { responseLength = body.length(); } */ Headers headers = x.getResponseHeaders(); //headers. //x.getResponseHeaders().add("Content-Type", contentType); //x.setAttribute(arg0, arg1) headers.set("Content-Type", contentType); //x.getResponseHeaders().set("Accept-Ranges", "bytes"); x.sendResponseHeaders(statusCode, responseLength); OutputStream os = x.getResponseBody(); OutputStreamWriter osw; try { osw = new OutputStreamWriter(os, "UTF-8"); } catch (Exception e) { throw new RuntimeException(e); } if (responseLength != -1) { //os.write(bodyBytes); osw.write(body); } osw.close(); os.close(); } /* public void handle(HttpExchange x) throws IOException { SimpleResponse response = null; try { response = process(x); } catch(Throwable t) { logger.error(ExceptionUtil.toString(t)); response = new SimpleResponse(500, null, null); } if(response == null) { response = new SimpleResponse(500, null, null); logger.error("No response object was created."); } Headers responseHeaders = x.getResponseHeaders(); responseHeaders.putAll(response.getHeader()); OutputStream os = x.getResponseBody(); int responseLength = 0; if(response.getBody() == null) responseLength = -1; x.sendResponseHeaders(response.getStatusCode(), -1); if(responseLength != -1) os.write(response.getBody().getBytes()); os.close(); } */ } public class JTriplifyServer { private static final Logger logger = Logger.getLogger(JTriplifyServer.class); protected static final Options cliOptions = new Options(); private static void initCLIOptions() { cliOptions.addOption("p", "port", true, "Server port"); cliOptions.addOption("c", "context", true, "Context e.g. /triplify/"); cliOptions.addOption("b", "backlog", true, "Maximum number of connections"); cliOptions.addOption("t", "type", true, "Database type (posgres, mysql,...)"); cliOptions.addOption("d", "database", true, "Database name"); cliOptions.addOption("u", "user", true, ""); cliOptions.addOption("w", "password", true, ""); cliOptions.addOption("h", "host", true, ""); cliOptions.addOption("n", "batchSize", true, "Batch size"); } public static String test(String a, String b) { System.out.println("In test"); return "Hello " + a + " and " + b + "!"; } /* public static void main(String[] args) throws Exception { String regex = ".*test/([^/]*)/(.*)"; Pattern pattern = Pattern.compile(regex); Matcher m = pattern.matcher("hi/test/a/b"); m.matches(); System.out.println(m.group()); for(int i = 0; i < m.groupCount(); ++i) { System.out.println(m.group(1 + i)); } } */ /*************************************************************************/ /* Init */ /*************************************************************************/ public static void main(String[] args) throws Exception { PropertyConfigurator.configure("log4j.properties"); initCLIOptions(); CommandLineParser cliParser = new GnuParser(); CommandLine commandLine = cliParser.parse(cliOptions, args); // Parsing of command line args String portStr = commandLine.getOptionValue("p", "7000"); String backLogStr = commandLine.getOptionValue("b", "100"); String context = commandLine.getOptionValue("c", "/triplify"); int port = Integer.parseInt(portStr); int backLog = Integer.parseInt(backLogStr); String hostName = commandLine.getOptionValue("h", "localhost"); String dbName = commandLine.getOptionValue("d", "lgd"); String userName = commandLine.getOptionValue("u", "lgd"); String passWord = commandLine.getOptionValue("w", "lgd"); String batchSizeStr = commandLine.getOptionValue("n", "1000"); int batchSize = Integer.parseInt(batchSizeStr); // Validation if (batchSize <= 0) throw new RuntimeException("Invalid argument for batchsize"); /* String fileName = "NamespaceResolv.ini"; File file = new File(fileName); if(!file.exists()) { throw new FileNotFoundException(fileName); } Transformer<String, URI> uriResolver = new URIResolver(file); */ new MyHandler(); logger.info("Connecting to db"); ConnectionConfig connectionConfig = new ConnectionConfig(hostName, dbName, userName, passWord); MyHttpHandler myHandler = new MyHttpHandler(); RegexInvocationContainer ric = new RegexInvocationContainer(); //initLegacy(myHandler, conn); initCurrent(myHandler, connectionConfig); //MyHandler handler = new MyHandler(); //handler.setInvocationMap(ric); // Start runServer(context, port, backLog, myHandler); } private static void initCurrent(MyHttpHandler mainHandler, ConnectionConfig connectionConfig) throws Exception { // Init jena //RDFWriter writer = MyHandler.getWriter("RDF/XML"); //writer.setProperty("showXMLDeclaration","true"); // FIXME Somehow get rid of the need for the following line TagMappingDB.getSession(); ISessionProvider sessionFactory = new HibernateSessionProvider(); IConnectionFactory connectionFactory = new JDBCConnectionProvider(connectionConfig); Connection conn = connectionFactory.getConnection(); String prefixModelPath = "Namespaces.2.0.ttl"; // Setup logger.info("Loading uri namespaces"); Model prefixModel = ModelFactory.createDefaultModel(); ModelUtil.read(prefixModel, new File(prefixModelPath), "TTL"); Map<String, String> prefixMap = prefixModel.getNsPrefixMap(); logger.info("Loading mapping rules"); //InMemoryTagMapper tagMapper = new InMemoryTagMapper(); //tagMapper.load(new File("data/triplify/config/2.0/LGDMappingRules.2.0.xml")); TagMapperDAO dbTagMapper = new TagMapperDAO(); ITagMapper tagMapper = new CachingTagMapper(dbTagMapper); LGDDAO innerDAO = new LGDDAO(conn); ILGDVocab vocab = new LGDVocab(); Set<String> defaultGraphNames = new HashSet<String>(); defaultGraphNames.add("http://linkedgeodata.org/110406/dbpedia"); defaultGraphNames.add("http://linkedgeodata.org/110406/geonames"); SparqlEndpoint sparqlEndpoint = new HttpSparqlEndpoint("http://linkedgeodata.org/sparql", defaultGraphNames); LGDRDFDAO dao = new LGDRDFDAO(innerDAO, tagMapper, vocab, sparqlEndpoint); dao.setConnection(conn); Session session = sessionFactory.createSession(); dao.setSession(session); dbTagMapper.setSession(session); /* Create a unified Jena-Model-View for the meta ontology (the lgd vocab) * and the osm vocab. */ Graph metaOntologyGraph = MyBeanFactory.getSingleton().getMetaOntologyModel().getGraph(); RdfGraphDaoGraph dataOntologyGraph = new RdfGraphDaoGraph(dao); Graph ontologyGraph = new Union(metaOntologyGraph, dataOntologyGraph); Model ontologyModel = ModelFactory.createModelForGraph(ontologyGraph); //ontolgyModel.read( //new FileInputStream( IRestApi methods = new ServerMethods(dao, prefixMap, connectionFactory, sessionFactory, ontologyModel); Method m; // Set up redirects /* LinkedDataRedirectHandler redirectHandler = new LinkedDataRedirectHandler(); mainHandler.getSubHandlers().add(redirectHandler); m = ServerMethods.class.getMethod("getNode", String.class); redirectHandler.getDataRIC().put("(.*)/triplify/(.*)", new RedirectInvocable("$0/data/$1"), "$0", "$1"); redirectHandler.getPageRIC().put("(.*)/triplify/(.*)", new RedirectInvocable("$0/page/$1"), "$0", "$1"); //redirectHandler.getDataRIC().put("(.*)/resource/(.*)", new RedirectInvocable("$0/data/$1"), "$0", "$1"); //redirectHandler.getPageRIC().put("(.*)/resource/(.*)", new RedirectInvocable("$0/page/$1"), "$0", "$1"); */ // Set up actual data URIs DataHandler dataHandler = new DataHandler(); mainHandler.getSubHandlers().add(dataHandler); m = ServerMethods.class.getMethod("getWayNode", Long.class); //dataHandler.getRIC().put(".*/way([^.]*)/nodes.*", new JavaMethodInvocable(m, methods), "$1"); dataHandler.getRIC().put(".*/way([^.]*)/nodes.*", DefaultCoercions.wrap(methods, "getWayNode"), "$1"); m = ServerMethods.class.getMethod("getNode", Long.class); //dataHandler.getRIC().put(".*/node([0-9]+).*", new JavaMethodInvocable(m, methods), "$1"); dataHandler.getRIC().put(".*/node([0-9]+).*", DefaultCoercions.wrap(methods, "getNode"), "$1"); m = ServerMethods.class.getMethod("getWay", Long.class); //dataHandler.getRIC().put(".*/way([^./]*)(\\.[^/]*)?/?(\\?.*)?", new JavaMethodInvocable(m, methods), "$1"); dataHandler.getRIC().put(".*/way([^./]*)(\\.[^/]*)?/?(\\?.*)?", DefaultCoercions.wrap(methods, "getWay"), "$1"); // Set up page URIs /* PageHandler pageHandler = new PageHandler(); mainHandler.getSubHandlers().add(pageHandler); m = ServerMethods.class.getMethod("getNode", String.class); dataHandler.getRIC().put(".*page/node([^/?]*)/?(\\?.*)?", new JavaMethodInvocable(m, methods), "$0"); m = ServerMethods.class.getMethod("getWay", String.class); dataHandler.getRIC().put(".*page/way([^/?]*)/?(\\?.*)?", new JavaMethodInvocable(m, methods), "$0"); */ //m = ServerMethods.class.getMethod("getNear", String.class, String.class, String.class); String pattern = ""; IInvocable nearFn = DefaultCoercions.wrap(methods, "publicGetEntitiesWithinRadius.*"); pattern = ".*/near/(-?[^,-]*),(-?[^-/]*)/([^/?]*)(/class/([^/]*))?(/label/([^/]*)/([^/]*)/([^/]*))?(/(\\d+))?(/(\\d+))?/?(\\?.*)?"; dataHandler.getRIC().put(pattern, nearFn, "$1", "$2", "$3", "$5", "$7", "$8", "$9", "$11", "$13"); IInvocable areaFn = DefaultCoercions.wrap(methods, "publicGetAreaStatistics.*"); pattern = ".*/area/(-?[^-]+)-(-?[^,]+),(-?[^-]+)-(-?[^/]+)?/?(\\?.*)?"; dataHandler.getRIC().put(pattern, areaFn, "$1", "$2", "$3", "$4"); //dataHandler.getRIC().put(pattern, bboxFn, "$1", "$2", "$3", "$4", "$6", "$8", "$9", "$10", "$11", "$12"); //dataHandler.getRIC().put(".*/near/([^,]*),([^/]*)/([^/]*)/([^/=?]*)/?(\\?.*)?", nearFn, "$0", "$1", "$2", "$3", null, false); //dataHandler.getRIC().put(".*/near/([^,]*),([^/]*)/([^/]*)/([^=]*)=([^/?]*)/?(\\?.*)?", nearFn, "$0", "$1", "$2", "$3", "$4", false); //dataHandler.getRIC().put(".*/near/([^,]*),([^/]*)/([^/]*)/class/([^/?]*)/?(\\?.*)?", nearFn, "$0", "$1", "$2", "$3", "$3", true); //dataHandler.getRIC().put(".*/near/([^,]*),([^/]*)/([^/?]*)/?(\\?.*)?", nearFn, "$0", "$1", "$2", null, null, false); //dataHandler.getRIC().put(".*/near/([^,]*),([^/]*)/([^/]*)/([^/=?]*)/?(\\?.*)?", nearFn, "$0", "$1", "$2", "$3", null, false); //dataHandler.getRIC().put(".*/near/([^,]*),([^/]*)/([^/]*)/([^=]*)=([^/?]*)/?(\\?.*)?", nearFn, "$0", "$1", "$2", "$3", "$4", false); //dataHandler.getRIC().put(".*/near/([^,]*),([^/]*)/([^/]*)/class/([^/?]*)/?(\\?.*)?", nearFn, "$0", "$1", "$2", "$3", "$3", true); IInvocable bboxFn = DefaultCoercions.wrap(methods, "publicGetEntitiesWithinRect.*"); // lat-lat lon-lon class lable lang matchmode pattern = ".*/near/(-?[^-]+)-(-?[^,]+),(-?[^-]+)-(-?[^/]+)(/class/([^/]*))?(/label/([^/]*)/([^/]*)/([^/]*))?(/(\\d+))?(/(\\d+))?/?(\\?.*)?"; // latMin latMax lonMin lonMax classname lang matchMode value offset? limit? dataHandler.getRIC().put(pattern, bboxFn, "$1", "$2", "$3", "$4", "$6", "$8", "$9", "$10", "$12", "$14"); //latMin, latMax, lonMin, lonMax, className, language, matchMode, label, offset, limit) //dataHandler.getRIC().put(".*/near/(-?[^-]+)-(-?[^,]+),(-?[^-]+)-(-?[^/]+)/?(\\?.*)?", bboxFn, "$0", "$1", "$2", "$3", null, null, null, null); //dataHandler.getRIC().put(".*/near/(-?[^-]+)-(-?[^,]+),(-?[^-]+)-(-?[^/]+)/class/([^/]*)/?(\\?.*)?", bboxFn, "$0", "$1", "$2", "$3", "$4", null, null, null); //dataHandler.getRIC().put(".*/near/(-?[^-]+)-(-?[^,]+),(-?[^-]+)-(-?[^/]+)/class/([^/]*)/label/([^/]*)/([^/]*)/(.*)/?(\\?.*)?", bboxFn, "$0", "$1", "$2", "$3", "$4", "$7", "$5", "$6"); //dataHandler.getRIC().put(".*/near/(-?[^-]+)-(-?[^,]+),(-?[^-]+)-(-?[^/]+)/class/([^/]*)/label/(.*)/?(\\?.*)?", bboxFn, "$0", "$1", "$2", "$3", "$4", "$5", null, null); //dataHandler.getRIC().put(".*/near/(-?[^-]+)-(-?[^,]+),(-?[^-]+)-(-?[^/]+)/class/([^/]*)/label/([^/]*)/(.*)/?(\\?.*)?", bboxFn, "$0", "$1", "$2", "$3", "$5", "$4", null); //dataHandler.getRIC().put(".*/near/(-?[^-]+)-(-?[^,]+),(-?[^-]+)-(-?[^/]+)/class/([^/]*)/label/([^/]*)/([^/]*)/(.*)/?(\\?.*)?", bboxFn, "$0", "$1", "$2", "$3", "$6", "$4", "$5"); //dataHandler.getRIC().put(".*/near/(-?[^-]+)-(-?[^,]+),(-?[^-]+)-(-?[^/]+)/label/([^/]*)/(*.)/?(\\?.*)?", bboxFn, "$0", "$1", "$2", "$3", "$5", "$6"); IInvocable getOntologyFn = DefaultCoercions.wrap(methods, "publicGetOntology.*"); dataHandler.getRIC().put(".*/ontology(\\.[^/]*)?/?(\\?.*)?", getOntologyFn); IInvocable describeFn = DefaultCoercions.wrap(methods, "publicDescribe.*"); dataHandler.getRIC().put(".*/(ontology/[^/\\.]+)(\\.[^/\\?]*)?(\\?.*)?", describeFn, "$1"); } private static void runServer(String context, int port, int backLog, HttpHandler handler) throws IOException { logger.info("Starting JTriplify Server"); InetSocketAddress socketAddress = new InetSocketAddress(port); HttpServer server = HttpServer.create(socketAddress, backLog); server.createContext(context, handler); server.setExecutor(null); server.start(); } }