You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@marmotta.apache.org by ja...@apache.org on 2013/12/10 15:51:57 UTC

[3/3] git commit: MARMOTTA-259: Initial Implementation of Sparql ServiceDescription

MARMOTTA-259: Initial Implementation of Sparql ServiceDescription


Project: http://git-wip-us.apache.org/repos/asf/marmotta/repo
Commit: http://git-wip-us.apache.org/repos/asf/marmotta/commit/d2c2193d
Tree: http://git-wip-us.apache.org/repos/asf/marmotta/tree/d2c2193d
Diff: http://git-wip-us.apache.org/repos/asf/marmotta/diff/d2c2193d

Branch: refs/heads/develop
Commit: d2c2193dce6034cf9628062c8827970fdad1ed2f
Parents: 74bf1bf
Author: Jakob Frank <ja...@apache.org>
Authored: Tue Dec 10 15:48:01 2013 +0100
Committer: Jakob Frank <ja...@apache.org>
Committed: Tue Dec 10 15:48:01 2013 +0100

----------------------------------------------------------------------
 .../marmotta/commons/vocabulary/SPARQL_SD.java  | 345 +++++++++++++++++++
 .../sparql/api/sparql/SparqlService.java        |  16 +-
 .../services/sparql/SparqlServiceImpl.java      | 187 ++++++++--
 .../sparql/webservices/SparqlWebService.java    |  64 +++-
 4 files changed, 577 insertions(+), 35 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/marmotta/blob/d2c2193d/commons/marmotta-commons/src/main/java/org/apache/marmotta/commons/vocabulary/SPARQL_SD.java
