diff --git a/pom.xml b/pom.xml
index 09a004f..f64f84d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,13 +3,12 @@
4.0.0
LDF-Server
LDF-Server
- 0.0.1
+ 0.0.2
war
- 9.2.5.v20141112
+ 9.3.6.v20151106
-
org.rdfhdt
@@ -31,10 +30,10 @@
httpclient
4.3.5
-
+
com.google.code.gson
gson
- 2.3
+ 2.5
javax.servlet
@@ -55,7 +54,7 @@
commons-cli
commons-cli
- 1.2
+ 1.3.1
org.apache.commons
@@ -116,4 +115,4 @@
-
\ No newline at end of file
+
diff --git a/src/org/linkeddatafragments/config/ConfigReader.java b/src/org/linkeddatafragments/config/ConfigReader.java
index 23aff12..fb982d9 100644
--- a/src/org/linkeddatafragments/config/ConfigReader.java
+++ b/src/org/linkeddatafragments/config/ConfigReader.java
@@ -15,9 +15,8 @@
* @author Ruben Verborgh
*/
public class ConfigReader {
-
- private final Map dataSources = new HashMap();
- private final Map prefixes = new HashMap();
+ private final Map dataSources = new HashMap<>();
+ private final Map prefixes = new HashMap<>();
/**
* Creates a new configuration reader.
@@ -25,12 +24,12 @@ public class ConfigReader {
* @param configReader the configuration
*/
public ConfigReader(Reader configReader) {
- final JsonObject root = new JsonParser().parse(configReader).getAsJsonObject();
- for (final Entry entry : root.getAsJsonObject("datasources").entrySet()) {
- final JsonObject dataSource = entry.getValue().getAsJsonObject();
+ JsonObject root = new JsonParser().parse(configReader).getAsJsonObject();
+ for (Entry entry : root.getAsJsonObject("datasources").entrySet()) {
+ JsonObject dataSource = entry.getValue().getAsJsonObject();
this.dataSources.put(entry.getKey(), dataSource);
}
- for (final Entry entry : root.getAsJsonObject("prefixes").entrySet()) {
+ for (Entry entry : root.getAsJsonObject("prefixes").entrySet()) {
this.prefixes.put(entry.getKey(), entry.getValue().getAsString());
}
}
diff --git a/src/org/linkeddatafragments/datasource/HdtDataSource.java b/src/org/linkeddatafragments/datasource/HdtDataSource.java
index e1acf17..f40c302 100644
--- a/src/org/linkeddatafragments/datasource/HdtDataSource.java
+++ b/src/org/linkeddatafragments/datasource/HdtDataSource.java
@@ -49,53 +49,61 @@ public TriplePatternFragment getFragment(Resource subject, Property predicate, R
throw new IllegalArgumentException("limit");
}
- // look up the result from the HDT datasource
- final int subjectId = subject == null ? 0 : dictionary.getIntID(subject.asNode(), TripleComponentRole.SUBJECT);
- final int predicateId = predicate == null ? 0 : dictionary.getIntID(predicate.asNode(), TripleComponentRole.PREDICATE);
- final int objectId = object == null ? 0 : dictionary.getIntID(object.asNode(), TripleComponentRole.OBJECT);
+ // look up the result from the HDT datasource)
+ int subjectId = subject == null ? 0 : dictionary.getIntID(subject.asNode(), TripleComponentRole.SUBJECT);
+ int predicateId = predicate == null ? 0 : dictionary.getIntID(predicate.asNode(), TripleComponentRole.PREDICATE);
+ int objectId = object == null ? 0 : dictionary.getIntID(object.asNode(), TripleComponentRole.OBJECT);
+
if (subjectId < 0 || predicateId < 0 || objectId < 0) {
return new TriplePatternFragmentBase();
}
+
final Model triples = ModelFactory.createDefaultModel();
- final IteratorTripleID matches = datasource.getTriples().search(new TripleID(subjectId, predicateId, objectId));
- final boolean hasMatches = matches.hasNext();
+ IteratorTripleID matches = datasource.getTriples().search(new TripleID(subjectId, predicateId, objectId));
+ boolean hasMatches = matches.hasNext();
- if (hasMatches) {
- // try to jump directly to the offset
- boolean atOffset;
- if (matches.canGoTo()) {
- try {
- matches.goTo(offset);
- atOffset = true;
- }
- // if the offset is outside the bounds, this page has no matches
- catch (IndexOutOfBoundsException exception) { atOffset = false; }
- }
- // if not possible, advance to the offset iteratively
- else {
- matches.goToStart();
- for (int i = 0; !(atOffset = i == offset) && matches.hasNext(); i++)
- matches.next();
- }
- // try to add `limit` triples to the result model
- if (atOffset) {
- for (int i = 0; i < limit && matches.hasNext(); i++)
- triples.add(triples.asStatement(toTriple(matches.next())));
- }
- }
-
- // estimates can be wrong; ensure 0 is returned if there are no results, and always more than actual results
- final long estimatedTotal = triples.size() > 0 ? Math.max(offset + triples.size() + 1, matches.estimatedNumResults())
- : hasMatches ? Math.max(matches.estimatedNumResults(), 1) : 0;
+ if (hasMatches) {
+ // try to jump directly to the offset
+ boolean atOffset;
+ if (matches.canGoTo()) {
+ try {
+ matches.goTo(offset);
+ atOffset = true;
+ } // if the offset is outside the bounds, this page has no matches
+ catch (IndexOutOfBoundsException exception) {
+ atOffset = false;
+ }
+ } // if not possible, advance to the offset iteratively
+ else {
+ matches.goToStart();
+ for (int i = 0; !(atOffset = i == offset) && matches.hasNext(); i++) {
+ matches.next();
+ }
+ }
+ // try to add `limit` triples to the result model
+ if (atOffset) {
+ for (int i = 0; i < limit && matches.hasNext(); i++) {
+ triples.add(triples.asStatement(toTriple(matches.next())));
+ }
+ }
+ }
+
+ // estimates can be wrong; ensure 0 is returned if there are no results, and always more than actual results
+ final long estimatedTotal = triples.size() > 0 ? Math.max(offset + triples.size() + 1, matches.estimatedNumResults())
+ : hasMatches ? Math.max(matches.estimatedNumResults(), 1) : 0;
// create the fragment
return new TriplePatternFragment() {
- @Override
- public Model getTriples() { return triples; }
-
- @Override
- public long getTotalSize() { return estimatedTotal; }
- };
+ @Override
+ public Model getTriples() {
+ return triples;
+ }
+
+ @Override
+ public long getTotalSize() {
+ return estimatedTotal;
+ }
+ };
}
/**
@@ -106,9 +114,9 @@ public TriplePatternFragment getFragment(Resource subject, Property predicate, R
*/
private Triple toTriple(TripleID tripleId) {
return new Triple(
- dictionary.getNode(tripleId.getSubject(), TripleComponentRole.SUBJECT),
- dictionary.getNode(tripleId.getPredicate(), TripleComponentRole.PREDICATE),
- dictionary.getNode(tripleId.getObject(), TripleComponentRole.OBJECT)
+ dictionary.getNode(tripleId.getSubject(), TripleComponentRole.SUBJECT),
+ dictionary.getNode(tripleId.getPredicate(), TripleComponentRole.PREDICATE),
+ dictionary.getNode(tripleId.getObject(), TripleComponentRole.OBJECT)
);
}
}
diff --git a/src/org/linkeddatafragments/datasource/IDataSource.java b/src/org/linkeddatafragments/datasource/IDataSource.java
index 47cc180..2b5a24d 100644
--- a/src/org/linkeddatafragments/datasource/IDataSource.java
+++ b/src/org/linkeddatafragments/datasource/IDataSource.java
@@ -9,18 +9,18 @@
* @author Ruben Verborgh
*/
public interface IDataSource {
- /**
- * Gets a page of the Basic Linked Data Fragment matching the specified triple pattern.
- * @param subject the subject (null to match any subject)
- * @param predicate the predicate (null to match any predicate)
- * @param object the object (null to match any object)
- * @param offset the triple index at which to start the page
- * @param limit the number of triples on the page
- * @return the first page of the fragment
- */
- public TriplePatternFragment getFragment(Resource subject, Property predicate, RDFNode object,
- long offset, long limit);
- public String getTitle();
+ /**
+ * Gets a page of the Basic Linked Data Fragment matching the specified triple pattern.
+ * @param subject the subject (null to match any subject)
+ * @param predicate the predicate (null to match any predicate)
+ * @param object the object (null to match any object)
+ * @param offset the triple index at which to start the page
+ * @param limit the number of triples on the page
+ * @return the first page of the fragment
+ */
+ public TriplePatternFragment getFragment(Resource subject, Property predicate,
+ RDFNode object, long offset, long limit);
+ public String getTitle();
- public String getDescription();
+ public String getDescription();
}
diff --git a/src/org/linkeddatafragments/datasource/TriplePatternFragment.java b/src/org/linkeddatafragments/datasource/TriplePatternFragment.java
index 02cac35..fa21d36 100644
--- a/src/org/linkeddatafragments/datasource/TriplePatternFragment.java
+++ b/src/org/linkeddatafragments/datasource/TriplePatternFragment.java
@@ -7,15 +7,15 @@
* @author Ruben Verborgh
*/
public interface TriplePatternFragment {
- /**
- * Gets the data of this fragment (possibly only partial).
- * @return the data as triples
- */
- public Model getTriples();
-
- /**
- * Gets the total number of triples in the fragment (can be an estimate).
- * @return the total number of triples
- */
- public long getTotalSize();
+ /**
+ * Gets the data of this fragment (possibly only partial).
+ * @return the data as triples
+ */
+ public Model getTriples();
+
+ /**
+ * Gets the total number of triples in the fragment (can be an estimate).
+ * @return the total number of triples
+ */
+ public long getTotalSize();
}
diff --git a/src/org/linkeddatafragments/datasource/TriplePatternFragmentBase.java b/src/org/linkeddatafragments/datasource/TriplePatternFragmentBase.java
index b7ac88d..3645b08 100644
--- a/src/org/linkeddatafragments/datasource/TriplePatternFragmentBase.java
+++ b/src/org/linkeddatafragments/datasource/TriplePatternFragmentBase.java
@@ -8,33 +8,33 @@
* @author Ruben Verborgh
*/
public class TriplePatternFragmentBase implements TriplePatternFragment {
- private final Model triples;
- private final long totalSize;
-
- /**
- * Creates an empty Basic Linked Data Fragment.
- */
- public TriplePatternFragmentBase() {
- this(null, 0);
- }
-
- /**
- * Creates a new Basic Linked Data Fragment.
- * @param triples the triples (possibly partial)
- * @param totalSize the total size
- */
- public TriplePatternFragmentBase(Model triples, long totalSize) {
- this.triples = triples == null ? ModelFactory.createDefaultModel() : triples;
- this.totalSize = totalSize < 0 ? 0 : totalSize;
- }
+ private final Model triples;
+ private final long totalSize;
- @Override
- public Model getTriples() {
- return triples;
- }
+ /**
+ * Creates an empty Basic Linked Data Fragment.
+ */
+ public TriplePatternFragmentBase() {
+ this(null, 0);
+ }
- @Override
- public long getTotalSize() {
- return totalSize;
- }
+ /**
+ * Creates a new Basic Linked Data Fragment.
+ * @param triples the triples (possibly partial)
+ * @param totalSize the total size
+ */
+ public TriplePatternFragmentBase(Model triples, long totalSize) {
+ this.triples = triples == null ? ModelFactory.createDefaultModel() : triples;
+ this.totalSize = totalSize < 0 ? 0 : totalSize;
+ }
+
+ @Override
+ public Model getTriples() {
+ return triples;
+ }
+
+ @Override
+ public long getTotalSize() {
+ return totalSize;
+ }
}
diff --git a/src/org/linkeddatafragments/exceptions/DataSourceException.java b/src/org/linkeddatafragments/exceptions/DataSourceException.java
index a82799e..fb6bd6a 100644
--- a/src/org/linkeddatafragments/exceptions/DataSourceException.java
+++ b/src/org/linkeddatafragments/exceptions/DataSourceException.java
@@ -5,6 +5,7 @@
* @author mielvandersande
*/
public class DataSourceException extends Exception {
+ private static final long serialVersionUID = 1L;
public DataSourceException(Throwable cause) {
super(cause.getMessage());
@@ -12,6 +13,5 @@ public DataSourceException(Throwable cause) {
public DataSourceException(String message) {
super("Could not create DataSource: " + message);
- }
-
+ }
}
diff --git a/src/org/linkeddatafragments/exceptions/UnknownDataSourceTypeException.java b/src/org/linkeddatafragments/exceptions/UnknownDataSourceTypeException.java
index e5bd95d..e7dc9fc 100644
--- a/src/org/linkeddatafragments/exceptions/UnknownDataSourceTypeException.java
+++ b/src/org/linkeddatafragments/exceptions/UnknownDataSourceTypeException.java
@@ -5,9 +5,9 @@
* @author mielvandersande
*/
public class UnknownDataSourceTypeException extends DataSourceException {
+ private static final long serialVersionUID = 1L;
public UnknownDataSourceTypeException(String type) {
super("Type " + type + " does not exist.");
- }
-
+ }
}
diff --git a/src/org/linkeddatafragments/servlet/TriplePatternFragmentServlet.java b/src/org/linkeddatafragments/servlet/TriplePatternFragmentServlet.java
index 9764cde..f86d927 100644
--- a/src/org/linkeddatafragments/servlet/TriplePatternFragmentServlet.java
+++ b/src/org/linkeddatafragments/servlet/TriplePatternFragmentServlet.java
@@ -1,120 +1,262 @@
package org.linkeddatafragments.servlet;
-import com.google.gson.JsonObject;
-import com.hp.hpl.jena.datatypes.TypeMapper;
-import com.hp.hpl.jena.datatypes.xsd.XSDDatatype;
-import com.hp.hpl.jena.rdf.model.Literal;
-import com.hp.hpl.jena.rdf.model.Model;
-import com.hp.hpl.jena.rdf.model.Property;
-import com.hp.hpl.jena.rdf.model.RDFNode;
-import com.hp.hpl.jena.rdf.model.Resource;
-import com.hp.hpl.jena.rdf.model.ResourceFactory;
-import com.hp.hpl.jena.shared.InvalidPropertyURIException;
import java.io.File;
import java.io.FileReader;
+import java.io.IOException;
+
+import java.net.URISyntaxException;
+
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.codec.CharEncoding;
+
+import org.apache.http.HttpHeaders;
import org.apache.http.client.utils.URIBuilder;
+
import org.apache.jena.riot.Lang;
import org.apache.jena.riot.RDFDataMgr;
import org.apache.jena.riot.RDFLanguages;
+
+import com.google.gson.JsonObject;
+
+import com.hp.hpl.jena.datatypes.TypeMapper;
+import com.hp.hpl.jena.datatypes.xsd.XSDDatatype;
+import com.hp.hpl.jena.rdf.model.Literal;
+import com.hp.hpl.jena.rdf.model.Model;
+import com.hp.hpl.jena.rdf.model.Property;
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import com.hp.hpl.jena.rdf.model.Resource;
+import com.hp.hpl.jena.rdf.model.ResourceFactory;
+import com.hp.hpl.jena.shared.InvalidPropertyURIException;
+
import org.linkeddatafragments.config.ConfigReader;
import org.linkeddatafragments.datasource.DataSourceFactory;
import org.linkeddatafragments.datasource.IDataSource;
import org.linkeddatafragments.datasource.TriplePatternFragment;
-
-import static org.linkeddatafragments.util.CommonResources.*;
-
+import org.linkeddatafragments.exceptions.DataSourceException;
+import org.linkeddatafragments.util.CommonResources;
import org.linkeddatafragments.util.MIMEParse;
/**
* Servlet that responds with a Basic Linked Data Fragment.
*
* @author Ruben Verborgh
+ * @author Bart Hanssens
*/
public class TriplePatternFragmentServlet extends HttpServlet {
-
private final static long serialVersionUID = 1L;
- private final static Pattern STRINGPATTERN = Pattern.compile("^\"(.*)\"(?:@(.*)|\\^\\^([^<>]*)>?)?$");
- private final static TypeMapper types = TypeMapper.getInstance();
+
+ // Parameters
+ public final static String CFGFILE = "configFile";
+ public final static String SUBJ = "subject";
+ public final static String PRED = "predicate";
+ public final static String OBJ = "object";
+ public final static String PAGE = "page";
+
+
+ private final static Pattern STRINGPATTERN =
+ Pattern.compile("^\"(.*)\"(?:@(.*)|\\^\\^([^<>]*)>?)?$");
+ private final static TypeMapper TYPES = TypeMapper.getInstance();
private final static long TRIPLESPERPAGE = 100;
private ConfigReader config;
private final HashMap dataSources = new HashMap<>();
private final Collection mimeTypes = new ArrayList<>();
+
+ private File getConfigFile(ServletConfig config) throws IOException {
+ String path = config.getServletContext().getRealPath("/");
+ if (path == null) {
+ // this can happen when running standalone
+ path = System.getProperty("user.dir");
+ }
+ File cfg = new File(path, "config-example.json");
+ if (config.getInitParameter(CFGFILE) != null) {
+ cfg = new File(config.getInitParameter(CFGFILE));
+ }
+ if (!cfg.exists()) {
+ throw new IOException("Configuration file " + cfg + " not found.");
+ }
+ if (!cfg.isFile()) {
+ throw new IOException("Configuration file " + cfg + " is not a file.");
+ }
+ return cfg;
+ }
+
@Override
public void init(ServletConfig servletConfig) throws ServletException {
try {
- // find the configuration file
- String applicationPathStr = servletConfig.getServletContext().getRealPath("/");
- if (applicationPathStr == null) { // this can happen when running standalone
- applicationPathStr = System.getProperty("user.dir");
- }
- final File applicationPath = new File(applicationPathStr);
-
- File configFile = new File(applicationPath, "config-example.json");
- if (servletConfig.getInitParameter("configFile") != null) {
- configFile = new File(servletConfig.getInitParameter("configFile"));
- }
-
- if (!configFile.exists()) {
- throw new Exception("Configuration file " + configFile + " not found.");
- }
-
- if (!configFile.isFile()) {
- throw new Exception("Configuration file " + configFile + " is not a file.");
- }
-
// load the configuration
+ File configFile = getConfigFile(servletConfig);
config = new ConfigReader(new FileReader(configFile));
+
for (Entry dataSource : config.getDataSources().entrySet()) {
dataSources.put(dataSource.getKey(), DataSourceFactory.create(dataSource.getValue()));
}
-
- // register content types
+ // register content types
mimeTypes.add(Lang.TTL.getHeaderString());
mimeTypes.add(Lang.JSONLD.getHeaderString());
mimeTypes.add(Lang.NTRIPLES.getHeaderString());
mimeTypes.add(Lang.RDFXML.getHeaderString() );
- } catch (Exception e) {
+ } catch (IOException | DataSourceException e) {
throw new ServletException(e);
}
}
+ /**
+ * Get the datasource
+ *
+ * @param request
+ * @return
+ * @throws IOException
+ */
+ private IDataSource getDataSource(HttpServletRequest request) throws IOException {
+ String contextPath = request.getContextPath();
+ String requestURI = request.getRequestURI();
+
+ String path = contextPath == null
+ ? requestURI
+ : requestURI.substring(contextPath.length());
+ String dataSourceName = path.substring(1);
+ IDataSource dataSource = dataSources.get(dataSourceName);
+ if (dataSource == null) {
+ throw new IOException("Data source not found.");
+ }
+ return dataSource;
+ }
+
+ /**
+ * Get dataset url
+ *
+ * @param request
+ * @return
+ */
+ private String getDatasetUrl(HttpServletRequest request) {
+ String hostName = request.getHeader(HttpHeaders.SERVER);
+ if (hostName == null) {
+ hostName = request.getServerName();
+ }
+ return request.getScheme() + "://" + hostName + request.getRequestURI();
+ }
+
+ /**
+ * Add total and limit
+ *
+ * @param output
+ * @param fragmentId
+ * @param total
+ * @param limit
+ */
+ private void addMeta(Model output, Resource datasetId, Resource fragmentId,
+ long total, long limit) {
+ output.add(datasetId, CommonResources.RDF_TYPE, CommonResources.VOID_DATASET);
+ output.add(datasetId, CommonResources.RDF_TYPE, CommonResources.HYDRA_COLLECTION);
+ output.add(datasetId, CommonResources.VOID_SUBSET, fragmentId);
+
+ output.add(fragmentId, CommonResources.RDF_TYPE, CommonResources.HYDRA_COLLECTION);
+ output.add(fragmentId, CommonResources.RDF_TYPE, CommonResources.HYDRA_PAGEDCOLLECTION);
+
+ Literal totalTyped = output.createTypedLiteral(total, XSDDatatype.XSDinteger);
+ Literal limitTyped = output.createTypedLiteral(limit, XSDDatatype.XSDinteger);
+
+ output.add(fragmentId, CommonResources.VOID_TRIPLES, totalTyped);
+ output.add(fragmentId, CommonResources.HYDRA_TOTALITEMS, totalTyped);
+ output.add(fragmentId, CommonResources.HYDRA_ITEMSPERPAGE, limitTyped);
+ }
+
+
+ /**
+ * Add reference to first/previous/next page
+ *
+ * @param output
+ * @param fragmentId
+ * @param fragmentUrl
+ * @param total
+ * @param limit
+ * @param offset
+ * @param page
+ * @throws URISyntaxException
+ */
+ private void addPages(Model output, Resource fragmentId, String fragmentUrl,
+ long total, long limit, long offset, long page) throws URISyntaxException {
+ URIBuilder pagedUrl = new URIBuilder(fragmentUrl);
+
+ pagedUrl.setParameter(PAGE, "1");
+ output.add(fragmentId, CommonResources.HYDRA_FIRSTPAGE,
+ output.createResource(pagedUrl.toString()));
+ if (offset > 0) {
+ pagedUrl.setParameter(PAGE, Long.toString(page - 1));
+ output.add(fragmentId, CommonResources.HYDRA_PREVIOUSPAGE,
+ output.createResource(pagedUrl.toString()));
+ }
+ if (offset + limit < total) {
+ pagedUrl.setParameter(PAGE, Long.toString(page + 1));
+ output.add(fragmentId, CommonResources.HYDRA_NEXTPAGE,
+ output.createResource(pagedUrl.toString()));
+ }
+ }
+
+ /**
+ * Add controls to output
+ *
+ * @param output
+ * @param datasetId
+ * @param datasetUrl
+ */
+ private void addControls(Model output, Resource datasetId, String datasetUrl) {
+ // add controls
+ Resource triplePattern = output.createResource();
+ Resource subjectMapping = output.createResource();
+ Resource predicateMapping = output.createResource();
+ Resource objectMapping = output.createResource();
+
+ output.add(datasetId, CommonResources.HYDRA_SEARCH, triplePattern);
+ output.add(triplePattern, CommonResources.HYDRA_TEMPLATE, output.createLiteral(datasetUrl + "{?subject,predicate,object}"));
+ output.add(triplePattern, CommonResources.HYDRA_MAPPING, subjectMapping);
+ output.add(triplePattern, CommonResources.HYDRA_MAPPING, predicateMapping);
+ output.add(triplePattern, CommonResources.HYDRA_MAPPING, objectMapping);
+
+ output.add(subjectMapping, CommonResources.HYDRA_VARIABLE, output.createLiteral(SUBJ));
+ output.add(subjectMapping, CommonResources.HYDRA_PROPERTY, CommonResources.RDF_SUBJECT);
+
+ output.add(predicateMapping, CommonResources.HYDRA_VARIABLE, output.createLiteral(PRED));
+ output.add(predicateMapping, CommonResources.HYDRA_PROPERTY, CommonResources.RDF_PREDICATE);
+ output.add(objectMapping, CommonResources.HYDRA_VARIABLE, output.createLiteral(OBJ));
+
+ output.add(objectMapping, CommonResources.HYDRA_PROPERTY, CommonResources.RDF_OBJECT);
+ }
+
+
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException {
try {
- // find the data source
- final String contextPath = request.getContextPath();
- final String requestURI = request.getRequestURI();
- final String path = contextPath == null ? requestURI : requestURI.substring(contextPath.length());
- final String query = request.getQueryString();
- final String dataSourceName = path.substring(1);
- final IDataSource dataSource = dataSources.get(dataSourceName);
- if (dataSource == null) {
- throw new Exception("Data source not found.");
- }
-
+ IDataSource dataSource = getDataSource(request);
+
// query the fragment
- final Resource subject = parseAsResource(request.getParameter("subject"));
- final Property predicate = parseAsProperty(request.getParameter("predicate"));
- final RDFNode object = parseAsNode(request.getParameter("object"));
- final long page = Math.max(1, parseAsInteger(request.getParameter("page")));
- final long limit = TRIPLESPERPAGE, offset = limit * (page - 1);
- final TriplePatternFragment fragment = dataSource.getFragment(subject, predicate, object, offset, limit);
+ Resource subject = parseAsResource(request.getParameter(SUBJ));
+ Property predicate = parseAsProperty(request.getParameter(PRED));
+ RDFNode object = parseAsNode(request.getParameter(OBJ));
+
+ long page = Math.max(1, parseAsInteger(request.getParameter(PAGE)));
+ long limit = TRIPLESPERPAGE;
+ long offset = limit * (page - 1);
+
+ TriplePatternFragment fragment =
+ dataSource.getFragment(subject, predicate, object, offset, limit);
// fill the output model
- final Model output = fragment.getTriples();
+ Model output = fragment.getTriples();
output.setNsPrefixes(config.getPrefixes());
// do conneg
@@ -128,54 +270,26 @@ public void doGet(HttpServletRequest request, HttpServletResponse response) thro
RDFDataMgr.write(response.getOutputStream(), output, contentType);
// add dataset metadata
- final String hostName = request.getHeader("Host");
- final String datasetUrl = request.getScheme() + "://"
- + (hostName == null ? request.getServerName() : hostName) + request.getRequestURI();
- final String fragmentUrl = query == null ? datasetUrl : (datasetUrl + "?" + query);
- final Resource datasetId = output.createResource(datasetUrl + "#dataset");
- final Resource fragmentId = output.createResource(fragmentUrl);
- output.add(datasetId, RDF_TYPE, VOID_DATASET);
- output.add(datasetId, RDF_TYPE, HYDRA_COLLECTION);
- output.add(datasetId, VOID_SUBSET, fragmentId);
-
- // add fragment metadata
- output.add(fragmentId, RDF_TYPE, HYDRA_COLLECTION);
- output.add(fragmentId, RDF_TYPE, HYDRA_PAGEDCOLLECTION);
- final Literal total = output.createTypedLiteral(fragment.getTotalSize(), XSDDatatype.XSDinteger);
- output.add(fragmentId, VOID_TRIPLES, total);
- output.add(fragmentId, HYDRA_TOTALITEMS, total);
- output.add(fragmentId, HYDRA_ITEMSPERPAGE, output.createTypedLiteral(limit, XSDDatatype.XSDinteger));
-
- // add pages
- final URIBuilder pagedUrl = new URIBuilder(fragmentUrl);
- pagedUrl.setParameter("page", "1");
- output.add(fragmentId, HYDRA_FIRSTPAGE, output.createResource(pagedUrl.toString()));
- if (offset > 0) {
- pagedUrl.setParameter("page", Long.toString(page - 1));
- output.add(fragmentId, HYDRA_PREVIOUSPAGE, output.createResource(pagedUrl.toString()));
- }
- if (offset + limit < fragment.getTotalSize()) {
- pagedUrl.setParameter("page", Long.toString(page + 1));
- output.add(fragmentId, HYDRA_NEXTPAGE, output.createResource(pagedUrl.toString()));
- }
+ String datasetUrl = getDatasetUrl(request);
+ Resource datasetId = output.createResource(datasetUrl + "#dataset");
+
+ String query = request.getQueryString();
+ String fragmentUrl = query == null ? datasetUrl : (datasetUrl + "?" + query);
+ Resource fragmentId = output.createResource(fragmentUrl);
- // add controls
- final Resource triplePattern = output.createResource();
- final Resource subjectMapping = output.createResource();
- final Resource predicateMapping = output.createResource();
- final Resource objectMapping = output.createResource();
- output.add(datasetId, HYDRA_SEARCH, triplePattern);
- output.add(triplePattern, HYDRA_TEMPLATE, output.createLiteral(datasetUrl + "{?subject,predicate,object}"));
- output.add(triplePattern, HYDRA_MAPPING, subjectMapping);
- output.add(triplePattern, HYDRA_MAPPING, predicateMapping);
- output.add(triplePattern, HYDRA_MAPPING, objectMapping);
- output.add(subjectMapping, HYDRA_VARIABLE, output.createLiteral("subject"));
- output.add(subjectMapping, HYDRA_PROPERTY, RDF_SUBJECT);
- output.add(predicateMapping, HYDRA_VARIABLE, output.createLiteral("predicate"));
- output.add(predicateMapping, HYDRA_PROPERTY, RDF_PREDICATE);
- output.add(objectMapping, HYDRA_VARIABLE, output.createLiteral("object"));
- output.add(objectMapping, HYDRA_PROPERTY, RDF_OBJECT);
- } catch (Exception e) {
+ long total = fragment.getTotalSize();
+
+ addMeta(output, datasetId, fragmentId, total, limit);
+ addPages(output, fragmentId, fragmentUrl, total, limit, offset, page);
+ addControls(output, datasetId, datasetUrl);
+
+ // serialize the output as Turtle
+ response.setHeader(HttpHeaders.SERVER, "Linked Data Fragments Server");
+ response.setContentType("text/turtle");
+ response.setCharacterEncoding(CharEncoding.UTF_8);
+
+ output.write(response.getWriter(), "Turtle", fragmentUrl);
+ } catch (IOException | URISyntaxException e) {
throw new ServletException(e);
}
}
@@ -201,8 +315,10 @@ private int parseAsInteger(String value) {
* @return the parsed value, or null if unspecified
*/
private Resource parseAsResource(String value) {
- final RDFNode subject = parseAsNode(value);
- return subject == null || subject instanceof Resource ? (Resource) subject : INVALID_URI;
+ RDFNode subject = parseAsNode(value);
+ return subject == null || subject instanceof Resource
+ ? (Resource) subject
+ : CommonResources.INVALID_URI;
}
/**
@@ -212,15 +328,15 @@ private Resource parseAsResource(String value) {
* @return the parsed value, or null if unspecified
*/
private Property parseAsProperty(String value) {
- final RDFNode predicateNode = parseAsNode(value);
+ RDFNode predicateNode = parseAsNode(value);
if (predicateNode instanceof Resource) {
try {
return ResourceFactory.createProperty(((Resource) predicateNode).getURI());
} catch (InvalidPropertyURIException ex) {
- return INVALID_URI;
+ return CommonResources.INVALID_URI;
}
}
- return predicateNode == null ? null : INVALID_URI;
+ return predicateNode == null ? null : CommonResources.INVALID_URI;
}
/**
@@ -231,11 +347,11 @@ private Property parseAsProperty(String value) {
*/
private RDFNode parseAsNode(String value) {
// nothing or empty indicates an unknown
- if (value == null || value.length() == 0) {
+ if (value == null || value.isEmpty()) {
return null;
}
// find the kind of entity based on the first character
- final char firstChar = value.charAt(0);
+ char firstChar = value.charAt(0);
switch (firstChar) {
// variable or blank node indicates an unknown
case '?':
@@ -246,20 +362,20 @@ private RDFNode parseAsNode(String value) {
return ResourceFactory.createResource(value.substring(1, value.length() - 1));
// quotes indicate a string
case '"':
- final Matcher matcher = STRINGPATTERN.matcher(value);
+ Matcher matcher = STRINGPATTERN.matcher(value);
if (matcher.matches()) {
- final String body = matcher.group(1);
- final String lang = matcher.group(2);
- final String type = matcher.group(3);
+ String body = matcher.group(1);
+ String lang = matcher.group(2);
+ String type = matcher.group(3);
if (lang != null) {
return ResourceFactory.createLangLiteral(body, lang);
}
if (type != null) {
- return ResourceFactory.createTypedLiteral(body, types.getSafeTypeByName(type));
+ return ResourceFactory.createTypedLiteral(body, TYPES.getSafeTypeByName(type));
}
return ResourceFactory.createPlainLiteral(body);
}
- return INVALID_URI;
+ return CommonResources.INVALID_URI;
// assume it's a URI without angular brackets
default:
return ResourceFactory.createResource(value);
diff --git a/src/org/linkeddatafragments/standalone/JettyServer.java b/src/org/linkeddatafragments/standalone/JettyServer.java
index 6d59d07..23ff9c1 100644
--- a/src/org/linkeddatafragments/standalone/JettyServer.java
+++ b/src/org/linkeddatafragments/standalone/JettyServer.java
@@ -1,9 +1,15 @@
package org.linkeddatafragments.standalone;
-import org.apache.commons.cli.*;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Options;
+
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
+
import org.linkeddatafragments.servlet.TriplePatternFragmentServlet;
/**
@@ -16,64 +22,58 @@
* need for a separate servlet container such as Tomcat.
*
*
- * Copyright 2014 MMLab, UGent
*
* @author Gerald Haesendonck
* @author Miel Vander Sande
+ * @author Bart Hanssens
*/
public class JettyServer {
-
+ private static void printHelp(Options options) {
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp(JettyServer.class.getName() + " [config-example.json] []",
+ "Starts a standalone LDF Triple Pattern server. Options:", options, "");
+ }
+
public static void main(String[] args) throws Exception {
Options options = new Options();
options.addOption("h", "help", false, "Print this help message and then exit.");
options.addOption("p", "port", true, "The port the server listents to. The default is 8080.");
- boolean printHelp = false;
- CommandLineParser parser = new BasicParser();
- try {
- CommandLine commandLine = parser.parse(options, args);
+
+ CommandLineParser parser = new DefaultParser();
+ CommandLine commandLine = parser.parse(options, args);
- String config = null;
- if (!commandLine.getArgList().isEmpty()) {
- config = commandLine.getArgs()[0];
- }
-
- if (commandLine.hasOption('h')) {
- printHelp = true;
- return;
- }
- int port;
- if (commandLine.hasOption('p')) {
- port = Integer.parseInt(commandLine.getOptionValue('p'));
- } else {
- port = 8080;
- }
+ String config = null;
+ if (!commandLine.getArgList().isEmpty()) {
+ config = commandLine.getArgs()[0];
+ }
- // create a new (Jetty) server, and add a servlet handler
- Server server = new Server(port);
- ServletHandler handler = new ServletHandler();
- server.setHandler(handler);
+ if (config == null || commandLine.hasOption('h')) {
+ printHelp(options);
+ System.exit(-1);
+ }
+
+ int port = 8080;
+ if (commandLine.hasOption('p')) {
+ port = Integer.parseInt(commandLine.getOptionValue('p'));
+ }
- // add the TriplePatternFragmentsServlet to the handler
- ServletHolder tpfServletHolder = new ServletHolder(new TriplePatternFragmentServlet());
- tpfServletHolder.setInitParameter("configFile", config);
- handler.addServletWithMapping(tpfServletHolder, "/*");
+ // create a new (Jetty) server, and add a servlet handler
+ Server server = new Server(port);
+ ServletHandler handler = new ServletHandler();
+ server.setHandler(handler);
- // start the server
- server.start();
- System.out.println("Started server, listening at port " + port);
+ // add the TriplePatternFragmentsServlet to the handler
+ ServletHolder tpfServletHolder = new ServletHolder(new TriplePatternFragmentServlet());
+ tpfServletHolder.setInitParameter(TriplePatternFragmentServlet.CFGFILE, config);
+ handler.addServletWithMapping(tpfServletHolder, "/*");
- // The use of server.join() the will make the current thread join and wait until the server is done executing.
- // See http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#join()
- server.join();
- } catch (ParseException e) {
- System.out.println(e.getMessage());
- printHelp = true;
+ // start the server
+ server.start();
+ System.out.println("Started server, listening at port " + port);
- } finally {
- if (printHelp) {
- HelpFormatter formatter = new HelpFormatter();
- formatter.printHelp(JettyServer.class.getName() + " [config-example.json] []", "Starts a standalone LDF Trpile Pattern server. Options:", options, "");
- }
- }
+ // The use of server.join() the will make the current thread join and wait until the server is done executing.
+ // See http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#join()
+ server.join();
}
}
diff --git a/src/org/linkeddatafragments/util/CommonResources.java b/src/org/linkeddatafragments/util/CommonResources.java
index f7b4f2c..150ca17 100644
--- a/src/org/linkeddatafragments/util/CommonResources.java
+++ b/src/org/linkeddatafragments/util/CommonResources.java
@@ -5,35 +5,35 @@
@SuppressWarnings("javadoc")
public class CommonResources {
- public final static String RDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
- public final static Property RDF_TYPE = createProperty(RDF + "type");
- public final static Property RDF_SUBJECT = createProperty(RDF + "subject");
- public final static Property RDF_PREDICATE = createProperty(RDF + "predicate");
- public final static Property RDF_OBJECT = createProperty(RDF + "object");
-
- public final static String VOID = "http://rdfs.org/ns/void#";
- public final static Property VOID_TRIPLES = createProperty(VOID + "triples");
- public final static Property VOID_SUBSET = createProperty(VOID + "subset");
- public final static Property VOID_DATASET = createProperty(VOID + "Dataset");
-
- public final static String HYDRA = "http://www.w3.org/ns/hydra/core#";
- public final static Property HYDRA_TOTALITEMS = createProperty(HYDRA + "totalItems");
- public final static Property HYDRA_ITEMSPERPAGE = createProperty(HYDRA + "itemsPerPage");
- public final static Property HYDRA_SEARCH = createProperty(HYDRA + "search");
- public final static Property HYDRA_TEMPLATE = createProperty(HYDRA + "template");
- public final static Property HYDRA_MAPPING = createProperty(HYDRA + "mapping");
- public final static Property HYDRA_VARIABLE = createProperty(HYDRA + "variable");
- public final static Property HYDRA_PROPERTY = createProperty(HYDRA + "property");
- public final static Property HYDRA_COLLECTION = createProperty(HYDRA + "Collection");
- public final static Property HYDRA_PAGEDCOLLECTION = createProperty(HYDRA + "PagedCollection");
- public final static Property HYDRA_FIRSTPAGE = createProperty(HYDRA + "firstPage");
- public final static Property HYDRA_LASTPAGE = createProperty(HYDRA + "lastPage");
- public final static Property HYDRA_NEXTPAGE = createProperty(HYDRA + "nextPage");
- public final static Property HYDRA_PREVIOUSPAGE = createProperty(HYDRA + "previousPage");
-
- public final static Property INVALID_URI = createProperty("urn:invalid");
-
- private static Property createProperty(String uri) {
- return ResourceFactory.createProperty(uri);
- }
+ public final static String RDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+ public final static Property RDF_TYPE = createProperty(RDF + "type");
+ public final static Property RDF_SUBJECT = createProperty(RDF + "subject");
+ public final static Property RDF_PREDICATE = createProperty(RDF + "predicate");
+ public final static Property RDF_OBJECT = createProperty(RDF + "object");
+
+ public final static String VOID = "http://rdfs.org/ns/void#";
+ public final static Property VOID_TRIPLES = createProperty(VOID + "triples");
+ public final static Property VOID_SUBSET = createProperty(VOID + "subset");
+ public final static Property VOID_DATASET = createProperty(VOID + "Dataset");
+
+ public final static String HYDRA = "http://www.w3.org/ns/hydra/core#";
+ public final static Property HYDRA_TOTALITEMS = createProperty(HYDRA + "totalItems");
+ public final static Property HYDRA_ITEMSPERPAGE = createProperty(HYDRA + "itemsPerPage");
+ public final static Property HYDRA_SEARCH = createProperty(HYDRA + "search");
+ public final static Property HYDRA_TEMPLATE = createProperty(HYDRA + "template");
+ public final static Property HYDRA_MAPPING = createProperty(HYDRA + "mapping");
+ public final static Property HYDRA_VARIABLE = createProperty(HYDRA + "variable");
+ public final static Property HYDRA_PROPERTY = createProperty(HYDRA + "property");
+ public final static Property HYDRA_COLLECTION = createProperty(HYDRA + "Collection");
+ public final static Property HYDRA_PAGEDCOLLECTION = createProperty(HYDRA + "PagedCollection");
+ public final static Property HYDRA_FIRSTPAGE = createProperty(HYDRA + "firstPage");
+ public final static Property HYDRA_LASTPAGE = createProperty(HYDRA + "lastPage");
+ public final static Property HYDRA_NEXTPAGE = createProperty(HYDRA + "nextPage");
+ public final static Property HYDRA_PREVIOUSPAGE = createProperty(HYDRA + "previousPage");
+
+ public final static Property INVALID_URI = createProperty("urn:invalid");
+
+ private static Property createProperty(String uri) {
+ return ResourceFactory.createProperty(uri);
+ }
}