From 677e602d3c7c61e645e8f44fa7263c28b9f8c4e2 Mon Sep 17 00:00:00 2001 From: cstadler Date: Sat, 29 Mar 2014 00:22:52 +0100 Subject: [PATCH] Towards getting the old REST API working again --- linkedgeodata-core/pom.xml | 59 ++- .../java/org/linkedgeodata/dump/LgdDumper.java | 22 +- .../linkedgeodata/rest/MessageBodyWriterHtml.java | 18 - .../rest/MessageBodyWriterNTriples.java | 60 --- .../main/java/org/linkedgeodata/rest/RestApi.java | 465 --------------------- .../AbstractModelMessageReaderWriterProvider.java | 4 +- .../linkedgeodata/{rest => web/api}/LGDVocab.java | 2 +- .../{rest => web/api}/LGDVocabDefault.java | 2 +- .../web/api/LinkedGeoDataRestApiServlet.java | 422 +++++++++++++++++++ .../web/api/MessageBodyWriterHtml.java | 17 + .../web/api/MessageBodyWriterNTriples.java | 16 + .../web/api/MessageBodyWriterNTriplesOld.java | 58 +++ .../{rest => web/api}/MessageBodyWriterRdfXml.java | 7 +- .../{rest => web/api}/MessageBodyWriterTurtle.java | 3 +- .../web/api/RDFNodePrettyComparator.java | 71 ++++ .../org/linkedgeodata/web/api/RDFWriterHtml.java | 165 ++++++++ .../web/api/StringPrettyComparator.java | 121 ++++++ .../java/org/linkedgeodata/web/main/AppConfig.java | 120 ++++++ .../web/main/MainLinkedGeoDataRestServer.java | 176 ++++++++ .../web/main/SparqlServiceFactoryImpl.java | 103 +++++ .../linkedgeodata/web/main/WebAppInitializer.java | 61 +++ .../org/linkedgeodata/web/main/WebMvcConfig.java | 148 +++++++ .../src/main/resources/jdklog.properties | 0 .../src/main/resources/log4j.properties | 2 +- linkedgeodata-core/src/main/webapp/WEB-INF/web.xml | 27 -- .../LinkedGeoDataApiMain.java | 2 +- pom.xml | 69 ++- 27 files changed, 1613 insertions(+), 607 deletions(-) delete mode 100644 linkedgeodata-core/src/main/java/org/linkedgeodata/rest/MessageBodyWriterHtml.java delete mode 100644 linkedgeodata-core/src/main/java/org/linkedgeodata/rest/MessageBodyWriterNTriples.java delete mode 100644 linkedgeodata-core/src/main/java/org/linkedgeodata/rest/RestApi.java rename linkedgeodata-core/src/main/java/org/linkedgeodata/{rest => web/api}/AbstractModelMessageReaderWriterProvider.java (97%) rename linkedgeodata-core/src/main/java/org/linkedgeodata/{rest => web/api}/LGDVocab.java (96%) rename linkedgeodata-core/src/main/java/org/linkedgeodata/{rest => web/api}/LGDVocabDefault.java (99%) create mode 100644 linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/LinkedGeoDataRestApiServlet.java create mode 100644 linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/MessageBodyWriterHtml.java create mode 100644 linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/MessageBodyWriterNTriples.java create mode 100644 linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/MessageBodyWriterNTriplesOld.java rename linkedgeodata-core/src/main/java/org/linkedgeodata/{rest => web/api}/MessageBodyWriterRdfXml.java (55%) rename linkedgeodata-core/src/main/java/org/linkedgeodata/{rest => web/api}/MessageBodyWriterTurtle.java (76%) create mode 100644 linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/RDFNodePrettyComparator.java create mode 100644 linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/RDFWriterHtml.java create mode 100644 linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/StringPrettyComparator.java create mode 100644 linkedgeodata-core/src/main/java/org/linkedgeodata/web/main/AppConfig.java create mode 100644 linkedgeodata-core/src/main/java/org/linkedgeodata/web/main/MainLinkedGeoDataRestServer.java create mode 100644 linkedgeodata-core/src/main/java/org/linkedgeodata/web/main/SparqlServiceFactoryImpl.java create mode 100644 linkedgeodata-core/src/main/java/org/linkedgeodata/web/main/WebAppInitializer.java create mode 100644 linkedgeodata-core/src/main/java/org/linkedgeodata/web/main/WebMvcConfig.java delete mode 100644 linkedgeodata-core/src/main/resources/jdklog.properties delete mode 100644 linkedgeodata-core/src/main/webapp/WEB-INF/web.xml rename {linkedgeodata-core/src/main/java/org/linkedgeodata/rest => linkedgeodata-trash}/LinkedGeoDataApiMain.java (99%) diff --git a/linkedgeodata-core/pom.xml b/linkedgeodata-core/pom.xml index 7dfb8eb..31c1b21 100644 --- a/linkedgeodata-core/pom.xml +++ b/linkedgeodata-core/pom.xml @@ -13,7 +13,7 @@ org.aksw.linkedgeodata linkedgeodata-parent - 0.4-SNAPSHOT + 0.4.2-SNAPSHOT + + + + + + + org.aksw.jena-sparql-api + jena-sparql-api-server + + + + org.aksw.jena-sparql-api + jena-sparql-api-servlets + + + + org.aksw.jena-sparql-api + jena-sparql-api-core + + + + org.aksw.jena-sparql-api + jena-sparql-api-cache-h2 + + + + org.springframework + spring-jdbc + + - org.aksw.sparqlify - sparqlify-core + commons-cli + commons-cli + + + + postgresql + postgresql + + + + com.jolbox + bonecp + 0.7.1.RELEASE + + + + org.openstreetmap.osmosis + osmosis-core + com.google.code.gson gson + + + commons-lang + commons-lang + + diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/dump/LgdDumper.java b/linkedgeodata-core/src/main/java/org/linkedgeodata/dump/LgdDumper.java index 81dfd07..7980010 100644 --- a/linkedgeodata-core/src/main/java/org/linkedgeodata/dump/LgdDumper.java +++ b/linkedgeodata-core/src/main/java/org/linkedgeodata/dump/LgdDumper.java @@ -27,7 +27,6 @@ import org.aksw.commons.collections.SinglePrefetchIterator; 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.HelpFormatter; import org.apache.commons.cli.Options; @@ -36,7 +35,6 @@ import org.apache.jena.atlas.lib.Sink; import org.apache.jena.riot.out.SinkTripleOutput; import org.apache.log4j.PropertyConfigurator; -import org.postgis.PGgeometry; import org.postgresql.ds.PGSimpleDataSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,15 +50,15 @@ import com.hp.hpl.jena.sparql.expr.NodeValue; import com.hp.hpl.jena.vocabulary.RDF; -interface GeometryRdfSerializer { - void write(PGgeometry geometry, Sink sink); -} - -class GeoVocabRdfSerializer implements GeometryRdfSerializer { - - public void write(PGgeometry geometry, Sink sink) { - } -} +//interface GeometryRdfSerializer { +// void write(PGgeometry geometry, Sink sink); +//} +// +//class GeoVocabRdfSerializer implements GeometryRdfSerializer { +// +// public void write(PGgeometry geometry, Sink sink) { +// } +//} class ValidatingSink implements Sink @@ -334,7 +332,7 @@ public static void main(String[] args) throws Exception { * FileInputStream("jdklog.properties")); */ - CommandLineParser cliParser = new GnuParser(); + GnuParser cliParser = new GnuParser(); /* cliOptions.addOption("t", "type", true, diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/rest/MessageBodyWriterHtml.java b/linkedgeodata-core/src/main/java/org/linkedgeodata/rest/MessageBodyWriterHtml.java deleted file mode 100644 index 5f4e662..0000000 --- a/linkedgeodata-core/src/main/java/org/linkedgeodata/rest/MessageBodyWriterHtml.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.linkedgeodata.rest; - -import javax.ws.rs.Consumes; -import javax.ws.rs.Produces; -import javax.ws.rs.ext.Provider; - -import com.hp.hpl.jena.sparql.engine.http.HttpParams; - -//@Provider -//@Produces({HttpParams.contentTypeTurtle}) -//@Consumes({HttpParams.contentTypeTurtle, "text/html"}) -public class MessageBodyWriterHtml - extends AbstractModelMessageReaderWriterProvider -{ - public MessageBodyWriterHtml() { - super("HTML"); - } -} \ No newline at end of file diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/rest/MessageBodyWriterNTriples.java b/linkedgeodata-core/src/main/java/org/linkedgeodata/rest/MessageBodyWriterNTriples.java deleted file mode 100644 index 06bb5d8..0000000 --- a/linkedgeodata-core/src/main/java/org/linkedgeodata/rest/MessageBodyWriterNTriples.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.linkedgeodata.rest; - -import java.io.IOException; -import java.io.OutputStream; -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; - -import javax.ws.rs.Produces; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.ext.MessageBodyWriter; -import javax.ws.rs.ext.Provider; - -import org.apache.jena.riot.WebContent; - -import com.hp.hpl.jena.rdf.model.Model; - -@Provider -@Produces({WebContent.contentTypeNTriples}) -//@Consumes({HttpParams.contentTypeNTriples}) -public class MessageBodyWriterNTriples - //extends AbstractModelMessageReaderWriterProvider - implements MessageBodyWriter -{ - public MessageBodyWriterNTriples() { - System.out.println("---"); - } - - /* - public MessageBodyWriterNTriples() { - super("N-TRIPLES"); - - throw new RuntimeException("Hooray - Initialized"); - }*/ - - @Override - public boolean isWriteable(Class type, Type genericType, - Annotation[] annotations, MediaType mediaType) { - return Model.class.isAssignableFrom(type); - } - - @Override - public void writeTo(Model t, Class type, Type genericType, - Annotation[] annotations, MediaType mediaType, - MultivaluedMap httpHeaders, - OutputStream entityStream) throws IOException, - WebApplicationException { - - - t.write(entityStream, "N-TRIPLES"); - } - - @Override - public long getSize(Model t, Class type, Type genericType, - Annotation[] annotations, MediaType mediaType) { - return -1; - } - -} \ No newline at end of file diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/rest/RestApi.java b/linkedgeodata-core/src/main/java/org/linkedgeodata/rest/RestApi.java deleted file mode 100644 index 5fe037f..0000000 --- a/linkedgeodata-core/src/main/java/org/linkedgeodata/rest/RestApi.java +++ /dev/null @@ -1,465 +0,0 @@ -package org.linkedgeodata.rest; - -import java.awt.geom.Point2D; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.lang.reflect.Type; -import java.net.URL; -import java.net.URLConnection; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; - -import org.aksw.commons.util.strings.StringUtils; -import org.aksw.jena_sparql_api.cache.core.QueryExecutionFactoryCacheEx; -import org.aksw.jena_sparql_api.cache.extra.CacheCoreEx; -import org.aksw.jena_sparql_api.cache.extra.CacheCoreH2; -import org.aksw.jena_sparql_api.cache.extra.CacheEx; -import org.aksw.jena_sparql_api.cache.extra.CacheExImpl; -import org.aksw.jena_sparql_api.core.QueryExecutionFactory; -import org.aksw.jena_sparql_api.delay.extra.Delayer; -import org.aksw.jena_sparql_api.delay.extra.DelayerDefault; -import org.aksw.jena_sparql_api.http.QueryExecutionFactoryHttp; -import org.aksw.jena_sparql_api.pagination.core.QueryExecutionFactoryPaginated; -import org.apache.log4j.lf5.util.StreamUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; -import com.hp.hpl.jena.rdf.model.Model; -import com.hp.hpl.jena.rdf.model.ModelFactory; -import com.hp.hpl.jena.rdf.model.Resource; -import com.hp.hpl.jena.vocabulary.DCTerms; -import com.hp.hpl.jena.vocabulary.OWL; -import com.sun.jersey.api.core.ResourceConfig; - -@Path("/api/3/") -public class RestApi { - - private static final Logger logger = LoggerFactory.getLogger(RestApi.class); - - private static LGDVocab vocab = new LGDVocabDefault(); - - private QueryExecutionFactory qeFactory; - - private Map prefixMap = new HashMap(); - - public RestApi(@Context ResourceConfig context) throws ClassNotFoundException, SQLException { - String serviceUrl = (String)context.getProperty("serviceUrl"); - - if(serviceUrl == null) { - throw new RuntimeException("'serviceUrl' parameter not set"); - } - - logger.info("Using service: " + serviceUrl); - - - //String service = "http://test.linkedgeodata.org/sparql"; - // String service = "http://localhost:7531/sparql"; - // service = "http://linkedgeodata.org/sparql"; - // String service = - // "http://[2001:638:902:2010:0:168:35:123]:7531/sparql"; - - QueryExecutionFactory tmp = new QueryExecutionFactoryHttp(serviceUrl); - - CacheCoreEx cacheBackend = CacheCoreH2.create("sparql", - 24l * 60l * 60l * 1000l, true); - CacheEx cacheFrontend = new CacheExImpl(cacheBackend); - - // QueryExecutionFactory - tmp = new QueryExecutionFactoryCacheEx(tmp, cacheFrontend); - - tmp = new QueryExecutionFactoryPaginated(tmp, 1000); - - qeFactory = tmp; - - // prefixMap.put(arg0, arg1); - } - - - private Model createModel() { - Model result = ModelFactory.createDefaultModel(); - result.setNsPrefixes(prefixMap); - - return result; - } - - @GET - @Path("/node/{id}") - public Model describeNode(@PathParam("id") long id) { - return describe("http://linkedgeodata.org/triplify/node" + id); - } - - @GET - @Path("/way/{id}") - public Model describeWay(@PathParam("id") long id) { - return describe("http://linkedgeodata.org/triplify/way" + id); - } - - @GET - @Path("/relation/{id}") - public Model describeRelation(@PathParam("id") long id) { - return describe("http://linkedgeodata.org/triplify/relation" + id); - } - - /* - * @GET - * - * @Path("/within/{yMin}-{yMax},{xMin}-{xMax}/{className}") // - * /label/{lang}/{predicate}/{value}") public Model - * within(@PathParam("xMin") double xMin, @PathParam("xMax") double xMax, - * @PathParam("yMin") double yMin, @PathParam("yMax") double yMax, - * @PathParam("className") String className) { - * - * } - */ - - @GET - @Path("/recent") - public Model recent() { - String query = "Construct { ?s ?p ?o } { ?s ?p ?o . Filter(?p = <" - + DCTerms.modified + ">) . } Order By Desc(?o) Limit 1000"; - - System.out.println(query); - - Model result = qeFactory.createQueryExecution(query).execConstruct(); - - return result; - } - - @GET - @Path("/intersects/{yMin}-{yMax},{xMin}-{xMax}/class/{className}") - // /label/{lang}/{predicate}/{value}") - public Model nearClass( - @PathParam("xMin") double xMin, - @PathParam("xMax") double xMax, - @PathParam("yMin") double yMin, - @PathParam("yMax") double yMax, - @PathParam("className") String className) { - Point2D.Double a = new Point2D.Double(xMin, yMin); - Point2D.Double b = new Point2D.Double(xMax, yMax); - - // Rectangle2D.Double c = new Rectangle2D.Double(a.x, a.y, b.x - a.x, - // b.y - a.y); - - String polygon = "POLYGON((" + a.x + " " + a.y + "," + b.x + " " + a.y - + "," + b.x + " " + b.y + "," + a.x + " " + b.y + "," + a.x - + " " + a.y + "))"; - - String filter = "Filter(ogc:intersects(?geo, ogc:geomFromText('" - + polygon + "')))"; - - String typeTriple = ""; - if (className != null) { - // TODO: Support resolving class labels - - typeTriple = "?s a . "; - } - - // Flat - String query - = "Prefix meta: Prefix geom: Prefix ogc: " - + "Construct { ?s ?p ?o } {\n" - + "?s a ?t . " - + "Filter(?t = meta:Node || ?t = meta:Way) ." - + typeTriple - + "?s geom:geometry ?x ." - + "?x ogc:asWKT ?geo ." - + "?s ?p ?o . " - + filter - + "} Order By ?s Limit 1000"; - - /* - + "Union " - + "{ ?s a meta:Way . " - + typeTriple - + " ?s geom:geometry ?x . ?x ogc:asWKT ?geo . ?s ?p ?o . " - + filter + "}" - +"} Order By ?s Limit 1000"; -*/ - // Intersects as sub-query - // String query = - // "Prefix geom: Prefix ogc: Construct { ?s ?p ?o } { " - // + typeTriple + - // " ?s ?p ?o . { Select ?s { ?s geom:geometry ?x . ?x ogc:asWKT ?geo . " - // + filter + "} } } Limit 1000"; - - // Test query - // String query = - // "Prefix geom: Prefix ogc: Construct { ?s ?p ?o } { ?s ?p ?o . ?s geom:geometry ?x . ?x ogc:asWKT ?geo . " - // + filter + "} Order By ?s Limit 1000"; - - // ??? - // String query = - // "Prefix geom: Prefix ogc: Construct { ?s ?p ?o } { { Select ?s { " - // + typeTriple + - // " ?s geom:geometry ?x . ?x ogc:asWKT ?geo } Order By Asc(?s) Limit 1000 }. ?s ?p ?o . " - // + filter + "} Order By Asc(?s) Limit 1000"; - - logger.debug(query); - - Model result = qeFactory.createQueryExecution(query).execConstruct(); - - return result; - } - - @GET - @Path("/intersects/{yMin}-{yMax},{xMin}-{xMax}") - public Model nearBasic( - @PathParam("xMin") double xMin, - @PathParam("xMax") double xMax, - @PathParam("yMin") double yMin, - @PathParam("yMax") double yMax) { - return nearClass(xMin, xMax, yMin, yMax, null); - } - - - /** - * - * @param x - * @param y - * @param radius in meters - * @return - */ - @GET - @Path("/intersects/{y},{x}/{radius}") - public Model nearBasic( - @PathParam("x") double x, - @PathParam("y") double y, - @PathParam("radius") double radius) - { - return nearClass(x, y, radius, null); - } - - - @GET - @Path("/intersects/{y},{x}/{radius}/class/{class}") - public Model nearClass( - @PathParam("x") double x, - @PathParam("y") double y, - @PathParam("radius") double radius, - @PathParam("class") String className - ) - { - return nearClasses(new Point2D.Double(x, y), radius, className); - } - - public Model nearClasses(Point2D point, double radius, String className) - { - String filter = "Filter(bif:st_intersects(?geo, bif:st_point(" + point.getY() + ", " + point.getX() + "), " + radius + "))"; - - - String typeTriple = ""; - if (className != null) { - // TODO: Support resolving class labels - typeTriple = "?s a . "; - } - - // Flat - String query - = "Prefix meta:\n" - + "Prefix geom:\n" - + "Prefix ogc:\n" - + "PREFIX bif: \n" - + "Construct { ?s ?p ?o } {\n" - + "?s a ?t .\n" - + "Filter(?t = meta:Node || ?t = meta:Way) .\n" - + typeTriple - + " ?s geom:geometry ?x .\n" + - "?x ogc:asWKT ?geo .\n" + - "?s ?p ?o . " - + filter - + "} Order By ?s Limit 1000"; - - logger.debug(query); - - Model result = qeFactory.createQueryExecution(query).execConstruct(); - - return result; - } - - @GET - @Path("/ontology") - public Model getOntology() throws Exception { - String query = "Construct { ?s ?p ?o } { ?s a <" + OWL.Class.toString() - + "> . ?s ?p ?o . }"; - Model result = qeFactory.createQueryExecution(query).execConstruct(); - - // result.write(System.out, "TURTLE"); - - return result; - } - - class JsonResponseItem { - String osm_type; - long osm_id; - - public JsonResponseItem() { - } - - public String getOsm_type() { - return osm_type; - } - - public void setOsm_type(String osm_type) { - this.osm_type = osm_type; - } - - public long getOsm_id() { - return osm_id; - } - - public void setOsm_id(long osm_id) { - this.osm_id = osm_id; - } - } - - private Delayer delayer = new DelayerDefault(1000); - - @GET - @Path("/geocode") - public Model geocode(@QueryParam("q") String queryString) throws Exception { - delayer.doDelay(); - - // queryString = StringUtils.urlDecode(queryString); - - String geocodeService = "http://open.mapquestapi.com/nominatim/v1/search"; - // http://nominatim.openstreetmap.org/search - - String uri = geocodeService + "?format=json&q=" + queryString; - - URL url = new URL(uri); - URLConnection c = url.openConnection(); - c.setRequestProperty("User-Agent", - "http://linkedgeodata.org, mailto:cstadler@informatik.uni-leipzig.de"); - - InputStream ins = c.getInputStream(); - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - StreamUtils.copy(ins, out); - - String json = out.toString(); - - Gson gson = new Gson(); - - Type collectionType = new TypeToken>() { - }.getType(); - Collection items = gson - .fromJson(json, collectionType); - - // gson.fromJson(json, JsonResponseItem.class); - - List resources = new ArrayList(); - for (JsonResponseItem item : items) { - Resource resource = null; - - if (item.getOsm_type().equals("node")) { - resource = vocab.createNIRNodeURI(item.getOsm_id()); - } else if (item.getOsm_type().equals("way")) { - resource = vocab.createNIRWayURI(item.getOsm_id()); - } else { - continue; - } - - resources.add(resource); - } - - Model result = createModel(); - - // String lgdService = "http://live.linkedgeodata.org/sparql"; - String lgdService = "http://test.linkedgeodata.org/sparql"; - QueryExecutionFactoryHttp qef = new QueryExecutionFactoryHttp( - lgdService, Collections.singleton("http://linkedgeodata.org")); - - for (Resource resource : resources) { - // QueryExecution qe = qef.createQueryExecution("Describe <" + - // resource.toString() + ">"); - // qe.execDescribe(result); - - // Workaround for Virtuoso returning invalid XML (which means we - // can't use the query execution - String serviceUri = "http://test.linkedgeodata.org/sparql?format=text%2Fplain&default-graph-uri=http%3A%2F%2Flinkedgeodata.org&query=DESCRIBE+<" - + StringUtils.urlEncode(resource.toString()) + ">"; - - URL serviceUrl = new URL(serviceUri); - URLConnection conn = serviceUrl.openConnection(); - conn.addRequestProperty("Accept", "text/plain"); - - /* - * ByteArrayOutputStream out1 = new ByteArrayOutputStream(); - * StreamUtils.copy(serviceUrl.openStream(), out1); String nt = - * out1.toString(); - */ - - InputStream in = null; - try { - in = conn.getInputStream(); - result.read(in, null, "N-TRIPLE"); - } finally { - if (in != null) { - in.close(); - } - } - - /* - * String tmp = "DESCRIBE <" + resource + ">"; - * System.out.println(tmp); QueryExecution qe = - * qef.createQueryExecution(tmp); qe.execDescribe(result); - */ - - } - - return result; - } - - public Model describe(String uri) { - String query = "Construct { ?s ?p ?o . } { ?s ?p ?o . Filter(?s = <" - + uri + ">) . }"; - // String query = "Describe <" + uri + ">"; - - return qeFactory.createQueryExecution(query).execConstruct(); - } - - /*************************************************************************/ - /* Helper methods for processing class and label restrictions */ - /*************************************************************************/ - - /* - * private String getLabelFilter(String var, String label, String matchMode, - * String value) { if (label == null || matchMode == null) return null; - * - * if (matchMode.equalsIgnoreCase("contains")) { //mm = - * TagFilterUtils.MatchMode.ILIKE; label = "%" + label.replace("%", "\\%") + - * "%"; - * - * } else if (matchMode.equalsIgnoreCase("startsWith")) { //mm = - * TagFilterUtils.MatchMode.ILIKE; //label = label.replace("%", "\\%") + - * "%"; return "Filter(regex(?" + var + ", " + value + ", 'i')" - * - * } if (matchMode.equalsIgnoreCase("ccontains")) { mm = - * TagFilterUtils.MatchMode.LIKE; label = "%" + label.replace("%", "\\%") + - * "%"; } else if (matchMode.equalsIgnoreCase("cstartsWith")) { mm = - * TagFilterUtils.MatchMode.LIKE; label = label.replace("%", "\\%") + "%"; } - * - * return new Pair(label, mm); } - * - * private List getEntityTagCondititions(String var, String - * className, String label, String language, String matchMode) { String - * result = ""; - * - * result += "Filter(?" + var + " a " } - */ - -} diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/rest/AbstractModelMessageReaderWriterProvider.java b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/AbstractModelMessageReaderWriterProvider.java similarity index 97% rename from linkedgeodata-core/src/main/java/org/linkedgeodata/rest/AbstractModelMessageReaderWriterProvider.java rename to linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/AbstractModelMessageReaderWriterProvider.java index b53c784..9ab3c9c 100644 --- a/linkedgeodata-core/src/main/java/org/linkedgeodata/rest/AbstractModelMessageReaderWriterProvider.java +++ b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/AbstractModelMessageReaderWriterProvider.java @@ -1,4 +1,4 @@ -package org.linkedgeodata.rest; +package org.linkedgeodata.web.api; import java.io.IOException; import java.io.OutputStream; @@ -58,6 +58,8 @@ public static RDFWriter getWriter(String format) } */ + + RDFWriter writer = ModelFactory.createDefaultModel().getWriter(format); return writer; diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/rest/LGDVocab.java b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/LGDVocab.java similarity index 96% rename from linkedgeodata-core/src/main/java/org/linkedgeodata/rest/LGDVocab.java rename to linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/LGDVocab.java index c553231..3752975 100644 --- a/linkedgeodata-core/src/main/java/org/linkedgeodata/rest/LGDVocab.java +++ b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/LGDVocab.java @@ -1,4 +1,4 @@ -package org.linkedgeodata.rest; +package org.linkedgeodata.web.api; import java.awt.geom.RectangularShape; diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/rest/LGDVocabDefault.java b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/LGDVocabDefault.java similarity index 99% rename from linkedgeodata-core/src/main/java/org/linkedgeodata/rest/LGDVocabDefault.java rename to linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/LGDVocabDefault.java index 77e47be..7b02e2a 100644 --- a/linkedgeodata-core/src/main/java/org/linkedgeodata/rest/LGDVocabDefault.java +++ b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/LGDVocabDefault.java @@ -18,7 +18,7 @@ * along with this program. If not, see . * */ -package org.linkedgeodata.rest; +package org.linkedgeodata.web.api; import java.awt.geom.RectangularShape; import java.util.Date; diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/LinkedGeoDataRestApiServlet.java b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/LinkedGeoDataRestApiServlet.java new file mode 100644 index 0000000..c1358fe --- /dev/null +++ b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/LinkedGeoDataRestApiServlet.java @@ -0,0 +1,422 @@ +package org.linkedgeodata.web.api; + +import java.awt.geom.Point2D; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.lang.reflect.Type; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.QueryParam; + +import org.aksw.commons.util.StreamUtils; +import org.aksw.commons.util.strings.StringUtils; +import org.aksw.jena_sparql_api.core.QueryExecutionFactory; +import org.aksw.jena_sparql_api.delay.extra.Delayer; +import org.aksw.jena_sparql_api.delay.extra.DelayerDefault; +import org.aksw.jena_sparql_api.http.QueryExecutionFactoryHttp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.ModelFactory; +import com.hp.hpl.jena.rdf.model.Resource; +import com.hp.hpl.jena.vocabulary.DCTerms; +import com.hp.hpl.jena.vocabulary.OWL; + +@Service +@Path("/") +public class LinkedGeoDataRestApiServlet { + + private static final Logger logger = LoggerFactory.getLogger(LinkedGeoDataRestApiServlet.class); + + private static LGDVocab vocab = new LGDVocabDefault(); + + private Map prefixMap = new HashMap(); + + + @Autowired + private HttpServletRequest req; + +// @Context +// private ServletContext servletContext; +// +// @javax.annotation.Resource(name="sparqlServiceFactory") +// private SparqlServiceFactory sparqlServiceFactory; + +// @javax.annotation.Resource(name="queryExecutionFactory") + @Autowired + private QueryExecutionFactory qef; + + + public LinkedGeoDataRestApiServlet() { + + } + + private Model createModel() { + Model result = ModelFactory.createDefaultModel(); + result.setNsPrefixes(prefixMap); + + return result; + } + + @GET + @Path("/node/{id}") + public Model describeNode(@PathParam("id") long id) { + return describe("http://linkedgeodata.org/triplify/node" + id); + } + + @GET + @Path("/way/{id}") + public Model describeWay(@PathParam("id") long id) { + return describe("http://linkedgeodata.org/triplify/way" + id); + } + + @GET + @Path("/relation/{id}") + public Model describeRelation(@PathParam("id") long id) { + return describe("http://linkedgeodata.org/triplify/relation" + id); + } + + /* + * @GET + * + * @Path("/within/{yMin}-{yMax},{xMin}-{xMax}/{className}") // + * /label/{lang}/{predicate}/{value}") public Model + * within(@PathParam("xMin") double xMin, @PathParam("xMax") double xMax, + * + * @PathParam("yMin") double yMin, @PathParam("yMax") double yMax, + * + * @PathParam("className") String className) { + * + * } + */ + + @GET + @Path("/recent") + public Model recent() { + String query = "Construct { ?s ?p ?o } { ?s ?p ?o . Filter(?p = <" + + DCTerms.modified + ">) . } Order By Desc(?o) Limit 1000"; + + System.out.println(query); + + Model result = qef.createQueryExecution(query).execConstruct(); + + return result; + } + + @GET + @Path("/intersects/{yMin}-{yMax},{xMin}-{xMax}/class/{className}") + // /label/{lang}/{predicate}/{value}") + public Model nearClass(@PathParam("xMin") double xMin, + @PathParam("xMax") double xMax, @PathParam("yMin") double yMin, + @PathParam("yMax") double yMax, + @PathParam("className") String className) { + Point2D.Double a = new Point2D.Double(xMin, yMin); + Point2D.Double b = new Point2D.Double(xMax, yMax); + + // Rectangle2D.Double c = new Rectangle2D.Double(a.x, a.y, b.x - a.x, + // b.y - a.y); + + String polygon = "POLYGON((" + a.x + " " + a.y + "," + b.x + " " + a.y + + "," + b.x + " " + b.y + "," + a.x + " " + b.y + "," + a.x + + " " + a.y + "))"; + + String filter = "Filter(ogc:intersects(?geo, ogc:geomFromText('" + + polygon + "')))"; + + String typeTriple = ""; + if (className != null) { + // TODO: Support resolving class labels + + typeTriple = "?s a . "; + } + + // Flat + String query = "Prefix meta: Prefix geom: Prefix ogc: " + + "Construct { ?s ?p ?o } {\n" + + "?s a ?t . " + + "Filter(?t = meta:Node || ?t = meta:Way) ." + + typeTriple + + "?s geom:geometry ?x ." + + "?x ogc:asWKT ?geo ." + + "?s ?p ?o . " + filter + "} Order By ?s Limit 1000"; + + /* + * + "Union " + "{ ?s a meta:Way . " + typeTriple + + * " ?s geom:geometry ?x . ?x ogc:asWKT ?geo . ?s ?p ?o . " + filter + + * "}" +"} Order By ?s Limit 1000"; + */ + // Intersects as sub-query + // String query = + // "Prefix geom: Prefix ogc: Construct { ?s ?p ?o } { " + // + typeTriple + + // " ?s ?p ?o . { Select ?s { ?s geom:geometry ?x . ?x ogc:asWKT ?geo . " + // + filter + "} } } Limit 1000"; + + // Test query + // String query = + // "Prefix geom: Prefix ogc: Construct { ?s ?p ?o } { ?s ?p ?o . ?s geom:geometry ?x . ?x ogc:asWKT ?geo . " + // + filter + "} Order By ?s Limit 1000"; + + // ??? + // String query = + // "Prefix geom: Prefix ogc: Construct { ?s ?p ?o } { { Select ?s { " + // + typeTriple + + // " ?s geom:geometry ?x . ?x ogc:asWKT ?geo } Order By Asc(?s) Limit 1000 }. ?s ?p ?o . " + // + filter + "} Order By Asc(?s) Limit 1000"; + + logger.debug(query); + + Model result = qef.createQueryExecution(query).execConstruct(); + + return result; + } + + @GET + @Path("/intersects/{yMin}-{yMax},{xMin}-{xMax}") + public Model nearBasic(@PathParam("xMin") double xMin, + @PathParam("xMax") double xMax, @PathParam("yMin") double yMin, + @PathParam("yMax") double yMax) { + return nearClass(xMin, xMax, yMin, yMax, null); + } + + /** + * + * @param x + * @param y + * @param radius + * in meters + * @return + */ + @GET + @Path("/intersects/{y},{x}/{radius}") + public Model nearBasic(@PathParam("x") double x, @PathParam("y") double y, + @PathParam("radius") double radius) { + return nearClass(x, y, radius, null); + } + + @GET + @Path("/intersects/{y},{x}/{radius}/class/{class}") + public Model nearClass(@PathParam("x") double x, @PathParam("y") double y, + @PathParam("radius") double radius, + @PathParam("class") String className) { + return nearClasses(new Point2D.Double(x, y), radius, className); + } + + public Model nearClasses(Point2D point, double radius, String className) { + String filter = "Filter(bif:st_intersects(?geo, bif:st_point(" + + point.getY() + ", " + point.getX() + "), " + radius + "))"; + + String typeTriple = ""; + if (className != null) { + // TODO: Support resolving class labels + typeTriple = "?s a . "; + } + + // Flat + String query = "Prefix meta:\n" + + "Prefix geom:\n" + + "Prefix ogc:\n" + + "PREFIX bif: \n" + + "Construct { ?s ?p ?o } {\n" + "?s a ?t .\n" + + "Filter(?t = meta:Node || ?t = meta:Way) .\n" + typeTriple + + " ?s geom:geometry ?x .\n" + "?x ogc:asWKT ?geo .\n" + + "?s ?p ?o . " + filter + "} Order By ?s Limit 1000"; + + logger.debug(query); + + Model result = qef.createQueryExecution(query).execConstruct(); + + return result; + } + + @GET + @Path("/ontology") + public Model getOntology() throws Exception { + String query = "Construct { ?s ?p ?o } { ?s a <" + OWL.Class.toString() + + "> . ?s ?p ?o . }"; + Model result = qef.createQueryExecution(query).execConstruct(); + + // result.write(System.out, "TURTLE"); + + return result; + } + + class JsonResponseItem { + String osm_type; + long osm_id; + + public JsonResponseItem() { + } + + public String getOsm_type() { + return osm_type; + } + + public void setOsm_type(String osm_type) { + this.osm_type = osm_type; + } + + public long getOsm_id() { + return osm_id; + } + + public void setOsm_id(long osm_id) { + this.osm_id = osm_id; + } + } + + private Delayer delayer = new DelayerDefault(1000); + + @GET + @Path("/geocode") + public Model geocode(@QueryParam("q") String queryString) throws Exception { + delayer.doDelay(); + + // queryString = StringUtils.urlDecode(queryString); + + String geocodeService = "http://open.mapquestapi.com/nominatim/v1/search"; + // http://nominatim.openstreetmap.org/search + + String uri = geocodeService + "?format=json&q=" + queryString; + + URL url = new URL(uri); + URLConnection c = url.openConnection(); + c.setRequestProperty("User-Agent", + "http://linkedgeodata.org, mailto:cstadler@informatik.uni-leipzig.de"); + + InputStream ins = c.getInputStream(); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + StreamUtils.copyThenClose(ins, out); + + String json = out.toString(); + + Gson gson = new Gson(); + + Type collectionType = new TypeToken>() { + }.getType(); + Collection items = gson + .fromJson(json, collectionType); + + // gson.fromJson(json, JsonResponseItem.class); + + List resources = new ArrayList(); + for (JsonResponseItem item : items) { + Resource resource = null; + + if (item.getOsm_type().equals("node")) { + resource = vocab.createNIRNodeURI(item.getOsm_id()); + } else if (item.getOsm_type().equals("way")) { + resource = vocab.createNIRWayURI(item.getOsm_id()); + } else { + continue; + } + + resources.add(resource); + } + + Model result = createModel(); + + // String lgdService = "http://live.linkedgeodata.org/sparql"; + String lgdService = "http://test.linkedgeodata.org/sparql"; + QueryExecutionFactoryHttp qef = new QueryExecutionFactoryHttp( + lgdService, Collections.singleton("http://linkedgeodata.org")); + + for (Resource resource : resources) { + // QueryExecution qe = qef.createQueryExecution("Describe <" + + // resource.toString() + ">"); + // qe.execDescribe(result); + + // Workaround for Virtuoso returning invalid XML (which means we + // can't use the query execution + String serviceUri = "http://test.linkedgeodata.org/sparql?format=text%2Fplain&default-graph-uri=http%3A%2F%2Flinkedgeodata.org&query=DESCRIBE+<" + + StringUtils.urlEncode(resource.toString()) + ">"; + + URL serviceUrl = new URL(serviceUri); + URLConnection conn = serviceUrl.openConnection(); + conn.addRequestProperty("Accept", "text/plain"); + + /* + * ByteArrayOutputStream out1 = new ByteArrayOutputStream(); + * StreamUtils.copy(serviceUrl.openStream(), out1); String nt = + * out1.toString(); + */ + + InputStream in = null; + try { + in = conn.getInputStream(); + result.read(in, null, "N-TRIPLE"); + } finally { + if (in != null) { + in.close(); + } + } + + /* + * String tmp = "DESCRIBE <" + resource + ">"; + * System.out.println(tmp); QueryExecution qe = + * qef.createQueryExecution(tmp); qe.execDescribe(result); + */ + + } + + return result; + } + + public Model describe(String uri) { + String query = "Construct { ?s ?p ?o . } { ?s ?p ?o . Filter(?s = <" + + uri + ">) . }"; + // String query = "Describe <" + uri + ">"; + + return qef.createQueryExecution(query).execConstruct(); + } + + /*************************************************************************/ + /* Helper methods for processing class and label restrictions */ + /*************************************************************************/ + + /* + * private String getLabelFilter(String var, String label, String matchMode, + * String value) { if (label == null || matchMode == null) return null; + * + * if (matchMode.equalsIgnoreCase("contains")) { //mm = + * TagFilterUtils.MatchMode.ILIKE; label = "%" + label.replace("%", "\\%") + + * "%"; + * + * } else if (matchMode.equalsIgnoreCase("startsWith")) { //mm = + * TagFilterUtils.MatchMode.ILIKE; //label = label.replace("%", "\\%") + + * "%"; return "Filter(regex(?" + var + ", " + value + ", 'i')" + * + * } if (matchMode.equalsIgnoreCase("ccontains")) { mm = + * TagFilterUtils.MatchMode.LIKE; label = "%" + label.replace("%", "\\%") + + * "%"; } else if (matchMode.equalsIgnoreCase("cstartsWith")) { mm = + * TagFilterUtils.MatchMode.LIKE; label = label.replace("%", "\\%") + "%"; } + * + * return new Pair(label, mm); } + * + * private List getEntityTagCondititions(String var, String + * className, String label, String language, String matchMode) { String + * result = ""; + * + * result += "Filter(?" + var + " a " } + */ + +} diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/MessageBodyWriterHtml.java b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/MessageBodyWriterHtml.java new file mode 100644 index 0000000..1e21de9 --- /dev/null +++ b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/MessageBodyWriterHtml.java @@ -0,0 +1,17 @@ +package org.linkedgeodata.web.api; + +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.ext.Provider; + + + +@Provider +@Produces({MediaType.TEXT_HTML}) +public class MessageBodyWriterHtml + extends AbstractModelMessageReaderWriterProvider +{ + public MessageBodyWriterHtml() { + super("HTML"); + } +} diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/MessageBodyWriterNTriples.java b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/MessageBodyWriterNTriples.java new file mode 100644 index 0000000..de83d65 --- /dev/null +++ b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/MessageBodyWriterNTriples.java @@ -0,0 +1,16 @@ +package org.linkedgeodata.web.api; + +import javax.ws.rs.Produces; +import javax.ws.rs.ext.Provider; + +import org.apache.jena.riot.WebContent; + +@Provider +@Produces({WebContent.contentTypeTextPlain, WebContent.contentTypeNTriples}) +public class MessageBodyWriterNTriples + extends AbstractModelMessageReaderWriterProvider +{ + public MessageBodyWriterNTriples() { + super("N-TRIPLES"); + } +} diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/MessageBodyWriterNTriplesOld.java b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/MessageBodyWriterNTriplesOld.java new file mode 100644 index 0000000..8d3b5b1 --- /dev/null +++ b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/MessageBodyWriterNTriplesOld.java @@ -0,0 +1,58 @@ +package org.linkedgeodata.web.api; + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.MessageBodyWriter; +import javax.ws.rs.ext.Provider; + +import org.apache.jena.riot.WebContent; + +import com.hp.hpl.jena.rdf.model.Model; +// +//@Provider +//@Produces({WebContent.contentTypeTextPlain, WebContent.contentTypeNTriples}) +//public class MessageBodyWriterNTriplesOld +// implements MessageBodyWriter +//{ +// public MessageBodyWriterNTriplesOld() { +// //super("N-TRIPLES"); +// } +// +// /* +// public MessageBodyWriterNTriples() { +// super("N-TRIPLES"); +// +// throw new RuntimeException("Hooray - Initialized"); +// }*/ +// +// @Override +// public boolean isWriteable(Class type, Type genericType, +// Annotation[] annotations, MediaType mediaType) { +// return Model.class.isAssignableFrom(type); +// } +// +// @Override +// public void writeTo(Model t, Class type, Type genericType, +// Annotation[] annotations, MediaType mediaType, +// MultivaluedMap httpHeaders, +// OutputStream entityStream) throws IOException, +// WebApplicationException { +// +// +// t.write(entityStream, "N-TRIPLES"); +// } +// +// @Override +// public long getSize(Model t, Class type, Type genericType, +// Annotation[] annotations, MediaType mediaType) { +// return -1; +// } +// +//} \ No newline at end of file diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/rest/MessageBodyWriterRdfXml.java b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/MessageBodyWriterRdfXml.java similarity index 55% rename from linkedgeodata-core/src/main/java/org/linkedgeodata/rest/MessageBodyWriterRdfXml.java rename to linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/MessageBodyWriterRdfXml.java index dfb0bbc..963cf1a 100644 --- a/linkedgeodata-core/src/main/java/org/linkedgeodata/rest/MessageBodyWriterRdfXml.java +++ b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/MessageBodyWriterRdfXml.java @@ -1,4 +1,4 @@ -package org.linkedgeodata.rest; +package org.linkedgeodata.web.api; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; @@ -6,11 +6,8 @@ import org.apache.jena.riot.WebContent; -//@Produces({HttpParams.contentTypeTextPlain}) -//@Consumes({HttpParams.contentTypeTextPlain}) @Provider -@Produces({WebContent.contentTypeRDFXML, MediaType.TEXT_PLAIN, "*/*"}) -//@Consumes({HttpParams.contentTypeRDFXML}) +@Produces({WebContent.contentTypeRDFXML, MediaType.APPLICATION_XML, "*/*"}) public class MessageBodyWriterRdfXml extends AbstractModelMessageReaderWriterProvider { diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/rest/MessageBodyWriterTurtle.java b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/MessageBodyWriterTurtle.java similarity index 76% rename from linkedgeodata-core/src/main/java/org/linkedgeodata/rest/MessageBodyWriterTurtle.java rename to linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/MessageBodyWriterTurtle.java index 90030b1..30e213c 100644 --- a/linkedgeodata-core/src/main/java/org/linkedgeodata/rest/MessageBodyWriterTurtle.java +++ b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/MessageBodyWriterTurtle.java @@ -1,4 +1,4 @@ -package org.linkedgeodata.rest; +package org.linkedgeodata.web.api; import javax.ws.rs.Produces; import javax.ws.rs.ext.Provider; @@ -7,7 +7,6 @@ @Provider @Produces({WebContent.contentTypeTurtle}) -//@Consumes({HttpParams.contentTypeTurtle, "text/xml", "*/*"}) public class MessageBodyWriterTurtle extends AbstractModelMessageReaderWriterProvider { diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/RDFNodePrettyComparator.java b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/RDFNodePrettyComparator.java new file mode 100644 index 0000000..6b0903d --- /dev/null +++ b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/RDFNodePrettyComparator.java @@ -0,0 +1,71 @@ +package org.linkedgeodata.web.api; + +import java.util.Comparator; + +import com.hp.hpl.jena.rdf.model.Literal; +import com.hp.hpl.jena.rdf.model.RDFNode; + +public class RDFNodePrettyComparator + implements Comparator +{ + private StringPrettyComparator stringComparator = new StringPrettyComparator(); + + int getTypeSortValue(RDFNode node) + { + if(node.isURIResource()) + return 0; + else if(node.isLiteral()) + return 1; + else if(node.isAnon()) + return 2; + else + throw new RuntimeException("Shouldn't happen"); + } + + public int compareLiteral(Literal a, Literal b) + { + int tA = (a.getDatatype() == null) ? -1 : 0; + int tB = (b.getDatatype() == null) ? 1 : 0; + + int d = tB + tA; + if(d != 0) + return d; + + if(a.getDatatype() != null) { + d = stringComparator.compare(a.getDatatypeURI(), b.getDatatypeURI()); + if(d != 0) + return d; + + return stringComparator.compare(a.getValue().toString(), b.getValue().toString()); + } else { + d = a.getLanguage().compareTo(b.getLanguage()); + + if(d != 0) + return d; + + return stringComparator.compare(a.getValue().toString(), b.getValue().toString()); + } + } + + @Override + public int compare(RDFNode a, RDFNode b) + { + int tA = getTypeSortValue(a); + int tB = getTypeSortValue(b); + + int d = tB - tA; + if(d != 0) + return d; + + if(a.isURIResource()) { + return stringComparator.compare(a.asNode().getURI(), b.asNode().getURI()); + } else if(a.isLiteral()) { + return compareLiteral(a.as(Literal.class), b.as(Literal.class)); + } else if(a.isAnon()) { + return stringComparator.compare(a.asNode().getBlankNodeLabel(), b.asNode().getBlankNodeLabel()); + } + + throw new RuntimeException("Shouldn't happen"); + } + +} diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/RDFWriterHtml.java b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/RDFWriterHtml.java new file mode 100644 index 0000000..af859c3 --- /dev/null +++ b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/RDFWriterHtml.java @@ -0,0 +1,165 @@ +package org.linkedgeodata.web.api; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.Writer; +import java.util.Comparator; +import java.util.Map; +import java.util.NavigableMap; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +import org.aksw.jena_sparql_api.utils.ModelUtils; +import org.apache.commons.lang.StringEscapeUtils; + +import com.hp.hpl.jena.rdf.model.Literal; +import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.RDFErrorHandler; +import com.hp.hpl.jena.rdf.model.RDFNode; +import com.hp.hpl.jena.rdf.model.RDFWriter; +import com.hp.hpl.jena.rdf.model.Resource; +import com.hp.hpl.jena.rdf.model.Statement; +import com.hp.hpl.jena.rdf.model.StmtIterator; + +public class RDFWriterHtml + implements RDFWriter +{ + String nodeToString(RDFNode node, NavigableMap nsToPrefix, String attributes) + { + if(node.isURIResource()) { + String uri = node.as(Resource.class).getURI(); + String prettyURI = ModelUtils.prettyUri(uri, nsToPrefix); + + return "" + StringEscapeUtils.escapeHtml(prettyURI) + ""; + } + else if(node.isLiteral()) { + Literal literal = node.as(Literal.class); + String valuePart = literal.getValue().toString(); + String suffixPart; + if(literal.getDatatype() != null) { + suffixPart = "^^" + ModelUtils.prettyUri(literal.getDatatypeURI(), nsToPrefix); + } + else { + suffixPart = literal.getLanguage().isEmpty() + ? "" + : "@" + literal.getLanguage(); + } + + String result = StringEscapeUtils.escapeHtml(valuePart + suffixPart); + + return result; + //return "