----------------------------------------------------------------------
diff --git a/commons/marmotta-commons/src/main/java/org/apache/marmotta/commons/vocabulary/SPARQL_SD.java b/commons/marmotta-commons/src/main/java/org/apache/marmotta/commons/vocabulary/SPARQL_SD.java
new file mode 100644
index 0000000..a83efe4
--- /dev/null
+++ b/commons/marmotta-commons/src/main/java/org/apache/marmotta/commons/vocabulary/SPARQL_SD.java
@@ -0,0 +1,345 @@
+package org.apache.marmotta.commons.vocabulary;
+
+import org.openrdf.model.URI;
+import org.openrdf.model.ValueFactory;
+import org.openrdf.model.impl.ValueFactoryImpl;
+
+/**
+ * Namespace SPARQL_SD - SparqlServiceDescription.
+ * @see http://www.w3.org/TR/sparql11-service-description/
+ */
+public class SPARQL_SD {
+
+    public static final String NAMESPACE = "http://www.w3.org/ns/sparql-service-description#";
+
+    public static final String PREFIX = "sd";
+
+    /**
+     * An instance of sd:Aggregate represents an aggregate that may be used in a
+     * SPARQL aggregate query (for instance in a HAVING clause or SELECT
+     * expression) besides the standard list of supported aggregates COUNT, SUM,
+     * MIN, MAX, AVG, GROUP_CONCAT, and SAMPLE.
+     */
+    public static final URI Aggregate;
+
+    /**
+     * sd:BasicFederatedQuery, when used as the object of the sd:feature
+     * property, indicates that the SPARQL service supports basic federated
+     * query using the SERVICE keyword as defined by SPARQL 1.1 Federation
+     * Extensions.
+     */
+    public static final URI BasicFederatedQuery;
+
+    /**
+     * An instance of sd:Dataset represents a RDF Dataset comprised of a default
+     * graph and zero or more named graphs.
+     */
+    public static final URI Dataset;
+
+    /**
+     * sd:DereferencesURIs, when used as the object of the sd:feature property,
+     * indicates that a SPARQL service will dereference URIs used in FROM/FROM
+     * NAMED and USING/USING NAMED clauses and use the resulting RDF in the
+     * dataset during query evaluation.
+     */
+    public static final URI DereferencesURIs;
+
+    /**
+     * sd:EmptyGraphs, when used as the object of the sd:feature property,
+     * indicates that the underlying graph store supports empty graphs. A graph
+     * store that supports empty graphs MUST NOT remove graphs that are left
+     * empty after triples are removed from them.
+     */
+    public static final URI EmptyGraphs;
+
+    /**
+     * An instance of sd:EntailmentProfile represents a profile of an entailment
+     * regime. An entailment profile MAY impose restrictions on what constitutes
+     * valid RDF with respect to entailment.
+     */
+    public static final URI EntailmentProfile;
+
+    /**
+     * An instance of sd:EntailmentRegime represents an entailment regime used
+     * in basic graph pattern matching (as described by SPARQL 1.1 Query
+     * Language).
+     */
+    public static final URI EntailmentRegime;
+
+    /**
+     * An instance of sd:Feature represents a feature of a SPARQL service.
+     * Specific types of features include functions, aggregates, languages, and
+     * entailment regimes and profiles. This document defines five instances of
+     * sd:Feature: sd:DereferencesURIs, sd:UnionDefaultGraph,
+     * sd:RequiresDataset, sd:EmptyGraphs, and sd:BasicFederatedQuery.
+     */
+    public static final URI Feature;
+
+    /**
+     * An instance of sd:Function represents a function that may be used in a
+     * SPARQL SELECT expression or a FILTER, HAVING, GROUP BY, ORDER BY, or BIND
+     * clause.
+     */
+    public static final URI Function;
+
+    /**
+     * An instance of sd:Graph represents the description of an RDF graph.
+     */
+    public static final URI Graph;
+
+    /**
+     * An instance of sd:GraphCollection represents a collection of zero or more
+     * named graph descriptions. Each named graph description belonging to an
+     * sd:GraphCollection MUST be linked with the sd:namedGraph predicate.
+     */
+    public static final URI GraphCollection;
+
+    /**
+     * An instance of sd:Language represents one of the SPARQL languages,
+     * including specific configurations providing particular features or
+     * extensions. This document defines three instances of sd:Language:
+     * sd:SPARQL10Query, sd:SPARQL11Query, and sd:SPARQL11Update.
+     */
+    public static final URI Language;
+
+    /**
+     * An instance of sd:NamedGraph represents a named graph having a name (via
+     * sd:name) and an optional graph description (via sd:graph).
+     */
+    public static final URI NamedGraph;
+
+    /**
+     * sd:RequiresDataset, when used as the object of the sd:feature property,
+     * indicates that the SPARQL service requires an explicit dataset
+     * declaration (based on either FROM/FROM NAMED clauses in a query,
+     * USING/USING NAMED clauses in an update, or the appropriate SPARQL
+     * Protocol parameters).
+     */
+    public static final URI RequiresDataset;
+
+    /**
+     * sd:SPARQL10Query is an sd:Language representing the SPARQL 1.0 Query
+     * language.
+     */
+    public static final URI SPARQL10Query;
+
+    /**
+     * sd:SPARQL11Query is an sd:Language representing the SPARQL 1.1 Query
+     * language.
+     */
+    public static final URI SPARQL11Query;
+
+    /**
+     * sd:SPARQLUpdate is an sd:Language representing the SPARQL 1.1 Update
+     * language.
+     */
+    public static final URI SPARQL11Update;
+
+    /**
+     * An instance of sd:Service represents a SPARQL service made available via
+     * the SPARQL Protocol.
+     */
+    public static final URI Service;
+
+    /**
+     * sd:UnionDefaultGraph, when used as the object of the sd:feature property,
+     * indicates that the default graph of the dataset used during query and
+     * update evaluation (when an explicit dataset is not specified) is
+     * comprised of the union of all the named graphs in that dataset.
+     */
+    public static final URI UnionDefaultGraph;
+
+    /**
+     * Relates an instance of sd:Service to a description of the graphs which
+     * are allowed in the construction of a dataset either via the SPARQL
+     * Protocol, with FROM/FROM NAMED clauses in a query, or with USING/USING
+     * NAMED in an update request, if the service limits the scope of dataset
+     * construction.
+     */
+    public static final URI availableGraphs;
+
+    /**
+     * Relates an instance of sd:Service to a description of the default dataset
+     * available when no explicit dataset is specified in the query, update
+     * request or via protocol parameters.
+     */
+    public static final URI defaultDataset;
+
+    /**
+     * Relates an instance of sd:Service with a resource representing an
+     * entailment regime used for basic graph pattern matching. This property is
+     * intended for use when a single entailment regime by default applies to
+     * all graphs in the default dataset of the service. In situations where a
+     * different entailment regime applies to a specific graph in the dataset,
+     * the sd:entailmentRegime property should be used to indicate this fact in
+     * the description of that graph.
+     */
+    public static final URI defaultEntailmentRegime;
+
+    /**
+     * Relates an instance of sd:Dataset to the description of its default
+     * graph.
+     */
+    public static final URI defaultGraph;
+
+    /**
+     * Relates an instance of sd:Service with a resource representing a
+     * supported profile of the default entailment regime (as declared by
+     * sd:defaultEntailmentRegime).
+     */
+    public static final URI defaultSupportedEntailmentProfile;
+
+    /**
+     * The SPARQL endpoint of an sd:Service that implements the SPARQL Protocol
+     * service. The object of the sd:endpoint property is an IRI.
+     */
+    public static final URI endpoint;
+
+    /**
+     * Relates a named graph description with a resource representing an
+     * entailment regime used for basic graph pattern matching over that graph.
+     */
+    public static final URI entailmentRegime;
+
+    /**
+     * Relates an instance of sd:Service to an aggregate that may be used in a
+     * SPARQL aggregate query (for instance in a HAVING clause or SELECT
+     * expression) besides the standard list of supported aggregates COUNT, SUM,
+     * MIN, MAX, AVG, GROUP_CONCAT, and SAMPLE
+     */
+    public static final URI extensionAggregate;
+
+    /**
+     * Relates an instance of sd:Service to a function that may be used in a
+     * SPARQL SELECT expression or a FILTER, HAVING, GROUP BY, ORDER BY, or BIND
+     * clause.
+     */
+    public static final URI extensionFunction;
+
+    /**
+     * Relates an instance of sd:Service with a resource representing a
+     * supported feature.
+     */
+    public static final URI feature;
+
+    /**
+     * Relates a named graph to its graph description.
+     */
+    public static final URI graph;
+
+    /**
+     * Relates an instance of sd:Service to a format that is supported for
+     * parsing RDF input; for example, via a SPARQL 1.1 Update LOAD statement,
+     * or when URIs are dereferenced in FROM/FROM NAMED/USING/USING NAMED
+     * clauses.
+     */
+    public static final URI inputFormat;
+
+    /**
+     * Relates an instance of sd:Service to a resource representing an
+     * implemented extension to the SPARQL Query or Update language.
+     */
+    public static final URI languageExtension;
+
+    /**
+     * Relates a named graph to the name by which it may be referenced in a
+     * FROM/FROM NAMED clause. The object of the sd:name property is an IRI.
+     */
+    public static final URI name;
+
+    /**
+     * Relates an instance of sd:GraphCollection (or its subclass sd:Dataset) to
+     * the description of one of its named graphs. The description of such a
+     * named graph MUST include the sd:name property and MAY include the
+     * sd:graph property.
+     */
+    public static final URI namedGraph;
+
+    /**
+     * Relates an instance of sd:Service to a resource representing an
+     * implemented feature that extends the SPARQL Query or Update language and
+     * that is accessed by using the named property.
+     */
+    public static final URI propertyFeature;
+
+    /**
+     * Relates an instance of sd:Service to a format that is supported for
+     * serializing query results.
+     */
+    public static final URI resultFormat;
+
+    /**
+     * Relates a named graph description with a resource representing a
+     * supported profile of the entailment regime (as declared by
+     * sd:entailmentRegime) used for basic graph pattern matching over that
+     * graph.
+     */
+    public static final URI supportedEntailmentProfile;
+
+    /**
+     * Relates an instance of sd:Service to a SPARQL language (e.g. Query and
+     * Update) that it implements.
+     */
+    public static final URI supportedLanguage;
+
+    static {
+        ValueFactory factory = ValueFactoryImpl.getInstance();
+        Aggregate = factory.createURI(SPARQL_SD.NAMESPACE, "Aggregate");
+        BasicFederatedQuery = factory.createURI(SPARQL_SD.NAMESPACE,
+                "BasicFederatedQuery");
+        Dataset = factory.createURI(SPARQL_SD.NAMESPACE, "Dataset");
+        DereferencesURIs = factory.createURI(SPARQL_SD.NAMESPACE,
+                "DereferencesURIs");
+        EmptyGraphs = factory.createURI(SPARQL_SD.NAMESPACE, "EmptyGraphs");
+        EntailmentProfile = factory.createURI(SPARQL_SD.NAMESPACE,
+                "EntailmentProfile");
+        EntailmentRegime = factory.createURI(SPARQL_SD.NAMESPACE,
+                "EntailmentRegime");
+        Feature = factory.createURI(SPARQL_SD.NAMESPACE, "Feature");
+        Function = factory.createURI(SPARQL_SD.NAMESPACE, "Function");
+        Graph = factory.createURI(SPARQL_SD.NAMESPACE, "Graph");
+        GraphCollection = factory.createURI(SPARQL_SD.NAMESPACE,
+                "GraphCollection");
+        Language = factory.createURI(SPARQL_SD.NAMESPACE, "Language");
+        NamedGraph = factory.createURI(SPARQL_SD.NAMESPACE, "NamedGraph");
+        RequiresDataset = factory.createURI(SPARQL_SD.NAMESPACE,
+                "RequiresDataset");
+        SPARQL10Query = factory.createURI(SPARQL_SD.NAMESPACE, "SPARQL10Query");
+        SPARQL11Query = factory.createURI(SPARQL_SD.NAMESPACE, "SPARQL11Query");
+        SPARQL11Update = factory.createURI(SPARQL_SD.NAMESPACE,
+                "SPARQL11Update");
+        Service = factory.createURI(SPARQL_SD.NAMESPACE, "Service");
+        UnionDefaultGraph = factory.createURI(SPARQL_SD.NAMESPACE,
+                "UnionDefaultGraph");
+        availableGraphs = factory.createURI(SPARQL_SD.NAMESPACE,
+                "availableGraphs");
+        defaultDataset = factory.createURI(SPARQL_SD.NAMESPACE,
+                "defaultDataset");
+        defaultEntailmentRegime = factory.createURI(SPARQL_SD.NAMESPACE,
+                "defaultEntailmentRegime");
+        defaultGraph = factory.createURI(SPARQL_SD.NAMESPACE, "defaultGraph");
+        defaultSupportedEntailmentProfile = factory.createURI(
+                SPARQL_SD.NAMESPACE, "defaultSupportedEntailmentProfile");
+        endpoint = factory.createURI(SPARQL_SD.NAMESPACE, "endpoint");
+        entailmentRegime = factory.createURI(SPARQL_SD.NAMESPACE,
+                "entailmentRegime");
+        extensionAggregate = factory.createURI(SPARQL_SD.NAMESPACE,
+                "extensionAggregate");
+        extensionFunction = factory.createURI(SPARQL_SD.NAMESPACE,
+                "extensionFunction");
+        feature = factory.createURI(SPARQL_SD.NAMESPACE, "feature");
+        graph = factory.createURI(SPARQL_SD.NAMESPACE, "graph");
+        inputFormat = factory.createURI(SPARQL_SD.NAMESPACE, "inputFormat");
+        languageExtension = factory.createURI(SPARQL_SD.NAMESPACE,
+                "languageExtension");
+        name = factory.createURI(SPARQL_SD.NAMESPACE, "name");
+        namedGraph = factory.createURI(SPARQL_SD.NAMESPACE, "namedGraph");
+        propertyFeature = factory.createURI(SPARQL_SD.NAMESPACE,
+                "propertyFeature");
+        resultFormat = factory.createURI(SPARQL_SD.NAMESPACE, "resultFormat");
+        supportedEntailmentProfile = factory.createURI(SPARQL_SD.NAMESPACE,
+                "supportedEntailmentProfile");
+        supportedLanguage = factory.createURI(SPARQL_SD.NAMESPACE,
+                "supportedLanguage");
+    }
+}

