From f4ad030d9862c7670c2d1269b181f6ea56539fdb Mon Sep 17 00:00:00 2001 From: Olaf Hartig Date: Fri, 25 Dec 2015 17:23:55 +0100 Subject: [PATCH 01/12] small change of the API in LinkedDataFragmentRequest: getPageNumber does not throw UnsupportedOperationException anymore --- ...asedRequestProcessorForTriplePatterns.java | 154 ------------------ .../fragments/LinkedDataFragmentRequest.java | 10 +- .../LinkedDataFragmentRequestBase.java | 9 +- 3 files changed, 7 insertions(+), 166 deletions(-) delete mode 100644 src/org/linkeddatafragments/datasource/AbstractJenaBasedRequestProcessorForTriplePatterns.java diff --git a/src/org/linkeddatafragments/datasource/AbstractJenaBasedRequestProcessorForTriplePatterns.java b/src/org/linkeddatafragments/datasource/AbstractJenaBasedRequestProcessorForTriplePatterns.java deleted file mode 100644 index 8fba309..0000000 --- a/src/org/linkeddatafragments/datasource/AbstractJenaBasedRequestProcessorForTriplePatterns.java +++ /dev/null @@ -1,154 +0,0 @@ -package org.linkeddatafragments.datasource; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.linkeddatafragments.fragments.LinkedDataFragment; -import org.linkeddatafragments.fragments.tpf.TriplePatternFragmentRequest; -import org.linkeddatafragments.util.CommonResources; - -import com.hp.hpl.jena.datatypes.TypeMapper; -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; - -/** - * Base class for implementations of {@link IFragmentRequestProcessor} that - * process {@link TriplePatternFragmentRequest}s based on the Jena API. - * - * @author Olaf Hartig - * @author Ruben Verborgh - */ -abstract public class AbstractJenaBasedRequestProcessorForTriplePatterns - extends AbstractRequestProcessorForTriplePatterns -{ - abstract static protected class Worker - extends AbstractRequestProcessorForTriplePatterns.Worker - { - public Worker( final TriplePatternFragmentRequest request ) - { - super( request ); - } - - @Override - protected LinkedDataFragment createFragment( final String subject, - final String predicate, - final String object, - final long offset, - final long limit ) - throws IllegalArgumentException - { - final Resource s = parseAsResource( subject ); - final Property p = parseAsProperty( predicate ); - final RDFNode o = parseAsNode( object ); - - return createFragment( s, p, o, offset, limit ); - } - - abstract protected LinkedDataFragment createFragment( - final Resource subject, - final Property predicate, - final RDFNode object, - final long offset, - final long limit ) - throws IllegalArgumentException; - - /** - * Parses the given value as an RDF resource. - * - * @param value the value - * @return the parsed value, or null if unspecified - */ - public Resource parseAsResource( String value ) - { - RDFNode subject = parseAsNode( value ); - return subject == null || subject instanceof Resource - ? (Resource) subject - : CommonResources.INVALID_URI; - } - - /** - * Parses the given value as an RDF property. - * - * @param value the value - * @return the parsed value, or null if unspecified - */ - public Property parseAsProperty( String value ) - { - RDFNode predicateNode = parseAsNode( value ); - if ( predicateNode instanceof Resource ) { - final String uri = ( (Resource) predicateNode ).getURI(); - return ResourceFactory.createProperty( uri ); - } - else if ( predicateNode == null ) { - return null; - } - else { - return CommonResources.INVALID_URI; - } - } - - public final static TypeMapper TYPES = TypeMapper.getInstance(); - public final static Pattern STRINGPATTERN - = Pattern.compile("^\"(.*)\"(?:@(.*)|\\^\\^]*)>?)?$"); - - /** - * Parses the given value as an RDF node. - * - * @param value the value - * @return the parsed value, or null if unspecified - */ - public RDFNode parseAsNode( String value ) - { - // nothing or empty indicates an unknown - if ( value == null || value.isEmpty() ) { - return null; - } - - // find the kind of entity based on the first character - char firstChar = value.charAt(0); - switch ( firstChar ) - { - // variable or blank node indicates an unknown - case '?': - case '_': - return null; - - // angular brackets indicate a URI - case '<': - return ResourceFactory.createResource( - value.substring(1, value.length() - 1) ); - - // quotes indicate a string - case '"': - Matcher matcher = STRINGPATTERN.matcher( value ); - if ( matcher.matches() ) { - String body = matcher.group(1); - String lang = matcher.group(2); - String type = matcher.group(3); - if ( lang != null ) { - return ResourceFactory.createLangLiteral( - body, lang ); - } - else if ( type != null ) { - return ResourceFactory.createTypedLiteral( - body, TYPES.getSafeTypeByName(type) ); - } - else { - return ResourceFactory.createPlainLiteral( body ); - } - } - else { - return CommonResources.INVALID_URI; - } - - // assume it's a URI without angular brackets - default: - return ResourceFactory.createResource( value ); - } - } - - } // end of class Worker - -} diff --git a/src/org/linkeddatafragments/fragments/LinkedDataFragmentRequest.java b/src/org/linkeddatafragments/fragments/LinkedDataFragmentRequest.java index 0cbe701..3cc12c0 100644 --- a/src/org/linkeddatafragments/fragments/LinkedDataFragmentRequest.java +++ b/src/org/linkeddatafragments/fragments/LinkedDataFragmentRequest.java @@ -28,11 +28,9 @@ public interface LinkedDataFragmentRequest boolean isPageRequest(); /** - * Returns the number of the page requested for the LDF, if any (thatis, - * if {@link #isPageOnly()} returns true). - * - * @throws UnsupportedOperationException - * If the request is not for a specific page. + * Returns the number of the page requested for the LDF; if this is not a + * page-based request (that is, if {@link #isPageRequest()} returns true), + * then this method returns 1. */ - long getPageNumber() throws UnsupportedOperationException; + long getPageNumber(); } diff --git a/src/org/linkeddatafragments/fragments/LinkedDataFragmentRequestBase.java b/src/org/linkeddatafragments/fragments/LinkedDataFragmentRequestBase.java index d6a7f87..d8e5d25 100644 --- a/src/org/linkeddatafragments/fragments/LinkedDataFragmentRequestBase.java +++ b/src/org/linkeddatafragments/fragments/LinkedDataFragmentRequestBase.java @@ -21,7 +21,7 @@ public LinkedDataFragmentRequestBase( final String fragmentURL, this.fragmentURL = fragmentURL; this.datasetURL = datasetURL; this.pageNumberWasRequested = pageNumberWasRequested; - this.pageNumber = pageNumber; + this.pageNumber = (pageNumberWasRequested) ? pageNumber : 1L; } @Override @@ -40,11 +40,8 @@ public boolean isPageRequest() { } @Override - public long getPageNumber() throws UnsupportedOperationException { - if ( pageNumberWasRequested ) - return pageNumber; - else - throw new UnsupportedOperationException(); + public long getPageNumber() { + return pageNumber; } @Override From e328519cf71e9a55fc2d32d98b38981b71164c1a Mon Sep 17 00:00:00 2001 From: Olaf Hartig Date: Fri, 25 Dec 2015 17:28:06 +0100 Subject: [PATCH 02/12] added TriplePatternElement as a generic, API-independent interface tp represent elements of triple patterns; plus a generic factory for possible TriplePatternElement objects --- .../fragments/tpf/TriplePatternElement.java | 49 +++++++++++++++ .../tpf/TriplePatternElementFactory.java | 63 +++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 src/org/linkeddatafragments/fragments/tpf/TriplePatternElement.java create mode 100644 src/org/linkeddatafragments/fragments/tpf/TriplePatternElementFactory.java diff --git a/src/org/linkeddatafragments/fragments/tpf/TriplePatternElement.java b/src/org/linkeddatafragments/fragments/tpf/TriplePatternElement.java new file mode 100644 index 0000000..55f0163 --- /dev/null +++ b/src/org/linkeddatafragments/fragments/tpf/TriplePatternElement.java @@ -0,0 +1,49 @@ +package org.linkeddatafragments.fragments.tpf; + +/** + * Represents an element of a triple pattern (i.e., subject, predicate, object). + * + * @param type for representing RDF terms in triple patterns + * @param type for representing specific variables in triple patterns + * + * @author Olaf Hartig + */ +public interface TriplePatternElement +{ + /** + * Returns true if this element is a variable (named or unnamed). + */ + boolean isVariable(); + + /** + * Returns true if this element is a specific variable, and false if either + * it is not a variable but an RDF term or it is some variable that is not + * specified. The latter (unspecified variables) is possible because when + * a client requests a triple pattern fragment, it may omit triple pattern + * related parameters. + * + * If this element is a specific variable (that is, this method returns + * true), this specific variable can be obtained by {@link #asVariable()}. + */ + boolean isSpecificVariable(); + + /** + * Returns a representation of this element as a specific variable (assuming + * it is a specific variable). + * + * @throws UnsupportedOperationException + * If this element is not a specific variable (i.e., + * if {@link #isSpecificVariable()} returns false). + */ + VarType asVariable() throws UnsupportedOperationException; + + /** + * Returns a representation of this element as an RDF term (assuming it is + * an RDF term and not a variable). + * + * @throws UnsupportedOperationException + * If this element is not an RDF term but a variable + * (i.e., if {@link #isVariable()} returns true). + */ + TermType asTerm() throws UnsupportedOperationException; +} diff --git a/src/org/linkeddatafragments/fragments/tpf/TriplePatternElementFactory.java b/src/org/linkeddatafragments/fragments/tpf/TriplePatternElementFactory.java new file mode 100644 index 0000000..aff548c --- /dev/null +++ b/src/org/linkeddatafragments/fragments/tpf/TriplePatternElementFactory.java @@ -0,0 +1,63 @@ +package org.linkeddatafragments.fragments.tpf; + +/** + * A factory for {@link TriplePatternElement}s. + * + * @param type for representing RDF terms in triple patterns + * @param type for representing specific variables in triple patterns + * + * @author Olaf Hartig + */ +public class TriplePatternElementFactory +{ + public TriplePatternElement createUnspecifiedVariable() { + return new UnspecifiedVariable(); + } + + public TriplePatternElement createSpecificVariable( + final VarType variable ) { + return new SpecificVariable( variable ); + } + public TriplePatternElement createRDFTerm( + final TermType term ) { + return new RDFTerm( term ); + } + + static abstract public class Variable + implements TriplePatternElement + { + public boolean isVariable() { return true; } + public TermType asTerm() { throw new UnsupportedOperationException(); } + } + + static public class UnspecifiedVariable + extends Variable + { + public boolean isSpecificVariable() { return false; } + public VarType asVariable() { throw new UnsupportedOperationException(); } + public String toString() { return "UnspecifiedVariable"; } + } + + static public class SpecificVariable + extends Variable + { + protected final VarType v; + public SpecificVariable( final VarType variable ) { v = variable; } + public boolean isSpecificVariable() { return true; } + public VarType asVariable() { return v; } + public String toString() { return "SpecificVariable(" + v.toString() + ")"; } + } + + static public class RDFTerm + implements TriplePatternElement + { + protected final TermType t; + public RDFTerm( final TermType term ) { t = term; } + public boolean isVariable() { return false; } + public boolean isSpecificVariable() { return false; } + public VarType asVariable() { throw new UnsupportedOperationException(); } + public TermType asTerm() { return t; } + public String toString() { return "RDFTerm(" + t.toString() + ")(type: " + t.getClass().getSimpleName() + ")"; } + } + +} From 05e6a1bfea2d01cd549b6c57399cf698753f847e Mon Sep 17 00:00:00 2001 From: Olaf Hartig Date: Fri, 25 Dec 2015 17:30:22 +0100 Subject: [PATCH 03/12] code to parse HTTP request parameters into triple pattern elements is now partially generic (API-independent) and has been moved to separate parser classes --- .../util/RDFTermParser.java | 75 +++++++++++++++++++ .../util/TriplePatternElementParser.java | 54 +++++++++++++ .../TriplePatternElementParserForJena.java | 73 ++++++++++++++++++ 3 files changed, 202 insertions(+) create mode 100644 src/org/linkeddatafragments/util/RDFTermParser.java create mode 100644 src/org/linkeddatafragments/util/TriplePatternElementParser.java create mode 100644 src/org/linkeddatafragments/util/TriplePatternElementParserForJena.java diff --git a/src/org/linkeddatafragments/util/RDFTermParser.java b/src/org/linkeddatafragments/util/RDFTermParser.java new file mode 100644 index 0000000..ea56524 --- /dev/null +++ b/src/org/linkeddatafragments/util/RDFTermParser.java @@ -0,0 +1,75 @@ +package org.linkeddatafragments.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Parses strings (as obtained from HTTP request parameters) into RDF terms. + * + * @param type for representing RDF terms + * + * @author Olaf Hartig + */ +abstract public class RDFTermParser +{ + public static final Pattern STRINGPATTERN + = Pattern.compile("^\"(.*)\"(?:@(.*)|\\^\\^]*)>?)?$"); + + public TermType parseIntoRDFNode( final String param ) + { + if ( param == null || param.isEmpty() ) + return handleUnparsableParameter( param ); + + // identify the kind of RDF term based on the first character + char firstChar = param.charAt(0); + switch ( firstChar ) + { + // blank node + case '_': + return createBlankNode( param ); + + // angular brackets indicate a URI + case '<': + return createURI( param.substring(1, param.length()-1) ); + + // quotes indicate a string + case '"': + Matcher matcher = STRINGPATTERN.matcher( param ); + if ( matcher.matches() ) { + String label = matcher.group(1); + String langTag = matcher.group(2); + String typeURI = matcher.group(3); + + if ( langTag != null ) + return createLanguageLiteral( label, langTag ); + + else if ( typeURI != null ) + return createTypedLiteral( label, typeURI ); + + else + return createPlainLiteral( label ); + } + else + return handleUnparsableParameter( param ); + + // assume it is a URI without angular brackets + default: + return createURI( param ); + } + } + + abstract public TermType createBlankNode( final String label ); + + abstract public TermType createURI( final String uri ); + + abstract public TermType createTypedLiteral( final String label, + final String typeURI ); + + abstract public TermType createLanguageLiteral( final String label, + final String langTag ); + + abstract public TermType createPlainLiteral( final String label ); + + abstract public TermType handleUnparsableParameter( final String param ); + +} diff --git a/src/org/linkeddatafragments/util/TriplePatternElementParser.java b/src/org/linkeddatafragments/util/TriplePatternElementParser.java new file mode 100644 index 0000000..ecbb2e3 --- /dev/null +++ b/src/org/linkeddatafragments/util/TriplePatternElementParser.java @@ -0,0 +1,54 @@ +package org.linkeddatafragments.util; + +import org.linkeddatafragments.fragments.tpf.TriplePatternElement; +import org.linkeddatafragments.fragments.tpf.TriplePatternElementFactory; + +/** + * Parses strings (as obtained from HTTP request parameters) into + * {@link TriplePatternElement}s. + * + * @param type for representing RDF terms + * @param type for representing specific variables + * + * @author Olaf Hartig + * @author Ruben Verborgh + */ +abstract public class TriplePatternElementParser + extends RDFTermParser +{ + public final TriplePatternElementFactory factory = + new TriplePatternElementFactory(); + + public TriplePatternElement + parseIntoTriplePatternElement( final String param ) + { + // nothing or empty indicates an unspecified variable + if ( param == null || param.isEmpty() ) + return factory.createUnspecifiedVariable(); + + // identify the kind of RDF term based on the first character + char firstChar = param.charAt(0); + switch ( firstChar ) + { + // specific variable + case '?': + { + final String varName = param.substring(1); + final VarType var = createSpecificVariable( varName ); + return factory.createSpecificVariable( var ); + } + + // blank node indicates an unspecified variable + case '_': + { + return factory.createUnspecifiedVariable(); + } + + // assume it is an RDF term + default: + return factory.createRDFTerm( parseIntoRDFNode(param) ); + } + } + + abstract public VarType createSpecificVariable( final String varName ); +} diff --git a/src/org/linkeddatafragments/util/TriplePatternElementParserForJena.java b/src/org/linkeddatafragments/util/TriplePatternElementParserForJena.java new file mode 100644 index 0000000..41dd83c --- /dev/null +++ b/src/org/linkeddatafragments/util/TriplePatternElementParserForJena.java @@ -0,0 +1,73 @@ +package org.linkeddatafragments.util; + +import com.hp.hpl.jena.datatypes.RDFDatatype; +import com.hp.hpl.jena.datatypes.TypeMapper; +import com.hp.hpl.jena.rdf.model.RDFNode; +import com.hp.hpl.jena.rdf.model.ResourceFactory; + +/** + * A {@link TriplePatternElementParser} for Jena-based backends. + * + * @author Olaf Hartig + */ +public class TriplePatternElementParserForJena + extends TriplePatternElementParser +{ + private static TriplePatternElementParserForJena instance = null; + + public static TriplePatternElementParserForJena getInstance() + { + if ( instance == null ) { + instance = new TriplePatternElementParserForJena(); + } + return instance; + } + + protected TriplePatternElementParserForJena() {} + + @Override + public String createSpecificVariable( final String varName ) + { + return varName; + } + + @Override + public RDFNode createBlankNode( final String label ) + { + return ResourceFactory.createResource(); + } + + @Override + public RDFNode createURI( final String uri ) + { + return ResourceFactory.createResource( uri ); + } + + @Override + public RDFNode createTypedLiteral( final String label, + final String typeURI ) + { + final RDFDatatype dt = TypeMapper.getInstance() + .getSafeTypeByName( typeURI ); + return ResourceFactory.createTypedLiteral( label, dt ); + } + + @Override + public RDFNode createLanguageLiteral( final String label, + final String languageTag ) + { + return ResourceFactory.createLangLiteral( label, languageTag ); + } + + @Override + public RDFNode createPlainLiteral( final String label ) + { + return ResourceFactory.createPlainLiteral( label ); + } + + @Override + public RDFNode handleUnparsableParameter( final String parameter ) + { + return CommonResources.INVALID_URI; + } +} From 2d522096320980acb7c93716d26643fb19a5a119 Mon Sep 17 00:00:00 2001 From: Olaf Hartig Date: Fri, 25 Dec 2015 17:36:04 +0100 Subject: [PATCH 04/12] changed interface TriplePatternFragmentRequest to use the new generic TriplePatternElement interface for subject, predicate, and object. --- .../tpf/TriplePatternFragmentRequest.java | 24 ++++++------ .../tpf/TriplePatternFragmentRequestImpl.java | 37 ++++++++++++------- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/src/org/linkeddatafragments/fragments/tpf/TriplePatternFragmentRequest.java b/src/org/linkeddatafragments/fragments/tpf/TriplePatternFragmentRequest.java index d64f8fe..85154f7 100644 --- a/src/org/linkeddatafragments/fragments/tpf/TriplePatternFragmentRequest.java +++ b/src/org/linkeddatafragments/fragments/tpf/TriplePatternFragmentRequest.java @@ -5,32 +5,30 @@ /** * Represents a request of a Triple Pattern Fragment (TPF). * + * @param type for representing RDF terms in triple patterns + * @param type for representing specific variables in triple patterns + * * @author Olaf Hartig */ -public interface TriplePatternFragmentRequest extends LinkedDataFragmentRequest +public interface TriplePatternFragmentRequest + extends LinkedDataFragmentRequest { public final static String PARAMETERNAME_SUBJ = "subject"; public final static String PARAMETERNAME_PRED = "predicate"; public final static String PARAMETERNAME_OBJ = "object"; /** - * Returns the subject position of the requested triple pattern (or null, - * in which case the requested triple pattern has an unnamed variable as - * subject). + * Returns the subject position of the requested triple pattern. */ - String getSubject(); + TriplePatternElement getSubject(); /** - * Returns the predicate position of the requested triple pattern (or null, - * in which case the requested triple pattern has an unnamed variable as - * predicate). + * Returns the predicate position of the requested triple pattern. */ - String getPredicate(); + TriplePatternElement getPredicate(); /** - * Returns the object position of the requested triple pattern (or null, - * in which case the requested triple pattern has an unnamed variable as - * object). + * Returns the object position of the requested triple pattern. */ - String getObject(); + TriplePatternElement getObject(); } diff --git a/src/org/linkeddatafragments/fragments/tpf/TriplePatternFragmentRequestImpl.java b/src/org/linkeddatafragments/fragments/tpf/TriplePatternFragmentRequestImpl.java index 3e1331f..c968212 100644 --- a/src/org/linkeddatafragments/fragments/tpf/TriplePatternFragmentRequestImpl.java +++ b/src/org/linkeddatafragments/fragments/tpf/TriplePatternFragmentRequestImpl.java @@ -7,41 +7,50 @@ * * @author Olaf Hartig */ -public class TriplePatternFragmentRequestImpl +public class TriplePatternFragmentRequestImpl extends LinkedDataFragmentRequestBase - implements TriplePatternFragmentRequest + implements TriplePatternFragmentRequest { - public final String subject; - public final String predicate; - public final String object; + public final TriplePatternElement subject; + public final TriplePatternElement predicate; + public final TriplePatternElement object; public TriplePatternFragmentRequestImpl( final String fragmentURL, final String datasetURL, final boolean pageNumberWasRequested, final long pageNumber, - final String subject, - final String predicate, - final String object ) + final TriplePatternElement subject, + final TriplePatternElement predicate, + final TriplePatternElement object ) { super( fragmentURL, datasetURL, pageNumberWasRequested, pageNumber ); + if ( subject == null ) + throw new IllegalArgumentException(); + + if ( predicate == null ) + throw new IllegalArgumentException(); + + if ( object == null ) + throw new IllegalArgumentException(); + this.subject = subject; this.predicate = predicate; this.object = object; } @Override - public String getSubject() { + public TriplePatternElement getSubject() { return subject; } @Override - public String getPredicate() { + public TriplePatternElement getPredicate() { return predicate; } @Override - public String getObject() { + public TriplePatternElement getObject() { return object; } @@ -50,9 +59,9 @@ public String toString() { return "TriplePatternFragmentRequest(" + "class: " + getClass().getName() + - ", subject: " + subject + - ", predicate: " + predicate + - ", object: " + object + + ", subject: " + subject.toString() + + ", predicate: " + predicate.toString() + + ", object: " + object.toString() + ", fragmentURL: " + fragmentURL + ", isPageRequest: " + pageNumberWasRequested + ", pageNumber: " + pageNumber + From 0ab596a6a6cea2b87ee48bdf3b090e1658222e61 Mon Sep 17 00:00:00 2001 From: Olaf Hartig Date: Fri, 25 Dec 2015 17:37:59 +0100 Subject: [PATCH 05/12] changed the request parser classes to use the new generic TriplePatternElement interface --- .../fragments/tpf/TPFRequestParser.java | 41 ++++++++++++++----- .../tpf/TPFRequestParserForJenaBackends.java | 29 +++++++++++++ 2 files changed, 60 insertions(+), 10 deletions(-) create mode 100644 src/org/linkeddatafragments/fragments/tpf/TPFRequestParserForJenaBackends.java diff --git a/src/org/linkeddatafragments/fragments/tpf/TPFRequestParser.java b/src/org/linkeddatafragments/fragments/tpf/TPFRequestParser.java index 2449b26..b03e7c8 100644 --- a/src/org/linkeddatafragments/fragments/tpf/TPFRequestParser.java +++ b/src/org/linkeddatafragments/fragments/tpf/TPFRequestParser.java @@ -6,14 +6,27 @@ import org.linkeddatafragments.fragments.FragmentRequestParserBase; import org.linkeddatafragments.fragments.IFragmentRequestParser; import org.linkeddatafragments.fragments.LinkedDataFragmentRequest; +import org.linkeddatafragments.util.TriplePatternElementParser; /** * An {@link IFragmentRequestParser} for {@link TriplePatternFragmentRequest}s. * + * @param type for representing RDF terms in triple patterns + * @param type for representing specific variables in triple patterns + * * @author Olaf Hartig */ -public class TPFRequestParser extends FragmentRequestParserBase +public class TPFRequestParser + extends FragmentRequestParserBase { + public final TriplePatternElementParser elmtParser; + + public TPFRequestParser( + final TriplePatternElementParser elmtParser ) + { + this.elmtParser = elmtParser; + } + @Override protected Worker getWorker( final HttpServletRequest httpRequest, final ConfigReader config ) @@ -22,8 +35,7 @@ protected Worker getWorker( final HttpServletRequest httpRequest, return new Worker( httpRequest, config ); } - - static protected class Worker extends FragmentRequestParserBase.Worker + protected class Worker extends FragmentRequestParserBase.Worker { public Worker( final HttpServletRequest request, final ConfigReader config ) @@ -31,10 +43,12 @@ public Worker( final HttpServletRequest request, super( request, config ); } + @Override public LinkedDataFragmentRequest createFragmentRequest() throws IllegalArgumentException { - return new TriplePatternFragmentRequestImpl( getFragmentURL(), + return new TriplePatternFragmentRequestImpl( + getFragmentURL(), getDatasetURL(), pageNumberWasRequested, pageNumber, @@ -43,21 +57,28 @@ public LinkedDataFragmentRequest createFragmentRequest() getObject() ); } - public String getSubject() { - return request.getParameter( + public TriplePatternElement getSubject() { + return getParameterAsTriplePatternElement( TriplePatternFragmentRequest.PARAMETERNAME_SUBJ ); } - public String getPredicate() { - return request.getParameter( + public TriplePatternElement getPredicate() { + return getParameterAsTriplePatternElement( TriplePatternFragmentRequest.PARAMETERNAME_PRED ); } - public String getObject() { - return request.getParameter( + public TriplePatternElement getObject() { + return getParameterAsTriplePatternElement( TriplePatternFragmentRequest.PARAMETERNAME_OBJ ); } + public TriplePatternElement + getParameterAsTriplePatternElement( final String paramName ) + { + final String parameter = request.getParameter( paramName ); + return elmtParser.parseIntoTriplePatternElement( parameter ); + } + } // end of class Worker } diff --git a/src/org/linkeddatafragments/fragments/tpf/TPFRequestParserForJenaBackends.java b/src/org/linkeddatafragments/fragments/tpf/TPFRequestParserForJenaBackends.java new file mode 100644 index 0000000..ee5f707 --- /dev/null +++ b/src/org/linkeddatafragments/fragments/tpf/TPFRequestParserForJenaBackends.java @@ -0,0 +1,29 @@ +package org.linkeddatafragments.fragments.tpf; + +import com.hp.hpl.jena.rdf.model.RDFNode; + +import org.linkeddatafragments.util.TriplePatternElementParserForJena; + +/** + * An {@link TPFRequestParser} for Jena-based backends. + * + * @author Olaf Hartig + */ +public class TPFRequestParserForJenaBackends + extends TPFRequestParser +{ + private static TPFRequestParserForJenaBackends instance = null; + + public static TPFRequestParserForJenaBackends getInstance() + { + if ( instance == null ) { + instance = new TPFRequestParserForJenaBackends(); + } + return instance; + } + + protected TPFRequestParserForJenaBackends() + { + super( TriplePatternElementParserForJena.getInstance() ); + } +} From be6576859ec30b47f23b76e32728a2b0d5ef0249 Mon Sep 17 00:00:00 2001 From: Olaf Hartig Date: Fri, 25 Dec 2015 17:39:19 +0100 Subject: [PATCH 06/12] changed the request processor classes to use the new generic TriplePatternElement interface --- ...ractRequestProcessorForTriplePatterns.java | 57 +++++++++++-------- .../hdt/HdtBasedRequestProcessorForTPFs.java | 38 +++++++------ .../index/IndexRequestProcessorForTPFs.java | 38 +++++++++---- .../JenaTDBBasedRequestProcessorForTPFs.java | 44 +++++++------- 4 files changed, 106 insertions(+), 71 deletions(-) diff --git a/src/org/linkeddatafragments/datasource/AbstractRequestProcessorForTriplePatterns.java b/src/org/linkeddatafragments/datasource/AbstractRequestProcessorForTriplePatterns.java index 36cff95..9ba984a 100644 --- a/src/org/linkeddatafragments/datasource/AbstractRequestProcessorForTriplePatterns.java +++ b/src/org/linkeddatafragments/datasource/AbstractRequestProcessorForTriplePatterns.java @@ -1,41 +1,52 @@ package org.linkeddatafragments.datasource; +import com.hp.hpl.jena.rdf.model.Model; + import org.linkeddatafragments.fragments.LinkedDataFragment; import org.linkeddatafragments.fragments.LinkedDataFragmentRequest; +import org.linkeddatafragments.fragments.tpf.TriplePatternElement; import org.linkeddatafragments.fragments.tpf.TriplePatternFragment; import org.linkeddatafragments.fragments.tpf.TriplePatternFragmentImpl; import org.linkeddatafragments.fragments.tpf.TriplePatternFragmentRequest; -import com.hp.hpl.jena.rdf.model.Model; - /** * Base class for implementations of {@link IFragmentRequestProcessor} that * process {@link TriplePatternFragmentRequest}s. * + * @param type for representing RDF terms in triple patterns + * @param type for representing specific variables in triple patterns + * * @author Olaf Hartig */ -public abstract class AbstractRequestProcessorForTriplePatterns - extends AbstractRequestProcessor +public abstract class + AbstractRequestProcessorForTriplePatterns + extends AbstractRequestProcessor { @Override - protected Worker getWorker( final LinkedDataFragmentRequest request ) + protected final Worker getWorker( + final LinkedDataFragmentRequest request ) throws IllegalArgumentException { - if ( request instanceof TriplePatternFragmentRequest ) - return getWorker( (TriplePatternFragmentRequest) request ); + if ( request instanceof TriplePatternFragmentRequest ) { + @SuppressWarnings("unchecked") + final TriplePatternFragmentRequest tpfRequest = + (TriplePatternFragmentRequest) request; + return getTPFSpecificWorker( tpfRequest ); + } else throw new IllegalArgumentException( request.getClass().getName() ); } - abstract protected Worker getWorker( - final TriplePatternFragmentRequest request ) + abstract protected Worker getTPFSpecificWorker( + final TriplePatternFragmentRequest request ) throws IllegalArgumentException; - abstract static protected class Worker + abstract static protected class Worker extends AbstractRequestProcessor.Worker { - public Worker( final TriplePatternFragmentRequest request ) + public Worker( + final TriplePatternFragmentRequest request ) { super( request ); } @@ -51,8 +62,9 @@ public LinkedDataFragment createRequestedFragment() else offset = 0L; - final TriplePatternFragmentRequest tpfRequest = - (TriplePatternFragmentRequest) request; + @SuppressWarnings("unchecked") + final TriplePatternFragmentRequest tpfRequest = + (TriplePatternFragmentRequest) request; return createFragment( tpfRequest.getSubject(), tpfRequest.getPredicate(), @@ -60,11 +72,12 @@ public LinkedDataFragment createRequestedFragment() offset, limit ); } - abstract protected LinkedDataFragment createFragment( final String subj, - final String pred, - final String obj, - final long offset, - final long limit ) + abstract protected LinkedDataFragment createFragment( + final TriplePatternElement subj, + final TriplePatternElement pred, + final TriplePatternElement obj, + final long offset, + final long limit ) throws IllegalArgumentException; protected TriplePatternFragment createEmptyTriplePatternFragment() @@ -78,17 +91,11 @@ protected TriplePatternFragment createTriplePatternFragment( final long totalSize, final boolean isLastPage ) { - final long pageNumber; - if ( request.isPageRequest() ) - pageNumber = request.getPageNumber(); - else - pageNumber = 1L; - return new TriplePatternFragmentImpl( triples, totalSize, request.getFragmentURL(), request.getDatasetURL(), - pageNumber, + request.getPageNumber(), isLastPage ); } diff --git a/src/org/linkeddatafragments/datasource/hdt/HdtBasedRequestProcessorForTPFs.java b/src/org/linkeddatafragments/datasource/hdt/HdtBasedRequestProcessorForTPFs.java index 7eff94f..cd029fe 100644 --- a/src/org/linkeddatafragments/datasource/hdt/HdtBasedRequestProcessorForTPFs.java +++ b/src/org/linkeddatafragments/datasource/hdt/HdtBasedRequestProcessorForTPFs.java @@ -2,9 +2,10 @@ import java.io.IOException; -import org.linkeddatafragments.datasource.AbstractJenaBasedRequestProcessorForTriplePatterns; +import org.linkeddatafragments.datasource.AbstractRequestProcessorForTriplePatterns; import org.linkeddatafragments.datasource.IFragmentRequestProcessor; import org.linkeddatafragments.fragments.LinkedDataFragment; +import org.linkeddatafragments.fragments.tpf.TriplePatternElement; import org.linkeddatafragments.fragments.tpf.TriplePatternFragmentRequest; import org.rdfhdt.hdt.enums.TripleComponentRole; import org.rdfhdt.hdt.hdt.HDT; @@ -16,9 +17,7 @@ import com.hp.hpl.jena.graph.Triple; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; -import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.RDFNode; -import com.hp.hpl.jena.rdf.model.Resource; /** * Implementation of {@link IFragmentRequestProcessor} that processes @@ -28,7 +27,7 @@ * @author Olaf Hartig */ public class HdtBasedRequestProcessorForTPFs - extends AbstractJenaBasedRequestProcessorForTriplePatterns + extends AbstractRequestProcessorForTriplePatterns { protected final HDT datasource; protected final NodeDictionary dictionary; @@ -46,7 +45,8 @@ public HdtBasedRequestProcessorForTPFs( String hdtFile ) throws IOException } @Override - protected Worker getWorker( final TriplePatternFragmentRequest request ) + protected Worker getTPFSpecificWorker( + final TriplePatternFragmentRequest request ) throws IllegalArgumentException { return new Worker( request ); @@ -54,23 +54,29 @@ protected Worker getWorker( final TriplePatternFragmentRequest request ) protected class Worker - extends AbstractJenaBasedRequestProcessorForTriplePatterns.Worker + extends AbstractRequestProcessorForTriplePatterns.Worker { - public Worker( final TriplePatternFragmentRequest request ) { - super( request ); + public Worker( final TriplePatternFragmentRequest req ) + { + super( req ); } @Override - protected LinkedDataFragment createFragment( final Resource subject, - final Property predicate, - final RDFNode object, - final long offset, - final long limit ) + protected LinkedDataFragment createFragment( + final TriplePatternElement subject, + final TriplePatternElement predicate, + final TriplePatternElement object, + final long offset, + final long limit ) { + // FIXME: The following algorithm is incorrect for cases in which + // the requested triple pattern contains a specific variable + // multiple times (e.g., ?x foaf:knows ?x ). + // 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); + int subjectId = subject.isVariable() ? 0 : dictionary.getIntID(subject.asTerm().asNode(), TripleComponentRole.SUBJECT); + int predicateId = predicate.isVariable() ? 0 : dictionary.getIntID(predicate.asTerm().asNode(), TripleComponentRole.PREDICATE); + int objectId = object.isVariable() ? 0 : dictionary.getIntID(object.asTerm().asNode(), TripleComponentRole.OBJECT); if (subjectId < 0 || predicateId < 0 || objectId < 0) { return createEmptyTriplePatternFragment(); diff --git a/src/org/linkeddatafragments/datasource/index/IndexRequestProcessorForTPFs.java b/src/org/linkeddatafragments/datasource/index/IndexRequestProcessorForTPFs.java index b9087e0..fd56526 100644 --- a/src/org/linkeddatafragments/datasource/index/IndexRequestProcessorForTPFs.java +++ b/src/org/linkeddatafragments/datasource/index/IndexRequestProcessorForTPFs.java @@ -5,16 +5,18 @@ 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.rdf.model.StmtIterator; import com.hp.hpl.jena.rdf.model.impl.PropertyImpl; import com.hp.hpl.jena.rdf.model.impl.ResourceImpl; import java.util.HashMap; import java.util.Map; -import org.linkeddatafragments.datasource.AbstractJenaBasedRequestProcessorForTriplePatterns; +import org.linkeddatafragments.datasource.AbstractRequestProcessorForTriplePatterns; import org.linkeddatafragments.datasource.IDataSource; import org.linkeddatafragments.datasource.IFragmentRequestProcessor; import org.linkeddatafragments.fragments.LinkedDataFragment; +import org.linkeddatafragments.fragments.tpf.TriplePatternElement; import org.linkeddatafragments.fragments.tpf.TriplePatternFragmentRequest; /** @@ -26,7 +28,7 @@ * @author Olaf Hartig */ public class IndexRequestProcessorForTPFs - extends AbstractJenaBasedRequestProcessorForTriplePatterns + extends AbstractRequestProcessorForTriplePatterns { final static String RDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; final static String RDFS = "http://www.w3.org/2000/01/rdf-schema#"; @@ -55,7 +57,8 @@ public IndexRequestProcessorForTPFs( } @Override - protected Worker getWorker( final TriplePatternFragmentRequest request ) + protected Worker getTPFSpecificWorker( + final TriplePatternFragmentRequest request ) throws IllegalArgumentException { return new Worker( request ); @@ -63,19 +66,32 @@ protected Worker getWorker( final TriplePatternFragmentRequest request ) protected class Worker - extends AbstractJenaBasedRequestProcessorForTriplePatterns.Worker + extends AbstractRequestProcessorForTriplePatterns.Worker { - public Worker( final TriplePatternFragmentRequest request ) { - super( request ); + public Worker( final TriplePatternFragmentRequest req ) + { + super( req ); } @Override - protected LinkedDataFragment createFragment( final Resource subject, - final Property predicate, - final RDFNode object, - final long offset, - final long limit ) + protected LinkedDataFragment createFragment( + final TriplePatternElement s, + final TriplePatternElement p, + final TriplePatternElement o, + final long offset, + final long limit ) { + // FIXME: The following algorithm is incorrect for cases in which + // the requested triple pattern contains a specific variable + // multiple times (e.g., ?x foaf:knows ?x ). + + final Resource subject = s.isVariable() ? null + : s.asTerm().asResource(); + final Property predicate = p.isVariable() ? null + : ResourceFactory.createProperty(p.asTerm().asResource().getURI()); + final RDFNode object = o.isVariable() ? null + : o.asTerm(); + StmtIterator listStatements = model.listStatements(subject, predicate, object); Model result = ModelFactory.createDefaultModel(); diff --git a/src/org/linkeddatafragments/datasource/tdb/JenaTDBBasedRequestProcessorForTPFs.java b/src/org/linkeddatafragments/datasource/tdb/JenaTDBBasedRequestProcessorForTPFs.java index 0360ddc..8aad998 100644 --- a/src/org/linkeddatafragments/datasource/tdb/JenaTDBBasedRequestProcessorForTPFs.java +++ b/src/org/linkeddatafragments/datasource/tdb/JenaTDBBasedRequestProcessorForTPFs.java @@ -12,15 +12,14 @@ import com.hp.hpl.jena.rdf.model.Literal; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; -import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.RDFNode; -import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.tdb.TDBFactory; import java.io.File; -import org.linkeddatafragments.datasource.AbstractJenaBasedRequestProcessorForTriplePatterns; +import org.linkeddatafragments.datasource.AbstractRequestProcessorForTriplePatterns; import org.linkeddatafragments.datasource.IFragmentRequestProcessor; import org.linkeddatafragments.fragments.LinkedDataFragment; +import org.linkeddatafragments.fragments.tpf.TriplePatternElement; import org.linkeddatafragments.fragments.tpf.TriplePatternFragmentRequest; /** @@ -31,7 +30,7 @@ * @author Olaf Hartig */ public class JenaTDBBasedRequestProcessorForTPFs - extends AbstractJenaBasedRequestProcessorForTriplePatterns + extends AbstractRequestProcessorForTriplePatterns { private final Dataset tdb; private final String sparql = "CONSTRUCT WHERE { ?s ?p ?o } " + @@ -43,7 +42,8 @@ public class JenaTDBBasedRequestProcessorForTPFs private final Query countQuery = QueryFactory.create(count, Syntax.syntaxSPARQL_11); @Override - protected Worker getWorker( final TriplePatternFragmentRequest request ) + protected Worker getTPFSpecificWorker( + final TriplePatternFragmentRequest request ) throws IllegalArgumentException { return new Worker( request ); @@ -51,29 +51,35 @@ protected Worker getWorker( final TriplePatternFragmentRequest request ) protected class Worker - extends AbstractJenaBasedRequestProcessorForTriplePatterns.Worker + extends AbstractRequestProcessorForTriplePatterns.Worker { - public Worker( final TriplePatternFragmentRequest request ) { - super( request ); + public Worker( final TriplePatternFragmentRequest req ) + { + super( req ); } @Override - protected LinkedDataFragment createFragment( final Resource subject, - final Property predicate, - final RDFNode object, - final long offset, - final long limit ) + protected LinkedDataFragment createFragment( + final TriplePatternElement subject, + final TriplePatternElement predicate, + final TriplePatternElement object, + final long offset, + final long limit ) { + // FIXME: The following algorithm is incorrect for cases in which + // the requested triple pattern contains a specific variable + // multiple times (e.g., ?x foaf:knows ?x ). + Model model = tdb.getDefaultModel(); QuerySolutionMap map = new QuerySolutionMap(); - if (subject != null) { - map.add("s", subject); + if ( ! subject.isVariable() ) { + map.add("s", subject.asTerm()); } - if (predicate != null) { - map.add("p", predicate); + if ( ! predicate.isVariable() ) { + map.add("p", predicate.asTerm()); } - if (object != null) { - map.add("o", object); + if ( ! object.isVariable() ) { + map.add("o", object.asTerm()); } query.setOffset(offset); From 12329649c86c1619b494e4fd26532ce768b786eb Mon Sep 17 00:00:00 2001 From: Olaf Hartig Date: Fri, 25 Dec 2015 17:41:49 +0100 Subject: [PATCH 07/12] the DataSource classes have to return their API-specific request parser now --- .../datasource/DataSource.java | 18 ------------------ .../datasource/hdt/HdtDataSource.java | 8 ++++++++ .../datasource/index/IndexDataSource.java | 8 ++++++++ .../datasource/tdb/JenaTDBDataSource.java | 8 ++++++++ 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/org/linkeddatafragments/datasource/DataSource.java b/src/org/linkeddatafragments/datasource/DataSource.java index 63344bd..465c9a0 100644 --- a/src/org/linkeddatafragments/datasource/DataSource.java +++ b/src/org/linkeddatafragments/datasource/DataSource.java @@ -1,10 +1,5 @@ package org.linkeddatafragments.datasource; -import org.linkeddatafragments.fragments.IFragmentRequestParser; -import org.linkeddatafragments.fragments.LinkedDataFragmentRequest; -import org.linkeddatafragments.fragments.tpf.TPFRequestParser; -import org.linkeddatafragments.fragments.tpf.TriplePatternFragmentRequest; - /** * * @author mielvandersande @@ -29,19 +24,6 @@ public String getTitle() { return this.title; }; - /** - * This implementation assumes that requests are - * {@link TriplePatternFragmentRequest}s. - * - * Data sources for other types of {@link LinkedDataFragmentRequest}s must - * override this method accordingly. - */ - @Override - public IFragmentRequestParser getRequestParser() - { - return new TPFRequestParser(); - } - @Override public void close() {} } diff --git a/src/org/linkeddatafragments/datasource/hdt/HdtDataSource.java b/src/org/linkeddatafragments/datasource/hdt/HdtDataSource.java index 2b32c78..03d7e19 100644 --- a/src/org/linkeddatafragments/datasource/hdt/HdtDataSource.java +++ b/src/org/linkeddatafragments/datasource/hdt/HdtDataSource.java @@ -4,6 +4,8 @@ import org.linkeddatafragments.datasource.DataSource; import org.linkeddatafragments.datasource.IFragmentRequestProcessor; +import org.linkeddatafragments.fragments.IFragmentRequestParser; +import org.linkeddatafragments.fragments.tpf.TPFRequestParserForJenaBackends; /** * An HDT data source of Basic Linked Data Fragments. @@ -28,6 +30,12 @@ public HdtDataSource(String title, String description, String hdtFile) throws IO requestProcessor = new HdtBasedRequestProcessorForTPFs( hdtFile ); } + @Override + public IFragmentRequestParser getRequestParser() + { + return TPFRequestParserForJenaBackends.getInstance(); + } + @Override public IFragmentRequestProcessor getRequestProcessor() { diff --git a/src/org/linkeddatafragments/datasource/index/IndexDataSource.java b/src/org/linkeddatafragments/datasource/index/IndexDataSource.java index 70ffb0f..72f6267 100644 --- a/src/org/linkeddatafragments/datasource/index/IndexDataSource.java +++ b/src/org/linkeddatafragments/datasource/index/IndexDataSource.java @@ -5,6 +5,8 @@ import org.linkeddatafragments.datasource.DataSource; import org.linkeddatafragments.datasource.IDataSource; import org.linkeddatafragments.datasource.IFragmentRequestProcessor; +import org.linkeddatafragments.fragments.IFragmentRequestParser; +import org.linkeddatafragments.fragments.tpf.TPFRequestParserForJenaBackends; /** * An Index data source provides an overview of all available datasets. @@ -21,6 +23,12 @@ public IndexDataSource(String baseUrl, HashMap datasources) requestProcessor = new IndexRequestProcessorForTPFs( baseUrl, datasources ); } + @Override + public IFragmentRequestParser getRequestParser() + { + return TPFRequestParserForJenaBackends.getInstance(); + } + @Override public IFragmentRequestProcessor getRequestProcessor() { diff --git a/src/org/linkeddatafragments/datasource/tdb/JenaTDBDataSource.java b/src/org/linkeddatafragments/datasource/tdb/JenaTDBDataSource.java index a08473a..698a644 100644 --- a/src/org/linkeddatafragments/datasource/tdb/JenaTDBDataSource.java +++ b/src/org/linkeddatafragments/datasource/tdb/JenaTDBDataSource.java @@ -4,6 +4,8 @@ import org.linkeddatafragments.datasource.DataSource; import org.linkeddatafragments.datasource.IFragmentRequestProcessor; +import org.linkeddatafragments.fragments.IFragmentRequestParser; +import org.linkeddatafragments.fragments.tpf.TPFRequestParserForJenaBackends; /** * Experimental Jena TDB-backed data source of Basic Linked Data Fragments. @@ -15,6 +17,12 @@ public class JenaTDBDataSource extends DataSource { protected final JenaTDBBasedRequestProcessorForTPFs requestProcessor; + @Override + public IFragmentRequestParser getRequestParser() + { + return TPFRequestParserForJenaBackends.getInstance(); + } + @Override public IFragmentRequestProcessor getRequestProcessor() { From a66e35440c57950edecbc673332ec54f58fc4aba Mon Sep 17 00:00:00 2001 From: Olaf Hartig Date: Fri, 25 Dec 2015 17:42:58 +0100 Subject: [PATCH 08/12] adapted the unit tests to the latest changes --- .../datasource/DataSourceTest.java | 48 +++++++++++++------ .../datasource/HdtDataSourceTest.java | 12 ++++- .../datasource/JenaTDBDataSourceTest.java | 12 ++++- 3 files changed, 56 insertions(+), 16 deletions(-) diff --git a/src/test/java/org/linkeddatafragments/datasource/DataSourceTest.java b/src/test/java/org/linkeddatafragments/datasource/DataSourceTest.java index 489611a..81c3589 100644 --- a/src/test/java/org/linkeddatafragments/datasource/DataSourceTest.java +++ b/src/test/java/org/linkeddatafragments/datasource/DataSourceTest.java @@ -15,15 +15,18 @@ import org.linkeddatafragments.datasource.IDataSource; import org.linkeddatafragments.datasource.IFragmentRequestProcessor; import org.linkeddatafragments.fragments.LinkedDataFragment; +import org.linkeddatafragments.fragments.tpf.TriplePatternElement; import org.linkeddatafragments.fragments.tpf.TriplePatternFragment; import org.linkeddatafragments.fragments.tpf.TriplePatternFragmentRequest; +import org.linkeddatafragments.fragments.tpf.TriplePatternFragmentRequestImpl; +import org.linkeddatafragments.util.TriplePatternElementParser; /** * * @author Bart Hanssens */ -public abstract class DataSourceTest { +public abstract class DataSourceTest { private static IDataSource ds; /** @@ -43,6 +46,9 @@ public static IDataSource getDatasource() { public static void setDatasource(IDataSource ds) { DataSourceTest.ds = ds; } + + protected abstract TriplePatternElementParser + getTriplePatternElementParser(); /** * Copy the demo triple in the jar to a temp file. @@ -84,15 +90,18 @@ public static JsonObject createConfig(String title, String desc, String type) { */ @Test public void testEmpty() { - TriplePatternFragmentRequest request = new TriplePatternFragmentRequest() { - public boolean isPageRequest() { return true; } - public long getPageNumber() { return 1L; } - public String getFragmentURL() { return "http://example.org/f"; } - public String getDatasetURL() { return "http://example.org/"; } - public String getSubject() { return "http://nothing.ldf.org"; } - public String getPredicate() { return null; } - public String getObject() { return null; } - }; + final TriplePatternElementParser tpeParser = + getTriplePatternElementParser(); + + final TriplePatternFragmentRequest request = + new TriplePatternFragmentRequestImpl( + "http://example.org/f", // fragmentURL + "http://example.org/", // datasetURL, + true, // pageNumberWasRequested, + 1L, //pageNumber, + tpeParser.parseIntoTriplePatternElement("http://nothing.ldf.org"), // subject, + tpeParser.parseIntoTriplePatternElement(null), // predicate, + tpeParser.parseIntoTriplePatternElement(null) ); //object final IFragmentRequestProcessor proc = getDatasource().getRequestProcessor(); final LinkedDataFragment ldf = proc.createRequestedFragment( request ); @@ -109,14 +118,25 @@ public void testEmpty() { */ @Test public void testEstimate() { - TriplePatternFragmentRequest request = new TriplePatternFragmentRequest() { + final TriplePatternElementParser tpeParser = + getTriplePatternElementParser(); + + final TriplePatternFragmentRequest request = + new TriplePatternFragmentRequest() { public boolean isPageRequest() { return true; } public long getPageNumber() { return 1L; } public String getFragmentURL() { return "http://example.org/f"; } public String getDatasetURL() { return "http://example.org/"; } - public String getSubject() { return "http://data.gov.be/catalog/ckanvl"; } - public String getPredicate() { return null; } - public String getObject() { return null; } + + public TriplePatternElement getSubject() { + return tpeParser.parseIntoTriplePatternElement("http://data.gov.be/catalog/ckanvl"); + } + public TriplePatternElement getPredicate() { + return tpeParser.parseIntoTriplePatternElement(null); + } + public TriplePatternElement getObject() { + return tpeParser.parseIntoTriplePatternElement(null); + } }; final IFragmentRequestProcessor proc = getDatasource().getRequestProcessor(); diff --git a/src/test/java/org/linkeddatafragments/datasource/HdtDataSourceTest.java b/src/test/java/org/linkeddatafragments/datasource/HdtDataSourceTest.java index f9f7ef4..b2a48cb 100644 --- a/src/test/java/org/linkeddatafragments/datasource/HdtDataSourceTest.java +++ b/src/test/java/org/linkeddatafragments/datasource/HdtDataSourceTest.java @@ -1,6 +1,8 @@ package test.java.org.linkeddatafragments.datasource; import com.google.gson.JsonObject; +import com.hp.hpl.jena.rdf.model.RDFNode; + import java.io.File; import org.junit.After; import org.junit.AfterClass; @@ -8,6 +10,8 @@ import org.junit.BeforeClass; import org.linkeddatafragments.datasource.DataSourceFactory; import org.linkeddatafragments.datasource.hdt.HdtDataSourceType; +import org.linkeddatafragments.util.TriplePatternElementParser; +import org.linkeddatafragments.util.TriplePatternElementParserForJena; import org.rdfhdt.hdt.enums.RDFNotation; import org.rdfhdt.hdt.hdt.HDT; import org.rdfhdt.hdt.hdt.HDTManager; @@ -17,10 +21,16 @@ * * @author Bart Hanssens */ -public class HdtDataSourceTest extends DataSourceTest { +public class HdtDataSourceTest extends DataSourceTest { private static File hdtfile; + @Override + protected TriplePatternElementParser + getTriplePatternElementParser() + { + return TriplePatternElementParserForJena.getInstance(); + } @BeforeClass public static void setUpClass() throws Exception { diff --git a/src/test/java/org/linkeddatafragments/datasource/JenaTDBDataSourceTest.java b/src/test/java/org/linkeddatafragments/datasource/JenaTDBDataSourceTest.java index 00548b3..b114b40 100644 --- a/src/test/java/org/linkeddatafragments/datasource/JenaTDBDataSourceTest.java +++ b/src/test/java/org/linkeddatafragments/datasource/JenaTDBDataSourceTest.java @@ -4,6 +4,7 @@ import com.hp.hpl.jena.query.Dataset; import com.hp.hpl.jena.rdf.model.Model; +import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.tdb.TDBFactory; import java.io.File; @@ -20,14 +21,23 @@ import org.linkeddatafragments.datasource.DataSourceFactory; import org.linkeddatafragments.datasource.tdb.JenaTDBDataSourceType; +import org.linkeddatafragments.util.TriplePatternElementParser; +import org.linkeddatafragments.util.TriplePatternElementParserForJena; /** * * @author Bart Hanssens */ -public class JenaTDBDataSourceTest extends DataSourceTest { +public class JenaTDBDataSourceTest extends DataSourceTest { private static File jena; private static Dataset dataset; + + @Override + protected TriplePatternElementParser + getTriplePatternElementParser() + { + return TriplePatternElementParserForJena.getInstance(); + } @BeforeClass public static void setUpClass() throws Exception { From 7c5db60b3afa93a96a96dd864563a71176197188 Mon Sep 17 00:00:00 2001 From: Olaf Hartig Date: Fri, 25 Dec 2015 18:00:31 +0100 Subject: [PATCH 09/12] extended FIXME comments to refer to the corresponding three bug reports: https://github.com/LinkedDataFragments/Server.Java/issues/23 https://github.com/LinkedDataFragments/Server.Java/issues/24 and https://github.com/LinkedDataFragments/Server.Java/issues/25 --- .../datasource/hdt/HdtBasedRequestProcessorForTPFs.java | 1 + .../datasource/index/IndexRequestProcessorForTPFs.java | 1 + .../datasource/tdb/JenaTDBBasedRequestProcessorForTPFs.java | 1 + 3 files changed, 3 insertions(+) diff --git a/src/org/linkeddatafragments/datasource/hdt/HdtBasedRequestProcessorForTPFs.java b/src/org/linkeddatafragments/datasource/hdt/HdtBasedRequestProcessorForTPFs.java index cd029fe..3ed8dbe 100644 --- a/src/org/linkeddatafragments/datasource/hdt/HdtBasedRequestProcessorForTPFs.java +++ b/src/org/linkeddatafragments/datasource/hdt/HdtBasedRequestProcessorForTPFs.java @@ -72,6 +72,7 @@ protected LinkedDataFragment createFragment( // FIXME: The following algorithm is incorrect for cases in which // the requested triple pattern contains a specific variable // multiple times (e.g., ?x foaf:knows ?x ). + // see https://github.com/LinkedDataFragments/Server.Java/issues/23 // look up the result from the HDT datasource) int subjectId = subject.isVariable() ? 0 : dictionary.getIntID(subject.asTerm().asNode(), TripleComponentRole.SUBJECT); diff --git a/src/org/linkeddatafragments/datasource/index/IndexRequestProcessorForTPFs.java b/src/org/linkeddatafragments/datasource/index/IndexRequestProcessorForTPFs.java index fd56526..8e4c6d4 100644 --- a/src/org/linkeddatafragments/datasource/index/IndexRequestProcessorForTPFs.java +++ b/src/org/linkeddatafragments/datasource/index/IndexRequestProcessorForTPFs.java @@ -84,6 +84,7 @@ protected LinkedDataFragment createFragment( // FIXME: The following algorithm is incorrect for cases in which // the requested triple pattern contains a specific variable // multiple times (e.g., ?x foaf:knows ?x ). + // see https://github.com/LinkedDataFragments/Server.Java/issues/25 final Resource subject = s.isVariable() ? null : s.asTerm().asResource(); diff --git a/src/org/linkeddatafragments/datasource/tdb/JenaTDBBasedRequestProcessorForTPFs.java b/src/org/linkeddatafragments/datasource/tdb/JenaTDBBasedRequestProcessorForTPFs.java index 8aad998..094183e 100644 --- a/src/org/linkeddatafragments/datasource/tdb/JenaTDBBasedRequestProcessorForTPFs.java +++ b/src/org/linkeddatafragments/datasource/tdb/JenaTDBBasedRequestProcessorForTPFs.java @@ -69,6 +69,7 @@ protected LinkedDataFragment createFragment( // FIXME: The following algorithm is incorrect for cases in which // the requested triple pattern contains a specific variable // multiple times (e.g., ?x foaf:knows ?x ). + // see https://github.com/LinkedDataFragments/Server.Java/issues/24 Model model = tdb.getDefaultModel(); QuerySolutionMap map = new QuerySolutionMap(); From fc14a7290842049316edd3af501e42719f749a31 Mon Sep 17 00:00:00 2001 From: Olaf Hartig Date: Fri, 25 Dec 2015 22:02:45 +0100 Subject: [PATCH 10/12] added the possibility to specify relevant IDataSourceType implementations in the config file --- config-example.json | 5 ++ .../config/ConfigReader.java | 48 +++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/config-example.json b/config-example.json index 4a5a721..11fcdf1 100644 --- a/config-example.json +++ b/config-example.json @@ -1,6 +1,11 @@ { "title": "My Linked Data Fragments server", + "datasourcetypes": { + "HdtDatasource" : "org.linkeddatafragments.datasource.hdt.HdtDataSourceType", + "JenaTDBDatasource" : "org.linkeddatafragments.datasource.tdb.JenaTDBDataSourceType" + }, + "datasources": { "dbpedia": { "title": "DBPedia", diff --git a/src/org/linkeddatafragments/config/ConfigReader.java b/src/org/linkeddatafragments/config/ConfigReader.java index a3240cc..7b2d99a 100644 --- a/src/org/linkeddatafragments/config/ConfigReader.java +++ b/src/org/linkeddatafragments/config/ConfigReader.java @@ -5,6 +5,8 @@ import java.util.Map; import java.util.Map.Entry; +import org.linkeddatafragments.datasource.IDataSourceType; + import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; @@ -13,8 +15,10 @@ * Reads the configuration of a Linked Data Fragments server. * * @author Ruben Verborgh + * @author Olaf Hartig */ public class ConfigReader { + private final Map dataSourceTypes = new HashMap<>(); private final Map dataSources = new HashMap<>(); private final Map prefixes = new HashMap<>(); private final String baseURL; @@ -28,6 +32,10 @@ public ConfigReader(Reader configReader) { JsonObject root = new JsonParser().parse(configReader).getAsJsonObject(); this.baseURL = root.has("baseURL") ? root.getAsJsonPrimitive("baseURL").getAsString() : null; + for (Entry entry : root.getAsJsonObject("datasourcetypes").entrySet()) { + final String className = entry.getValue().getAsString(); + dataSourceTypes.put(entry.getKey(), initDataSouceType(className) ); + } for (Entry entry : root.getAsJsonObject("datasources").entrySet()) { JsonObject dataSource = entry.getValue().getAsJsonObject(); this.dataSources.put(entry.getKey(), dataSource); @@ -37,6 +45,15 @@ public ConfigReader(Reader configReader) { } } + /** + * Gets the data source types. + * + * @return a mapping of names of data source types to these types + */ + public Map getDataSourceTypes() { + return dataSourceTypes; + } + /** * Gets the data sources. * @@ -58,4 +75,35 @@ public Map getPrefixes() { public String getBaseURL() { return baseURL; } + + protected IDataSourceType initDataSouceType( final String className ) + { + final Class c; + try { + c = Class.forName( className ); + } + catch ( ClassNotFoundException e ) { + throw new IllegalArgumentException( "Class not found: " + className, + e ); + } + + final Object o; + try { + o = c.newInstance(); + } + catch ( Exception e ) { + throw new IllegalArgumentException( + "Creating an instance of class '" + className + "' " + + "caused a " + e.getClass().getSimpleName() + ": " + + e.getMessage(), e ); + } + + if ( ! (o instanceof IDataSourceType) ) + throw new IllegalArgumentException( + "Class '" + className + "' is not an implementation " + + "of IDataSourceType." ); + + return (IDataSourceType) o; + } + } From 5022839d7e121d9eb19acc01d1729ffb2e8fe6cb Mon Sep 17 00:00:00 2001 From: Olaf Hartig Date: Fri, 25 Dec 2015 22:04:55 +0100 Subject: [PATCH 11/12] changed the servlet to make use of thespecification of relevant IDataSourceType implementations as given in the config file --- .../servlet/LinkedDataFragmentServlet.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/org/linkeddatafragments/servlet/LinkedDataFragmentServlet.java b/src/org/linkeddatafragments/servlet/LinkedDataFragmentServlet.java index 9a16dce..6b4f89b 100644 --- a/src/org/linkeddatafragments/servlet/LinkedDataFragmentServlet.java +++ b/src/org/linkeddatafragments/servlet/LinkedDataFragmentServlet.java @@ -20,11 +20,10 @@ import org.apache.jena.riot.RDFLanguages; import org.linkeddatafragments.config.ConfigReader; import org.linkeddatafragments.datasource.DataSourceFactory; +import org.linkeddatafragments.datasource.DataSourceTypesRegistry; import org.linkeddatafragments.datasource.IDataSource; -import org.linkeddatafragments.datasource.hdt.HdtDataSourceType; +import org.linkeddatafragments.datasource.IDataSourceType; import org.linkeddatafragments.datasource.index.IndexDataSource; -import org.linkeddatafragments.datasource.tdb.JenaTDBDataSourceType; -import org.linkeddatafragments.exceptions.DataSourceException; import org.linkeddatafragments.exceptions.DataSourceNotFoundException; import org.linkeddatafragments.fragments.FragmentRequestParserBase; import org.linkeddatafragments.fragments.LinkedDataFragment; @@ -49,11 +48,6 @@ public class LinkedDataFragmentServlet extends HttpServlet { private final HashMap dataSources = new HashMap<>(); private final Collection mimeTypes = new ArrayList<>(); - public LinkedDataFragmentServlet() { - HdtDataSourceType.register(); - JenaTDBDataSourceType.register(); - } - private File getConfigFile(ServletConfig config) throws IOException { String path = config.getServletContext().getRealPath("/"); if (path == null) { @@ -80,6 +74,13 @@ public void init(ServletConfig servletConfig) throws ServletException { File configFile = getConfigFile(servletConfig); config = new ConfigReader(new FileReader(configFile)); + // register data source types + for ( Entry typeEntry : config.getDataSourceTypes().entrySet() ) { + DataSourceTypesRegistry.register( typeEntry.getKey(), + typeEntry.getValue() ); + } + + // register data sources for (Entry dataSource : config.getDataSources().entrySet()) { dataSources.put(dataSource.getKey(), DataSourceFactory.create(dataSource.getValue())); } @@ -89,7 +90,7 @@ public void init(ServletConfig servletConfig) throws ServletException { mimeTypes.add(Lang.JSONLD.getHeaderString()); mimeTypes.add(Lang.NTRIPLES.getHeaderString()); mimeTypes.add(Lang.RDFXML.getHeaderString()); - } catch (IOException | DataSourceException e) { + } catch (Exception e) { throw new ServletException(e); } } From 1a5d567303ff567705c7046d0657440215ca2858 Mon Sep 17 00:00:00 2001 From: Olaf Hartig Date: Fri, 25 Dec 2015 22:06:17 +0100 Subject: [PATCH 12/12] removed static code for registering the existing data source types --- .../datasource/hdt/HdtDataSourceType.java | 10 ---------- .../datasource/tdb/JenaTDBDataSourceType.java | 10 ---------- .../datasource/HdtDataSourceTest.java | 10 +++++++--- .../datasource/JenaTDBDataSourceTest.java | 9 +++++++-- 4 files changed, 14 insertions(+), 25 deletions(-) diff --git a/src/org/linkeddatafragments/datasource/hdt/HdtDataSourceType.java b/src/org/linkeddatafragments/datasource/hdt/HdtDataSourceType.java index d72e2aa..2826c2f 100644 --- a/src/org/linkeddatafragments/datasource/hdt/HdtDataSourceType.java +++ b/src/org/linkeddatafragments/datasource/hdt/HdtDataSourceType.java @@ -3,7 +3,6 @@ import java.io.File; import java.io.IOException; -import org.linkeddatafragments.datasource.DataSourceTypesRegistry; import org.linkeddatafragments.datasource.IDataSource; import org.linkeddatafragments.datasource.IDataSourceType; import org.linkeddatafragments.exceptions.DataSourceException; @@ -17,15 +16,6 @@ */ public class HdtDataSourceType implements IDataSourceType { - public static final String TYPE_NAME = "HdtDatasource"; - - public static void register() { - if ( ! DataSourceTypesRegistry.isRegistered(TYPE_NAME) ) { - DataSourceTypesRegistry.register( TYPE_NAME, - new HdtDataSourceType() ); - } - } - @Override public IDataSource createDataSource( final String title, final String description, diff --git a/src/org/linkeddatafragments/datasource/tdb/JenaTDBDataSourceType.java b/src/org/linkeddatafragments/datasource/tdb/JenaTDBDataSourceType.java index 5f38eee..3be3dea 100644 --- a/src/org/linkeddatafragments/datasource/tdb/JenaTDBDataSourceType.java +++ b/src/org/linkeddatafragments/datasource/tdb/JenaTDBDataSourceType.java @@ -2,7 +2,6 @@ import java.io.File; -import org.linkeddatafragments.datasource.DataSourceTypesRegistry; import org.linkeddatafragments.datasource.IDataSource; import org.linkeddatafragments.datasource.IDataSourceType; import org.linkeddatafragments.exceptions.DataSourceException; @@ -17,15 +16,6 @@ */ public class JenaTDBDataSourceType implements IDataSourceType { - public static final String TYPE_NAME = "JenaTDBDatasource"; - - public static void register() { - if ( ! DataSourceTypesRegistry.isRegistered(TYPE_NAME) ) { - DataSourceTypesRegistry.register( TYPE_NAME, - new JenaTDBDataSourceType() ); - } - } - @Override public IDataSource createDataSource( final String title, final String description, diff --git a/src/test/java/org/linkeddatafragments/datasource/HdtDataSourceTest.java b/src/test/java/org/linkeddatafragments/datasource/HdtDataSourceTest.java index f9f7ef4..482ec77 100644 --- a/src/test/java/org/linkeddatafragments/datasource/HdtDataSourceTest.java +++ b/src/test/java/org/linkeddatafragments/datasource/HdtDataSourceTest.java @@ -7,6 +7,7 @@ import org.junit.Before; import org.junit.BeforeClass; import org.linkeddatafragments.datasource.DataSourceFactory; +import org.linkeddatafragments.datasource.DataSourceTypesRegistry; import org.linkeddatafragments.datasource.hdt.HdtDataSourceType; import org.rdfhdt.hdt.enums.RDFNotation; import org.rdfhdt.hdt.hdt.HDT; @@ -24,7 +25,11 @@ public class HdtDataSourceTest extends DataSourceTest { @BeforeClass public static void setUpClass() throws Exception { - HdtDataSourceType.register(); + final String typeName = "HdtTestSourceType"; + if ( ! DataSourceTypesRegistry.isRegistered(typeName) ) { + DataSourceTypesRegistry.register( typeName, new HdtDataSourceType() ); + } + // HDT does not seem to support an InputReader, so write to temp file File temp = getResourceAsFile(); @@ -37,8 +42,7 @@ public static void setUpClass() throws Exception { temp.getAbsoluteFile().delete(); // Everything is in place, now create the LDF datasource - JsonObject config = createConfig("hdt test", "hdt test", - HdtDataSourceType.TYPE_NAME); + JsonObject config = createConfig("hdt test", "hdt test", typeName); JsonObject settings = new JsonObject(); settings.addProperty("file", hdtfile.getAbsolutePath()); diff --git a/src/test/java/org/linkeddatafragments/datasource/JenaTDBDataSourceTest.java b/src/test/java/org/linkeddatafragments/datasource/JenaTDBDataSourceTest.java index 00548b3..6a3be38 100644 --- a/src/test/java/org/linkeddatafragments/datasource/JenaTDBDataSourceTest.java +++ b/src/test/java/org/linkeddatafragments/datasource/JenaTDBDataSourceTest.java @@ -19,6 +19,7 @@ import org.junit.BeforeClass; import org.linkeddatafragments.datasource.DataSourceFactory; +import org.linkeddatafragments.datasource.DataSourceTypesRegistry; import org.linkeddatafragments.datasource.tdb.JenaTDBDataSourceType; /** @@ -31,7 +32,11 @@ public class JenaTDBDataSourceTest extends DataSourceTest { @BeforeClass public static void setUpClass() throws Exception { - JenaTDBDataSourceType.register(); + final String typeName = "JenaSourceType"; + if ( ! DataSourceTypesRegistry.isRegistered(typeName) ) { + DataSourceTypesRegistry.register( typeName, + new JenaTDBDataSourceType() ); + } String tmpdir = System.getProperty("java.io.tmpdir"); jena = new File(tmpdir, "ldf-jena-test"); @@ -46,7 +51,7 @@ public static void setUpClass() throws Exception { // Everything is in place, now create the LDF datasource JsonObject config = createConfig("jena tdb test", "jena tdb test", - JenaTDBDataSourceType.TYPE_NAME); + typeName); JsonObject settings = new JsonObject(); settings.addProperty("directory", jena.getAbsolutePath());