" + result + "

"; + } + else if(node.isAnon()) { + return StringEscapeUtils.escapeHtml(node.toString()); + } + + throw new RuntimeException("Should not happen"); + } + + @Override + public void write(Model model, Writer out, String base) + { + try { + _write(model, out, base); + } catch(Exception e) { + throw new RuntimeException(e); + } + } + + //@Override + public void _write(Model model, Writer out, String base) + throws IOException + { + // Create the reverse map for mapping namespaces to prefixes + Map prefixToNs = model.getNsPrefixMap(); + NavigableMap nsToPrefix = new TreeMap(); + for(Map.Entry item : prefixToNs.entrySet()) + nsToPrefix.put(item.getValue(), item.getKey()); + + + // Sort the for output + Comparator comp = new RDFNodePrettyComparator(); + + StmtIterator itStmt = model.listStatements(); + Map>> spo = new TreeMap>>(comp); + while(itStmt.hasNext()) { + Statement stmt = itStmt.next(); + + + Map> po = spo.get(stmt.getSubject()); + if(po == null) { + po = new TreeMap>(comp); + spo.put(stmt.getSubject(), po); + } + + Set p = po.get(stmt.getPredicate()); + if(p == null) { + p = new TreeSet(comp); + po.put(stmt.getPredicate(), p); + } + + p.add(stmt.getObject()); + } + itStmt.close(); + + boolean isOdd = true; + + out.write("\n"); + + // Output HTML + for(Map.Entry>> s2po : spo.entrySet()) { + RDFNode subject = s2po.getKey(); + + + out.write("\n"); + + for(Map.Entry> p2o : s2po.getValue().entrySet()) { + RDFNode predicate = p2o.getKey(); + + String predField = nodeToString(predicate, nsToPrefix, "class='content'"); + + for(RDFNode o : p2o.getValue()) { + + String cssClass = isOdd ? "odd" : "even"; + isOdd = !isOdd; + + out.write("\n"); + + predField = ""; + } + + + } + //out.write("
\n"); + //out.write("
\n"); + out.write("\n"); + } + + out.write("
" + nodeToString(subject, nsToPrefix, "class='heading'") + "
" + predField + "" + nodeToString(o, nsToPrefix, "class='content'") + "
 