http://git-wip-us.apache.org/repos/asf/marmotta/blob/d2c2193d/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/api/sparql/SparqlService.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/api/sparql/SparqlService.java b/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/api/sparql/SparqlService.java
index 67984eb..d6bda04 100644
--- a/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/api/sparql/SparqlService.java
+++ b/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/api/sparql/SparqlService.java
@@ -35,7 +35,8 @@ import org.openrdf.query.resultio.BooleanQueryResultWriter;
 import org.openrdf.query.resultio.QueryResultWriter;
 import org.openrdf.query.resultio.TupleQueryResultWriter;
 import org.openrdf.repository.RepositoryException;
-import org.openrdf.rio.RDFHandler;
+import org.openrdf.rio.RDFHandlerException;
+import org.openrdf.rio.RDFWriter;
 
 /**
  * Add file description here!
@@ -140,5 +141,18 @@ public interface SparqlService {
      */
     @Deprecated
     void query(QueryLanguage queryLanguage, String query, QueryResultWriter writer, int timeoutInSeconds) throws MarmottaException, MalformedQueryException, QueryEvaluationException, TimeoutException;
+
+    /**
+     * Write a SparqlServiceDescription of the Service to the provided {@link RDFWriter}.
+     * 
+     * @param writer the {@link RDFWriter} to write the description to
+     * @param string the URI of the SPARQL Endpoint
+     * @param isUpdate if the endpoint is a update or select/query endpoint
+     * 
+     * @see http://www.w3.org/TR/sparql11-service-description/
+     */
+    void createServiceDescription(RDFWriter writer, String string, boolean isUpdate) throws RDFHandlerException;
+    
+    
     
 }

http://git-wip-us.apache.org/repos/asf/marmotta/blob/d2c2193d/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/services/sparql/SparqlServiceImpl.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/services/sparql/SparqlServiceImpl.java b/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/services/sparql/SparqlServiceImpl.java
index bdefc8b..c3dd7b1 100644
--- a/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/services/sparql/SparqlServiceImpl.java
+++ b/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/services/sparql/SparqlServiceImpl.java
@@ -17,12 +17,16 @@
  */
 package org.apache.marmotta.platform.sparql.services.sparql;
 
+import info.aduna.lang.FileFormat;
+
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
@@ -36,6 +40,8 @@ import javax.annotation.PostConstruct;
 import javax.enterprise.context.ApplicationScoped;
 import javax.inject.Inject;
 
+import org.apache.commons.lang3.StringUtils;
+import org.apache.marmotta.commons.vocabulary.SPARQL_SD;
 import org.apache.marmotta.platform.core.api.config.ConfigurationService;
 import org.apache.marmotta.platform.core.api.templating.TemplatingService;
 import org.apache.marmotta.platform.core.api.triplestore.SesameService;
@@ -44,10 +50,15 @@ import org.apache.marmotta.platform.core.exception.MarmottaException;
 import org.apache.marmotta.platform.sparql.api.sparql.QueryType;
 import org.apache.marmotta.platform.sparql.api.sparql.SparqlService;
 import org.apache.marmotta.platform.sparql.services.sparqlio.rdf.SPARQLGraphResultWriter;