\n"); + + out.flush(); + } + + @Override + public void write(Model model, OutputStream out, String base) + { + write(model, new PrintWriter(out), base); + } + + @Override + public Object setProperty(String propName, Object propValue) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public RDFErrorHandler setErrorHandler(RDFErrorHandler errHandler) + { + // TODO Auto-generated method stub + return null; + } +} \ No newline at end of file diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/StringPrettyComparator.java b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/StringPrettyComparator.java new file mode 100644 index 0000000..12f2d8e --- /dev/null +++ b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/api/StringPrettyComparator.java @@ -0,0 +1,121 @@ +package org.linkedgeodata.web.api; + +import java.util.Comparator; + +/** + * Identifies sub-strings that correspond to integers and compares those parts + * as integers. Therefore strings like a1, a10 a2 will be sorted as + * a1, a2, a10 rather than a1, a10, a2 + * + * @author raven + * + */ +public class StringPrettyComparator + implements Comparator +{ + public static boolean isDigitPrefix(String s) + { + if(s.isEmpty()) { + return false; + } + + boolean result = Character.isDigit(s.charAt(0)); + return result; + } + + public static String getPrefix(String s, boolean digitMode) + { + if(s.isEmpty()) { + return ""; + } + + int i = 0; + for(i = 0; i < s.length(); ++i) { + if(Character.isDigit(s.charAt(i)) != digitMode) { + break; + } + } + //while(Character.isDigit(s.charAt(i)) == digitMode && (i < s.length() - 1)) + //++i; + + String part = s.substring(0, i); + + return part; + } + + + + public static boolean isDigitSuffix(String s) + { + if(s.isEmpty()) + return false; + + boolean result = Character.isDigit(s.charAt(s.length() - 1)); + return result; + } + + public static String getSuffix(String s, boolean digitMode) + { + if(s.isEmpty()) { + return ""; + } + + int i = s.length() - 1; + + for(; Character.isDigit(s.charAt(i)) == digitMode && i > 0; --i); + + String part = s.substring(i); + + return part; + } + + public static int doCompare(String a, String b) { + while(true) { + if(a.isEmpty() && b.isEmpty()) { + return 0; + } + + // Sort empty strings before non-empty ones + int da = a.isEmpty() ? -1 : 0; + int db = b.isEmpty() ? 1 : 0; + + int d = db + da; + if(d != 0) { + return d; + } + + + // Sort values before strings + da = isDigitPrefix(a) ? -1 : 0; + db = isDigitPrefix(b) ? 1 : 0; + + d = db + da; + if(d != 0) { + return d; + } + + String sa = getPrefix(a, da != 0); + String sb = getPrefix(b, db != 0); + + d = (da != 0) + ? ((Long)Long.parseLong(sa)).compareTo(Long.parseLong(sb)) + : sa.compareTo(sb); + + if(d != 0) { + return d; + } + + a = a.substring(sa.length()); + b = b.substring(sb.length()); + //a = a.substring(0, a.length() - sa.length()); + //b = b.substring(0, b.length() - sb.length()); + } + } + + @Override + public int compare(String a, String b) + { + int result = StringPrettyComparator.doCompare(a, b); + return result; + } +} diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/web/main/AppConfig.java b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/main/AppConfig.java new file mode 100644 index 0000000..60ea7dd --- /dev/null +++ b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/main/AppConfig.java @@ -0,0 +1,120 @@ +package org.linkedgeodata.web.main; + +import java.util.HashSet; + +import javax.annotation.Resource; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.sql.DataSource; + +import org.aksw.jena_sparql_api.cache.extra.CacheBackend; +import org.aksw.jena_sparql_api.cache.extra.CacheFrontend; +import org.aksw.jena_sparql_api.cache.extra.CacheFrontendImpl; +import org.aksw.jena_sparql_api.cache.staging.CacheBackendDao; +import org.aksw.jena_sparql_api.cache.staging.CacheBackendDaoPostgres; +import org.aksw.jena_sparql_api.cache.staging.CacheBackendDataSource; +import org.aksw.jena_sparql_api.core.QueryExecutionFactory; +import org.aksw.jena_sparql_api.core.SparqlServiceFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.jdbc.datasource.DriverManagerDataSource; + +import com.jolbox.bonecp.BoneCPConfig; +import com.jolbox.bonecp.BoneCPDataSource; + +@Configuration +@ComponentScan({"org.linkedgeodata.web.api"}) +//@PropertySource("classpath:config/jdbc/jdbc.properties") +// @EnableTransactionManagement +public class AppConfig { + private static final Logger logger = LoggerFactory + .getLogger(AppConfig.class); + + private static final String JDBC_DRIVER = "jdbc.driver"; + private static final String JDBC_PASSWORD = "jdbc.password"; + private static final String JDBC_URL = "jdbc.url"; + private static final String JDBC_USERNAME = "jdbc.username"; + + + @Resource + private Environment env; + + /** + * When starting the server from the command line, this attribute can be set + * to override any other means of creating a data source + */ + public static DataSource cliDataSource = null; + public static String lgdServiceUrl = null; + + @Bean + public DataSource dataSource() throws IllegalArgumentException, + ClassNotFoundException { + + // TODO Somehow allow loading drivers dynamically + Class.forName("org.postgresql.Driver"); + + DataSource dsBean = null; + + try { + + String jndiName = "java:comp/env/jdbc/linkedGeoDataDs"; + Context ctx = new InitialContext(); + dsBean = (DataSource) ctx.lookup(jndiName); + + } catch (NamingException e) { + logger.info("Exception on retrieving initial JNDI context - trying a different method", e); + } + + if(dsBean == null) { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + + dataSource.setDriverClassName(env.getRequiredProperty(JDBC_DRIVER)); + dataSource.setUrl(env.getRequiredProperty(JDBC_URL)); + dataSource.setUsername(env.getRequiredProperty(JDBC_USERNAME)); + dataSource.setPassword(env.getRequiredProperty(JDBC_PASSWORD)); + + dsBean = dataSource; + } + + BoneCPConfig cpConfig = new BoneCPConfig(); + cpConfig.setDatasourceBean(dsBean); + + cpConfig.setMinConnectionsPerPartition(1); + cpConfig.setMaxConnectionsPerPartition(10); + cpConfig.setPartitionCount(2); + //cpConfig.setCloseConnectionWatch(true); + + DataSource result = new BoneCPDataSource(cpConfig); + + return result; + } + + @Bean + @Autowired + public SparqlServiceFactory sparqlServiceFactory(DataSource dataSource) { + CacheBackendDao dao = new CacheBackendDaoPostgres(); + CacheBackend cacheBackend = new CacheBackendDataSource(dataSource, dao); + CacheFrontend cacheFrontend = new CacheFrontendImpl(cacheBackend); + + SparqlServiceFactory result = new SparqlServiceFactoryImpl(cacheFrontend); + return result; + } + + @Bean + @Autowired + public QueryExecutionFactory queryExecutionFactory(SparqlServiceFactory sparqlServiceFactory) { + if(lgdServiceUrl == null) { + throw new RuntimeException("LinkedGeoData Service Url not specified"); + } + + QueryExecutionFactory result = sparqlServiceFactory.createSparqlService(lgdServiceUrl, new HashSet()); + return result; + } + +} diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/web/main/MainLinkedGeoDataRestServer.java b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/main/MainLinkedGeoDataRestServer.java new file mode 100644 index 0000000..2a9f890 --- /dev/null +++ b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/main/MainLinkedGeoDataRestServer.java @@ -0,0 +1,176 @@ +package org.linkedgeodata.web.main; + +import java.net.URL; +import java.net.URLClassLoader; +import java.security.ProtectionDomain; + +import javax.servlet.ServletException; + +import org.aksw.commons.util.slf4j.LoggerCount; +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.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.bio.SocketConnector; +import org.eclipse.jetty.util.component.AbstractLifeCycle.AbstractLifeCycleListener; +import org.eclipse.jetty.util.component.LifeCycle; +import org.eclipse.jetty.webapp.WebAppContext; +import org.linkedgeodata.web.api.RDFWriterHtml; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.hp.hpl.jena.rdf.model.impl.RDFWriterFImpl; + + +/* +class HtmlWriter + implements RDFWriter +{ + + @Override + public void write(Model model, Writer out, String base) { + // TODO Auto-generated method stub + + } + + @Override + public void write(Model model, OutputStream out, String base) { + // TODO Auto-generated method stub + + } + + @Override + public Object setProperty(String propName, Object propValue) { + // TODO Auto-generated method stub + return null; + } + + @Override + public RDFErrorHandler setErrorHandler(RDFErrorHandler errHandler) { + // TODO Auto-generated method stub + return null; + } +} +*/ + +/** + * + * + * http://stackoverflow.com/questions/10738816/deploying-a-servlet- + * programmatically-with-jetty + * http://stackoverflow.com/questions/3718221/add-resources + * -to-jetty-programmatically + * + * @author raven + * + * + */ +public class MainLinkedGeoDataRestServer { + + private static final Logger logger = LoggerFactory.getLogger(MainLinkedGeoDataRestServer.class); + + + private static final Options cliOptions = new Options(); + + static { + cliOptions.addOption("P", "port", true, "Server port"); + cliOptions.addOption("s", "service", true, "Sparql service url"); + } + + public static void printClassPath() { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + + URL[] urls = ((URLClassLoader)cl).getURLs(); + + for(URL url: urls){ + System.out.println(url.getFile()); + } + } + + // Source: + // http://eclipsesource.com/blogs/2009/10/02/executable-wars-with-jetty/ + public static void main(String[] args) throws Exception { + + RDFWriterFImpl.setBaseWriterClassName("HTML", RDFWriterHtml.class.getName()); + + + LoggerCount loggerCount = new LoggerCount(logger); + + //Class.forName("org.postgresql.Driver"); + + CommandLineParser cliParser = new GnuParser(); + CommandLine commandLine = cliParser.parse(cliOptions, args); + + + String portStr = commandLine.getOptionValue("P", "9998"); + int port = Integer.parseInt(portStr); + + AppConfig.lgdServiceUrl = commandLine.getOptionValue("s", "http://linkedgeodata.org/vsparql"); + + + ProtectionDomain protectionDomain = MainLinkedGeoDataRestServer.class.getProtectionDomain(); + URL location = protectionDomain.getCodeSource().getLocation(); + String externalForm = location.toExternalForm(); + + logger.debug("External form: " + externalForm); + + // Try to detect whether we are being run from an + // archive (uber jar / war) or just from compiled classes + if(externalForm.endsWith("/classes/")) { + externalForm = "src/main/webapp"; + //externalForm = "target/sparqlify-web-admin-server"; + } + + + logger.debug("Loading webAppContext from " + externalForm); + + + startServer(port, externalForm); + } + + public static void startServer(int port, String externalForm) { + + + Server server = new Server(); + SocketConnector connector = new SocketConnector(); + + // Set some timeout options to make debugging easier. + connector.setMaxIdleTime(1000 * 60 * 60); + connector.setSoLingerTime(-1); + connector.setPort(port); + server.setConnectors(new Connector[] { connector }); + + final WebAppContext webAppContext = new WebAppContext(); + + webAppContext.addLifeCycleListener(new AbstractLifeCycleListener() { + @Override + public void lifeCycleStarting(LifeCycle arg0) { + WebAppInitializer initializer = new WebAppInitializer(); + try { + initializer.onStartup(webAppContext.getServletContext()); + } catch (ServletException e) { + throw new RuntimeException(e); + } + } + }); + + webAppContext.setServer(server); + webAppContext.setContextPath("/"); + + //context.setDescriptor(externalForm + "/WEB-INF/web.xml"); + webAppContext.setWar(externalForm); + + server.setHandler(webAppContext); + try { + server.start(); + System.in.read(); + server.stop(); + server.join(); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } +} diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/web/main/SparqlServiceFactoryImpl.java b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/main/SparqlServiceFactoryImpl.java new file mode 100644 index 0000000..81592c3 --- /dev/null +++ b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/main/SparqlServiceFactoryImpl.java @@ -0,0 +1,103 @@ +package org.linkedgeodata.web.main; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import org.aksw.jena_sparql_api.cache.core.QueryExecutionFactoryCacheEx; +import org.aksw.jena_sparql_api.cache.extra.CacheFrontend; +import org.aksw.jena_sparql_api.core.QueryExecutionFactory; +import org.aksw.jena_sparql_api.core.SparqlServiceFactory; +import org.aksw.jena_sparql_api.http.QueryExecutionFactoryHttp; +import org.aksw.jena_sparql_api.pagination.core.QueryExecutionFactoryPaginated; +import org.aksw.jena_sparql_api.retry.core.QueryExecutionFactoryRetry; + + +public class SparqlServiceFactoryImpl + implements SparqlServiceFactory +{ + private Map keyToSparqlService = new HashMap(); + + private CacheFrontend cacheFrontend = null; + + public SparqlServiceFactoryImpl(CacheFrontend cacheFrontend) { + this.cacheFrontend = cacheFrontend; + } + + @Override + public QueryExecutionFactory createSparqlService(String serviceUri, Collection defaultGraphUris) { + + Set tmp = new TreeSet(defaultGraphUris); + String key = serviceUri + tmp; + + QueryExecutionFactory result; + + result = keyToSparqlService.get(key); + + if(result == null) { + + result = new QueryExecutionFactoryHttp(serviceUri, defaultGraphUris); + //result = new QueryExecutionFactoryPag +// result = new QueryExecutionFactoryDelay(result, 1000l); // 1 second delay between queries + result = new QueryExecutionFactoryRetry(result, 3, 5000l); // 3 retries, 5 second delay between retries + if(cacheFrontend != null) { + result = new QueryExecutionFactoryCacheEx(result, cacheFrontend); + } + result = new QueryExecutionFactoryPaginated(result); + + keyToSparqlService.put(key, result); + } + + return result; + } + + +// +// public static QueryExecutionFactory wrapWithCache(QueryExecutionFactory qef) +// throws Exception { +// Class.forName("org.h2.Driver"); +// +// PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); +// +// String schemaResourceName = "/org/aksw/jena_sparql_api/cache/cache-schema-pgsql.sql"; +// org.springframework.core.io.Resource resource = resolver.getResource(schemaResourceName); +// +// if(resource == null) { +// throw new RuntimeException("SQL schema file not found"); +// } +// +// +// JdbcDataSource dataSource = new JdbcDataSource(); +// dataSource.setURL("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"); +// dataSource.setUser("sa"); +// dataSource.setPassword("sa"); +// +//// +//// URL resource = RestApi.class.getResource(schemaResourceName); +// +// InputStream in = resource.getInputStream(); +// +// if (in == null) { +// throw new RuntimeException("Failed to load resource: " +// + schemaResourceName); +// } +// +// InputStreamReader reader = new InputStreamReader(in); +// Connection conn = dataSource.getConnection(); +// try { +// RunScript.execute(conn, reader); +// } finally { +// conn.close(); +// } +// +// CacheBackendDao dao = new CacheBackendDaoPostgres(); +// CacheBackend cacheBackend = new CacheBackendDataSource(dataSource, dao); +// CacheFrontend cacheFrontend = new CacheFrontendImpl(cacheBackend); +// qef = new QueryExecutionFactoryCacheEx(qef, cacheFrontend); +// +// return qef; +// } + +} \ No newline at end of file diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/web/main/WebAppInitializer.java b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/main/WebAppInitializer.java new file mode 100644 index 0000000..6aa5450 --- /dev/null +++ b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/main/WebAppInitializer.java @@ -0,0 +1,61 @@ +package org.linkedgeodata.web.main; + +import javax.servlet.FilterRegistration; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; + +import org.aksw.jena_sparql_api.web.filters.CorsFilter; +import org.springframework.web.WebApplicationInitializer; +import org.springframework.web.context.ContextLoaderListener; +import org.springframework.web.context.request.RequestContextListener; +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; +import org.springframework.web.servlet.DispatcherServlet; + +import com.sun.jersey.spi.spring.container.servlet.SpringServlet; + + +public class WebAppInitializer + implements WebApplicationInitializer +{ + @Override + public void onStartup(ServletContext servletContext) + throws ServletException + { + // Create the 'root' Spring application context + AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext(); + rootContext.register(AppConfig.class); + + // Manage the lifecycle of the root application context + servletContext.addListener(new ContextLoaderListener(rootContext)); + servletContext.addListener(new RequestContextListener()); + + { + FilterRegistration.Dynamic fr = servletContext.addFilter("CorsFilter", new CorsFilter()); + fr.addMappingForUrlPatterns(null, true, "/*"); + // fr.setInitParameter("dispatcher", "REQUEST"); + } + +// { +// FilterRegistration.Dynamic fr = servletContext.addFilter("UrlRewriteFilter", new UrlRewriteFilter()); +// fr.setInitParameter("dispatcher", "REQUEST"); +// fr.setInitParameter("dispatcher", "FORWARD"); +// fr.addMappingForUrlPatterns(null, true, "/*"); +// } + + + // Create the dispatcher servlet's Spring application context + AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext(); + dispatcherContext.register(WebMvcConfig.class); + + ServletRegistration.Dynamic lgdApiServlet = servletContext.addServlet("linkedgeodata-api-servlet", new SpringServlet()); + lgdApiServlet.setInitParameter("com.sun.jersey.config.property.packages", "org.linkedgeodata.web.api"); + lgdApiServlet.addMapping("/api/3/*"); + lgdApiServlet.setLoadOnStartup(1); + + + ServletRegistration.Dynamic defaultServlet = servletContext.addServlet("default-servlet", new DispatcherServlet(dispatcherContext)); + defaultServlet.addMapping("*.do"); + defaultServlet.setLoadOnStartup(1); + } +} diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/web/main/WebMvcConfig.java b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/main/WebMvcConfig.java new file mode 100644 index 0000000..8c74832 --- /dev/null +++ b/linkedgeodata-core/src/main/java/org/linkedgeodata/web/main/WebMvcConfig.java @@ -0,0 +1,148 @@ +package org.linkedgeodata.web.main; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletContext; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.web.accept.ContentNegotiationManager; +import org.springframework.web.servlet.ViewResolver; +import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; +import org.springframework.web.servlet.view.ContentNegotiatingViewResolver; +import org.springframework.web.servlet.view.InternalResourceViewResolver; +import org.springframework.web.servlet.view.JstlView; +import org.springframework.web.servlet.view.UrlBasedViewResolver; + + + +@Configuration +@EnableWebMvc +@ComponentScan(basePackages = "org.aksw.linkedgeodata.web.api") +public class WebMvcConfig + extends WebMvcConfigurerAdapter +{ + @Autowired + private ServletContext servletContext; + + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("/bower_components/**").addResourceLocations("/bower_components/"); + registry.addResourceHandler("/scripts/**").addResourceLocations("/scripts/"); + registry.addResourceHandler("/styles/**").addResourceLocations("/styles/"); + } + + + @Override + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/index.do").setViewName("index"); + } + + +// @Bean +// public ServletForwardingController endpointsFwdCtrl() { +// ServletForwardingController result = new ServletForwardingController(); +// result.setServletName("sparqlify-endpoints"); +// +// return result; +// } + +// @Bean +// public SimpleUrlHandlerMapping urlMapping() { +// SimpleUrlHandlerMapping result = new SimpleUrlHandlerMapping(); +// +//// ServletForwardingController fwd1 = new ServletForwardingController(); +//// fwd1.setServletName("sparqlify-admin-api"); +//// +//// +//// Map urlMap = new HashMap(); +//// urlMap.put("/manager/*", fwd1); +//// urlMap.put("/endpoints/*", fwd2); +//// result.setUrlMap(urlMap); +// +// Properties mappings = new Properties(); +// mappings.put("/endpoints/*", "endpointsFwdCtrl"); +// +// result.setMappings(mappings); +// +// return result; +// } + + + //http://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc/ + @Override + public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { + + Map mediaTypes = new HashMap(); + mediaTypes.put("htm", MediaType.TEXT_HTML); + mediaTypes.put("html", MediaType.TEXT_HTML); + mediaTypes.put("json", MediaType.APPLICATION_JSON); + + + configurer.favorPathExtension(true); + configurer.favorParameter(true); + configurer.parameterName("mediaType"); + configurer.ignoreAcceptHeader(false); + configurer.useJaf(false); + configurer.defaultContentType(MediaType.TEXT_HTML); + configurer.mediaTypes(mediaTypes); + } + + @Bean + public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) { + // Define the view resolvers + List resolvers = new ArrayList(); + + //resolvers.add(internalResourceViewResolverJsp()); + //resolvers.add(urlBasedViewResolver()); + resolvers.add(internalResourceViewResolverHtml()); + + // Create the CNVR plugging in the resolvers and the content-negotiation manager + ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver(); + resolver.setViewResolvers(resolvers); + resolver.setContentNegotiationManager(manager); + return resolver; + } + + + public ViewResolver urlBasedViewResolver() { + UrlBasedViewResolver result = new InternalResourceViewResolver(); +// result.setPrefix("/WEB-INF/jsp/"); +// result.setSuffix(".jsp"); +// result.setOrder(0); + return result; + } + + + //@Bean(name="viewResolverJsp") + public InternalResourceViewResolver internalResourceViewResolverJsp() { + InternalResourceViewResolver result = new InternalResourceViewResolver(); + result.setPrefix("/WEB-INF/jsp/"); + result.setSuffix(".jsp"); + result.setViewClass(JstlView.class); +// result.setOrder(1); + return result; + } + + //@Bean(name="viewResolverHtml") + public InternalResourceViewResolver internalResourceViewResolverHtml() { + InternalResourceViewResolver result = new InternalResourceViewResolver(); + //result.setPrefix("/resources/app/"); + result.setPrefix(""); + result.setSuffix(".html"); +// result.setOrder(2); + return result; + } + +} diff --git a/linkedgeodata-core/src/main/resources/jdklog.properties b/linkedgeodata-core/src/main/resources/jdklog.properties deleted file mode 100644 index e69de29..0000000 diff --git a/linkedgeodata-core/src/main/resources/log4j.properties b/linkedgeodata-core/src/main/resources/log4j.properties index df45ceb..473a9e8 100644 --- a/linkedgeodata-core/src/main/resources/log4j.properties +++ b/linkedgeodata-core/src/main/resources/log4j.properties @@ -3,7 +3,7 @@ # stdout logging ############################################################################### log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.Target=System.out +log4j.appender.stdout.Target=System.err log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d [%t] %-5p %c: %m%n diff --git a/linkedgeodata-core/src/main/webapp/WEB-INF/web.xml b/linkedgeodata-core/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index b6d9c3f..0000000 --- a/linkedgeodata-core/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - Jersey Web Application - com.sun.jersey.spi.container.servlet.ServletContainer - - - com.sun.jersey.config.property.packages - org.linkedgeodata.rest - - - 1 - - - Jersey Web Application - /* - - diff --git a/linkedgeodata-core/src/main/java/org/linkedgeodata/rest/LinkedGeoDataApiMain.java b/linkedgeodata-trash/LinkedGeoDataApiMain.java similarity index 99% rename from linkedgeodata-core/src/main/java/org/linkedgeodata/rest/LinkedGeoDataApiMain.java rename to linkedgeodata-trash/LinkedGeoDataApiMain.java index a778945..b790476 100644 --- a/linkedgeodata-core/src/main/java/org/linkedgeodata/rest/LinkedGeoDataApiMain.java +++ b/linkedgeodata-trash/LinkedGeoDataApiMain.java @@ -1,4 +1,4 @@ -package org.linkedgeodata.rest; +package org.linkedgeodata.web.api; import java.io.FileInputStream; import java.util.logging.LogManager; diff --git a/pom.xml b/pom.xml index 426d6a1..d94907d 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ - + linkedgeodata-core linkedgeodata-debian @@ -47,9 +47,9 @@ 1.8 - 3.1.2.RELEASE + 3.2.4.RELEASE - 2.10.0-20 + 2.10.0-43 @@ -167,21 +167,65 @@ + + + + + + + + - org.aksw.sparqlify - sparqlify-core - 0.6.5-SNAPSHOT - jar - compile + org.aksw.jena-sparql-api + jena-sparql-api-server + ${jena-sparql-api.version} org.aksw.jena-sparql-api - jena-sparql-api-server + jena-sparql-api-servlets + ${jena-sparql-api.version} + + + + org.aksw.jena-sparql-api + jena-sparql-api-core + ${jena-sparql-api.version} + + + + org.aksw.jena-sparql-api + jena-sparql-api-cache-h2 ${jena-sparql-api.version} + org.springframework + spring-jdbc + ${spring.version} + + + commons-logging + commons-logging + + + + + + postgresql + postgresql + 8.4-701.jdbc4 + + + + + commons-cli + commons-cli + 1.2 + + + + org.openstreetmap.osmosis osmosis-core 0.43.1 @@ -193,7 +237,12 @@ com.google.code.gson gson 2.2.2 - compile + + + + commons-lang + commons-lang + 2.4