-import org.apache.marmotta.platform.sparql.services.sparqlio.sparqlhtml.SPARQLResultsHTMLFormat;
 import org.apache.marmotta.platform.sparql.services.sparqlio.sparqlhtml.SPARQLHTMLSettings;
 import org.apache.marmotta.platform.sparql.webservices.SparqlWebService;
+import org.openrdf.model.BNode;
+import org.openrdf.model.Resource;
+import org.openrdf.model.URI;
 import org.openrdf.model.Value;
+import org.openrdf.model.ValueFactory;
+import org.openrdf.model.impl.ValueFactoryImpl;
+import org.openrdf.model.vocabulary.RDF;
 import org.openrdf.query.Binding;
 import org.openrdf.query.BindingSet;
 import org.openrdf.query.BooleanQuery;
@@ -70,17 +81,24 @@ import org.openrdf.query.parser.QueryParser;
 import org.openrdf.query.parser.QueryParserUtil;
 import org.openrdf.query.resultio.BooleanQueryResultFormat;
 import org.openrdf.query.resultio.BooleanQueryResultWriter;
+import org.openrdf.query.resultio.QueryResultFormat;
 import org.openrdf.query.resultio.QueryResultIO;
 import org.openrdf.query.resultio.QueryResultWriter;
 import org.openrdf.query.resultio.TupleQueryResultFormat;
 import org.openrdf.query.resultio.TupleQueryResultWriter;
+import org.openrdf.repository.Repository;
 import org.openrdf.repository.RepositoryConnection;
 import org.openrdf.repository.RepositoryException;
+import org.openrdf.repository.RepositoryResult;
+import org.openrdf.repository.sail.SailRepository;
+import org.openrdf.repository.sail.SailRepositoryConnection;
 import org.openrdf.rio.RDFFormat;
-import org.openrdf.rio.RDFHandler;
 import org.openrdf.rio.RDFHandlerException;
+import org.openrdf.rio.RDFWriter;
+import org.openrdf.rio.RDFWriterRegistry;
 import org.openrdf.rio.Rio;
 import org.openrdf.rio.UnsupportedRDFormatException;
+import org.openrdf.sail.memory.MemoryStore;
 import org.slf4j.Logger;
 
 /**
@@ -93,6 +111,28 @@ import org.slf4j.Logger;
 public class SparqlServiceImpl implements SparqlService {
 
     /**
+     * @deprecated beginning with Sesame 2.8, use {@link RDFFormat#getStandardURI()} or {@link QueryResultFormat#etStandardURI()}
+     */
+    @Deprecated
+    private static final Map<FileFormat, String> w3cFormatID = new HashMap<FileFormat, String>() {{
+        put(RDFFormat.JSONLD, "http://www.w3.org/ns/formats/JSON-LD");
+        put(RDFFormat.N3, "http://www.w3.org/ns/formats/N3");
+        put(RDFFormat.NTRIPLES, "http://www.w3.org/ns/formats/N-Triples");
+        put(RDFFormat.NQUADS, "http://www.w3.org/ns/formats/N-Quads");
+        put(RDFFormat.RDFA, "http://www.w3.org/ns/formats/RDFa");
+        put(RDFFormat.RDFJSON, "http://www.w3.org/ns/formats/RDF_JSON");
+        put(RDFFormat.RDFXML, "http://www.w3.org/ns/formats/RDF_XML");
+        put(RDFFormat.TURTLE, "http://www.w3.org/ns/formats/Turtle");
+        put(RDFFormat.TRIG, "http://www.w3.org/ns/formats/TriG");
+
+        put(TupleQueryResultFormat.CSV, "http://www.w3.org/ns/formats/SPARQL_Results_CSV");
+        put(TupleQueryResultFormat.JSON, "http://www.w3.org/ns/formats/SPARQL_Results_JSON");
+        put(TupleQueryResultFormat.TSV, "http://www.w3.org/ns/formats/SPARQL_Results_TSV");
+        put(TupleQueryResultFormat.SPARQL, "http://www.w3.org/ns/formats/SPARQL_Results_XML");
+    }};
+
+
+    /**
      * Get the seam logger for issuing logging statements.
      */
     @Inject
@@ -134,17 +174,17 @@ public class SparqlServiceImpl implements SparqlService {
         }
         return sparqlQuery;
     }
-    
+
     @Override
     public QueryType getQueryType(QueryLanguage language, String query) throws MalformedQueryException {
-    	QueryParser parser = QueryParserUtil.createParser(language); 
-    	ParsedQuery parsedQuery = parser.parseQuery(query, configurationService.getServerUri() + SparqlWebService.PATH + "/" + SparqlWebService.SELECT);
+        QueryParser parser = QueryParserUtil.createParser(language); 
+        ParsedQuery parsedQuery = parser.parseQuery(query, configurationService.getServerUri() + SparqlWebService.PATH + "/" + SparqlWebService.SELECT);
         if (parsedQuery instanceof ParsedTupleQuery) {
             return QueryType.TUPLE;
         } else if (parsedQuery instanceof ParsedBooleanQuery) {
-        	return QueryType.BOOL;
+            return QueryType.BOOL;
         } else if (parsedQuery instanceof ParsedGraphQuery) {
-        	return QueryType.GRAPH;
+            return QueryType.GRAPH;
         } else {
             return null;
         }
@@ -215,7 +255,7 @@ public class SparqlServiceImpl implements SparqlService {
             }
         }
     }
-    
+
     @Override
     @Deprecated
     public void query(final QueryLanguage queryLanguage, final String query, final QueryResultWriter writer, final int timeoutInSeconds) throws MarmottaException, MalformedQueryException, QueryEvaluationException, TimeoutException {
@@ -226,29 +266,29 @@ public class SparqlServiceImpl implements SparqlService {
             public Boolean call() throws Exception {
                 long start = System.currentTimeMillis();
                 try {
-	                RepositoryConnection connection = sesameService.getConnection();
-	                try {
-	                    connection.begin();
-	                    Query sparqlQuery = connection.prepareQuery(queryLanguage, query);
-	
-	                    if (sparqlQuery instanceof TupleQuery) {
-	                        query((TupleQuery) sparqlQuery, (TupleQueryResultWriter)writer);
-	                    } else if (sparqlQuery instanceof BooleanQuery) {
-	                        query((BooleanQuery) sparqlQuery, (BooleanQueryResultWriter)writer);
-	                    } else if (sparqlQuery instanceof GraphQuery) {
-	                        query((GraphQuery) sparqlQuery, ((SPARQLGraphResultWriter)writer).getOutputStream(), ((SPARQLGraphResultWriter)writer).getFormat());
-	                    } else {
-	                        connection.rollback();
-	                        throw new InvalidArgumentException("SPARQL query type " + sparqlQuery.getClass() + " not supported!");
-	                    }
-	
-	                    connection.commit();
-	                } catch (Exception ex) {
-	                    connection.rollback();
-	                    throw ex;
-	                } finally {
-	                    connection.close();
-	                }
+                    RepositoryConnection connection = sesameService.getConnection();
+                    try {
+                        connection.begin();
+                        Query sparqlQuery = connection.prepareQuery(queryLanguage, query);
+
+                        if (sparqlQuery instanceof TupleQuery) {
+                            query((TupleQuery) sparqlQuery, (TupleQueryResultWriter)writer);
+                        } else if (sparqlQuery instanceof BooleanQuery) {
+                            query((BooleanQuery) sparqlQuery, (BooleanQueryResultWriter)writer);
+                        } else if (sparqlQuery instanceof GraphQuery) {
+                            query((GraphQuery) sparqlQuery, ((SPARQLGraphResultWriter)writer).getOutputStream(), ((SPARQLGraphResultWriter)writer).getFormat());
+                        } else {
+                            connection.rollback();
+                            throw new InvalidArgumentException("SPARQL query type " + sparqlQuery.getClass() + " not supported!");
+                        }
+
+                        connection.commit();
+                    } catch (Exception ex) {
+                        connection.rollback();
+                        throw ex;
+                    } finally {
+                        connection.close();
+                    }
                 } catch(RepositoryException e) {
                     log.error("error while getting repository connection: {}", e);
                     throw new MarmottaException("error while getting repository connection", e);
@@ -281,7 +321,7 @@ public class SparqlServiceImpl implements SparqlService {
         }    	
     }
 
-	@Override
+    @Override
     public void query(final QueryLanguage language, final String query, final OutputStream output, final String format, int timeoutInSeconds) throws MarmottaException, TimeoutException, MalformedQueryException {
         log.debug("executing SPARQL query:\n{}", query);
         Future<Boolean> future = executorService.submit(new Callable<Boolean>() {
@@ -510,6 +550,89 @@ public class SparqlServiceImpl implements SparqlService {
         return result;
     }
 
+    @Override
+    public void createServiceDescription(RDFWriter writer, String requestURL, boolean isUpdate) throws RDFHandlerException {
+        try {
+            writer.startRDF();
+            final ValueFactory vf = new ValueFactoryImpl();
+            writer.handleNamespace(SPARQL_SD.PREFIX, SPARQL_SD.NAMESPACE);
+            writer.handleNamespace("formats", "http://www.w3.org/ns/formats/");
+            writer.handleNamespace("void", "http://rdfs.org/ns/void#");
+
+            final BNode sd = vf.createBNode();
+            writer.handleStatement(vf.createStatement(sd, RDF.TYPE, SPARQL_SD.Service));
+            writer.handleStatement(vf.createStatement(sd, SPARQL_SD.endpoint, vf.createURI(requestURL)));
+            writer.handleStatement(vf.createStatement(sd, SPARQL_SD.supportedLanguage, isUpdate?SPARQL_SD.SPARQL11Update:SPARQL_SD.SPARQL11Query));
+
+            if (!isUpdate) {
+                // FIXME: really? these types?
+                final Set<FileFormat> formats = new HashSet<>();
+                formats.addAll(RDFWriterRegistry.getInstance().getKeys());
+                formats.addAll(TupleQueryResultFormat.values());
+                for (FileFormat f: formats) {
+                    final String formatUri = w3cFormatID.get(f);
+                    if (StringUtils.isNotBlank(formatUri)) {
+                        writer.handleStatement(vf.createStatement(sd, SPARQL_SD.resultFormat, vf.createURI(formatUri)));
+                    } else {
+                        final BNode fNode = vf.createBNode();
+                        writer.handleStatement(vf.createStatement(sd, SPARQL_SD.resultFormat, fNode));
+                        writer.handleStatement(vf.createStatement(fNode, RDF.TYPE, vf.createURI("http://www.w3.org/ns/formats/Format")));
+                        writer.handleStatement(vf.createStatement(fNode, vf.createURI("http://www.w3.org/ns/formats/media_type"), vf.createLiteral(f.getDefaultMIMEType())));
+                        writer.handleStatement(vf.createStatement(fNode, vf.createURI("http://www.w3.org/ns/formats/preferred_suffix"), vf.createLiteral("."+f.getDefaultFileExtension())));
+                    }
+                }
+            }
+
+            final BNode dataset = vf.createBNode();
+            writer.handleStatement(vf.createStatement(sd, SPARQL_SD.defaultDataset, dataset));
+            writer.handleStatement(vf.createStatement(dataset, RDF.TYPE, SPARQL_SD.Dataset));
+
+            final RepositoryConnection kiwiCon = sesameService.getConnection();
+            try {
+                kiwiCon.begin();
+                // FIXME: Default graph, in KiWi this is all - is it not?
+                final BNode defaultGraph = vf.createBNode();
+                writer.handleStatement(vf.createStatement(dataset, SPARQL_SD.defaultGraph, defaultGraph));
+                writer.handleStatement(vf.createStatement(defaultGraph, RDF.TYPE, SPARQL_SD.Graph));
+                // TODO: Number of triples here? This can be expensive!
+                writer.handleStatement(vf.createStatement(defaultGraph, vf.createURI("http://rdfs.org/ns/void#triples"), vf.createLiteral(kiwiCon.size())));
+
+                final RepositoryResult<Resource> cID = kiwiCon.getContextIDs();
+                try {
+                    while (cID.hasNext()) {
+                        final Resource c = cID.next();
+                        if (c instanceof URI) {
+                            // A named graph
+                            final BNode ng = vf.createBNode();
+                            writer.handleStatement(vf.createStatement(dataset, SPARQL_SD.namedGraph, ng));
+                            writer.handleStatement(vf.createStatement(ng, RDF.TYPE, SPARQL_SD.NamedGraph));
+                            writer.handleStatement(vf.createStatement(ng, SPARQL_SD.name, c));
+                            final BNode g = vf.createBNode();
+                            writer.handleStatement(vf.createStatement(ng, SPARQL_SD.graph, g));
+                            writer.handleStatement(vf.createStatement(g, RDF.TYPE, SPARQL_SD.Graph));
+                            // TODO: Number of triples here? This can be expensive!
+                            writer.handleStatement(vf.createStatement(g, vf.createURI("http://rdfs.org/ns/void#triples"), vf.createLiteral(kiwiCon.size(c))));
+
+                        }
+                    }
+                } finally {
+                    cID.close();
+                }
+
+                kiwiCon.commit();
+            } catch (final Throwable t){
+                kiwiCon.rollback();
+                throw t;
+            } finally {
+                kiwiCon.close();
+            } 
+
+            writer.endRDF();
+        } catch (RepositoryException e) {
+            throw new RDFHandlerException("Could not build SparqlServiceDescription");
+        }
+    }
+
     private TupleQueryResultWriter getTupleResultWriter(String format, OutputStream os) {
         TupleQueryResultFormat resultFormat;
         if(format == null) {

http://git-wip-us.apache.org/repos/asf/marmotta/blob/d2c2193d/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/webservices/SparqlWebService.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/webservices/SparqlWebService.java b/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/webservices/SparqlWebService.java
index 974ef7f..f1e8084 100644
--- a/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/webservices/SparqlWebService.java
+++ b/platform/marmotta-sparql/src/main/java/org/apache/marmotta/platform/sparql/webservices/SparqlWebService.java
@@ -17,12 +17,15 @@
  */
 package org.apache.marmotta.platform.sparql.webservices;
 
+import static org.openrdf.rio.RDFFormat.RDFXML;
+
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URLDecoder;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -43,8 +46,10 @@ import javax.ws.rs.Path;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.ResponseBuilder;
+import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.core.StreamingOutput;
 import javax.ws.rs.core.UriBuilder;
 
@@ -59,6 +64,7 @@ import org.apache.marmotta.platform.core.exception.MarmottaException;
 import org.apache.marmotta.platform.core.util.WebServiceUtil;
 import org.apache.marmotta.platform.sparql.api.sparql.QueryType;
 import org.apache.marmotta.platform.sparql.api.sparql.SparqlService;
+import org.jboss.resteasy.spi.NoLogWebApplicationException;
 import org.openrdf.query.MalformedQueryException;
 import org.openrdf.query.QueryLanguage;
 import org.openrdf.query.UpdateExecutionException;
@@ -66,6 +72,10 @@ import org.openrdf.query.resultio.BooleanQueryResultWriterRegistry;
 import org.openrdf.query.resultio.QueryResultIO;
 import org.openrdf.query.resultio.TupleQueryResultFormat;
 import org.openrdf.query.resultio.TupleQueryResultWriterRegistry;
+import org.openrdf.rio.RDFFormat;
+import org.openrdf.rio.RDFHandlerException;
+import org.openrdf.rio.RDFWriter;
+import org.openrdf.rio.Rio;
 import org.slf4j.Logger;
 
 import com.google.common.collect.Lists;
@@ -75,7 +85,8 @@ import com.google.common.io.CharStreams;
  * Execute SPARQL query (both query and update) on the LMF triple store
  * according the SPARQL 1.1 Protocol
  * 
- * @link http://www.w3.org/TR/sparql11-protocol/
+ * @see http://www.w3.org/TR/sparql11-protocol/
+ * @see http://www.w3.org/TR/sparql11-service-description/
  * 
  * @author Sebastian Schaffert
  * @author Sergio Fernández
@@ -168,7 +179,10 @@ public class SparqlWebService {
      */
     @GET
     @Path(SELECT)
-    public Response selectGet(@QueryParam("query") String query, @QueryParam("output") String resultType, @Context HttpServletRequest request) {  
+    public Response selectGet(@QueryParam("query") String query, @QueryParam("output") String resultType, @Context HttpServletRequest request) {
+        if (StringUtils.isBlank(query)) {
+            return createServiceDescriptionResponse(request, false);
+        }
     	//get real return type: even it is not in the standard, this is useful
         if(resultType != null && outputMapper.containsKey(resultType)) resultType = outputMapper.get(resultType);
         return select(query, resultType, request);
@@ -340,6 +354,9 @@ public class SparqlWebService {
     @Path(UPDATE)
     public Response updateGet(@QueryParam("update") String update, @QueryParam("query") String query, @QueryParam("output") String resultType, @Context HttpServletRequest request) {
     	String q = getUpdateQuery(update, query);
+    	if (StringUtils.isBlank(q)) {
+    	    return createServiceDescriptionResponse(request, true);
+    	}
         return update(q, resultType, request);
     }
     
@@ -474,6 +491,49 @@ public class SparqlWebService {
 		return params;
 	}
     
+    private Response createServiceDescriptionResponse(final HttpServletRequest request, final boolean isUpdate) {
+        final List<ContentType> acceptedTypes;
+        if (StringUtils.isBlank(request.getHeader("Accept"))) {
+            acceptedTypes = Collections.singletonList(MarmottaHttpUtils.parseContentType(RDFXML.getDefaultMIMEType()));
+        } else {
+            acceptedTypes = MarmottaHttpUtils.parseAcceptHeader(request.getHeader("Accept"));
+        }
+        
+        ContentType _bestType = null;
+        RDFFormat _format = null;
+        for (ContentType ct : acceptedTypes) {
+            final RDFFormat f = Rio.getWriterFormatForMIMEType(ct.getMime());
+            if (f != null) {
+                _bestType = ct;
+                _format = f;
+                break;
+            }
+        }
+        if (_bestType == null || _format == null) {
+            // FIXME: todo
+            return Response.status(Status.BAD_REQUEST).entity("Could not determine Format").build();
+        }
+        
+        final RDFFormat format = _format;
+        final ContentType returnType = _bestType;
+        
+        final StreamingOutput entity = new StreamingOutput() {
+            @Override
+            public void write(OutputStream outputStream) throws IOException,
+                    WebApplicationException {
+                try {
+                    final RDFWriter writer = Rio.createWriter(format, outputStream);
+                    sparqlService.createServiceDescription(writer, request.getRequestURL().toString(), isUpdate);
+                } catch (RDFHandlerException e) {
+                    log.warn("Could not send SpaqlServiceDescription: {}", e);
+                    throw new NoLogWebApplicationException(e, Response.serverError().entity(e).build());
+                }
+            }
+        };
+
+        return Response.ok(entity, new MediaType(returnType.getType(), returnType.getSubtype(), returnType.getCharset().name())).build();
+    }
+    
 	private Response buildQueryResponse(final ContentType format, final String query, final QueryType queryType) throws Exception {		
         StreamingOutput entity = new StreamingOutput() {
             @Override