jenkins-bot has submitted this change and it was merged.

Change subject: Implement LDF server for Blazegraph
......................................................................


Implement LDF server for Blazegraph

Change-Id: I78b4edd4d725d2b87cfead92a35b31b072f31b40
Bug: T136358
---
M blazegraph/pom.xml
A 
blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/BigdataStatementToJenaStatementMapper.java
A 
blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/BlazegraphBasedTPF.java
A 
blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/BlazegraphBasedTPFRequestProcessor.java
A 
blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/BlazegraphDataSource.java
A 
blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/BlazegraphDataSourceType.java
A blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/LDFServlet.java
A 
blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/TPFRequestParserForBlazegraph.java
A 
blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/TriplePatternElementParserForBlazegraph.java
A dist/src/script/ldf-config.json
M dist/src/script/runBlazegraph.sh
M docs/ChangeLog
M pom.xml
M war/pom.xml
M war/src/assembly/dist.xml
M war/src/config/web.xml
16 files changed, 881 insertions(+), 8 deletions(-)

Approvals:
  Smalyshev: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/blazegraph/pom.xml b/blazegraph/pom.xml
index 7c5017d..70626b9 100644
--- a/blazegraph/pom.xml
+++ b/blazegraph/pom.xml
@@ -40,6 +40,12 @@
       <version>${project.parent.version}</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+       <groupId>org.linkeddatafragments</groupId>
+       <artifactId>ldfserver</artifactId>
+       <version>0.1.1-wmf</version>
+       <classifier>classes</classifier>
+    </dependency>
   </dependencies>
 
   <build>
diff --git 
a/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/BigdataStatementToJenaStatementMapper.java
 
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/BigdataStatementToJenaStatementMapper.java
new file mode 100644
index 0000000..a494245
--- /dev/null
+++ 
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/BigdataStatementToJenaStatementMapper.java
@@ -0,0 +1,104 @@
+package org.wikidata.query.rdf.blazegraph.ldf;
+
+import com.hp.hpl.jena.datatypes.RDFDatatype;
+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;
+import com.hp.hpl.jena.rdf.model.Statement;
+import com.hp.hpl.jena.util.iterator.Map1;
+
+import org.openrdf.model.URI;
+
+import com.bigdata.rdf.model.BigdataLiteral;
+import com.bigdata.rdf.model.BigdataResource;
+import com.bigdata.rdf.model.BigdataStatement;
+import com.bigdata.rdf.model.BigdataValue;
+
+/**
+ * Implementation of {@link Map1} that transforms {@link BigdataStatement}s to
+ * Jena {@link Statement}s.
+ *
+ * @author <a href="http://olafhartig.de";>Olaf Hartig</a>
+ */
+@SuppressWarnings("all")
+public class BigdataStatementToJenaStatementMapper implements
+            Map1<BigdataStatement, Statement> {
+    /**
+     * Jenna type mapper.
+     */
+    public static final TypeMapper JENA_TYPE_MAPPER = TypeMapper.getInstance();
+
+    /**
+     * Singleton instance.
+     */
+    private static BigdataStatementToJenaStatementMapper instance;
+
+    /**
+     * Get singleton instance.
+     * @return
+     */
+    public static BigdataStatementToJenaStatementMapper getInstance() {
+        if (instance == null) {
+            instance = new BigdataStatementToJenaStatementMapper();
+        }
+        return instance;
+    }
+
+    @Override
+    public Statement map1(final BigdataStatement blzgStmt) {
+        final Resource s = convertToJenaResource(blzgStmt.getSubject());
+        final Property p = convertToJenaProperty(blzgStmt.getPredicate());
+        final RDFNode o = convertToJenaRDFNode(blzgStmt.getObject());
+
+        return ResourceFactory.createStatement(s, p, o);
+    }
+
+    /**
+     * Convert Bigdata resource to Jena resource.
+     * @param r
+     * @return Jena resource.
+     */
+    public Resource convertToJenaResource(final BigdataResource r) {
+        return ResourceFactory.createResource(r.stringValue());
+    }
+
+    /**
+     * Convert Bigdata resource to Jena property.
+     * @param r
+     * @return Jena property.
+     */
+    public Property convertToJenaProperty(final BigdataResource r) {
+        return ResourceFactory.createProperty(r.stringValue());
+    }
+
+    /**
+     * Convert Bigdata value to Jena RDF Node.
+     * @param v
+     * @return Jena RDF node.
+     */
+    public RDFNode convertToJenaRDFNode(final BigdataValue v) {
+        if (v instanceof BigdataResource)
+            return convertToJenaResource((BigdataResource) v);
+
+        if (!(v instanceof BigdataLiteral))
+            throw new IllegalArgumentException(v.getClass().getName());
+
+        final BigdataLiteral l = (BigdataLiteral) v;
+        final String lex = l.getLabel();
+        final URI datatypeURI = l.getDatatype();
+        final String languageTag = l.getLanguage();
+
+        if (datatypeURI != null) {
+            final RDFDatatype dt = JENA_TYPE_MAPPER
+                    .getSafeTypeByName(datatypeURI.stringValue());
+            return ResourceFactory.createTypedLiteral(lex, dt);
+        } else if (languageTag != null) {
+            return ResourceFactory.createLangLiteral(lex, languageTag);
+        } else {
+            return ResourceFactory.createPlainLiteral(lex);
+        }
+    }
+
+}
diff --git 
a/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/BlazegraphBasedTPF.java
 
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/BlazegraphBasedTPF.java
new file mode 100644
index 0000000..15fdc9e
--- /dev/null
+++ 
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/BlazegraphBasedTPF.java
@@ -0,0 +1,126 @@
+package org.wikidata.query.rdf.blazegraph.ldf;
+
+import java.io.Closeable;
+
+import org.linkeddatafragments.fragments.tpf.TriplePatternFragmentBase;
+
+import com.bigdata.rdf.model.BigdataStatement;
+import com.bigdata.rdf.spo.ISPO;
+import com.bigdata.rdf.store.AbstractTripleStore;
+import com.bigdata.rdf.store.BigdataStatementIterator;
+import com.bigdata.relation.accesspath.IAccessPath;
+import com.hp.hpl.jena.rdf.model.Statement;
+import com.hp.hpl.jena.rdf.model.StmtIterator;
+import com.hp.hpl.jena.util.iterator.Map1Iterator;
+
+/**
+ * Implementation of
+ * {@link org.linkeddatafragments.fragments.tpf.TriplePatternFragmentBase}.
+ *
+ * @author <a href="http://olafhartig.de";>Olaf Hartig</a>
+ */
+public class BlazegraphBasedTPF extends TriplePatternFragmentBase {
+    /**
+     * Statement iterator.
+     */
+    private final MyStmtIterator myStmtIt;
+
+    public BlazegraphBasedTPF(final IAccessPath<ISPO> ap,
+            final AbstractTripleStore store, final long count,
+            final long offset, final long limit, final String fragmentURL,
+            final String datasetURL, final long pageNumber) {
+        this((ap == null) // blzgStmtIt
+                ? null
+                : store.asStatementIterator(ap.iterator(offset, limit, 0)),
+                // capacity=0, i.e., default capacity will be used
+                count, // totalSize
+                fragmentURL, datasetURL, pageNumber, count < offset + limit); 
// isLastPage
+    }
+
+    protected BlazegraphBasedTPF(final BigdataStatementIterator blzgStmtIt,
+            long totalSize, final String fragmentURL, final String datasetURL,
+            final long pageNumber, final boolean isLastPage) {
+        super(totalSize, fragmentURL, datasetURL, pageNumber, isLastPage);
+
+        if (blzgStmtIt != null)
+            myStmtIt = new MyStmtIterator(blzgStmtIt);
+        else
+            myStmtIt = null;
+    }
+
+    @Override
+    protected StmtIterator getNonEmptyStmtIterator() {
+        if (myStmtIt == null)
+            throw new IllegalStateException();
+
+        if (!myStmtIt.hasNext())
+            throw new IllegalStateException();
+
+        return myStmtIt;
+    }
+
+    @Override
+    public void close() {
+        myStmtIt.close();
+    }
+
+    /**
+     *
+     */
+    public static class MyStmtIterator extends Map1Iterator<BigdataStatement, 
Statement>
+            implements StmtIterator, Closeable {
+        /**
+         * Blazegraph statement iterator.
+         */
+        private final BigdataStatementIterator blzgStmtIt;
+        /**
+         * Is iterator closed?
+         */
+        private boolean closed;
+
+        public MyStmtIterator(final BigdataStatementIterator blzgStmtIt) {
+            super(BigdataStatementToJenaStatementMapper.getInstance(),
+                    blzgStmtIt);
+
+            this.blzgStmtIt = blzgStmtIt;
+        }
+
+        @Override
+        public Statement nextStatement() {
+            return next();
+        }
+
+        @Override
+        public boolean hasNext() {
+            if (closed)
+                return false;
+
+            if (!blzgStmtIt.hasNext()) {
+                close();
+                return false;
+            } else {
+                return true;
+            }
+        }
+
+        @Override
+        public void close() {
+            if (closed)
+                return;
+
+            blzgStmtIt.close();
+            super.close();
+            closed = true;
+        }
+
+        /**
+         * Is iterator closed?
+         * @return true or false
+         */
+        public boolean isClosed() {
+            return closed;
+        }
+
+    } // end of MyStmtIterator
+
+}
diff --git 
a/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/BlazegraphBasedTPFRequestProcessor.java
 
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/BlazegraphBasedTPFRequestProcessor.java
new file mode 100644
index 0000000..ef72c61
--- /dev/null
+++ 
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/BlazegraphBasedTPFRequestProcessor.java
@@ -0,0 +1,293 @@
+package org.wikidata.query.rdf.blazegraph.ldf;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.openrdf.model.Value;
+
+import com.bigdata.rdf.internal.IV;
+import com.bigdata.rdf.internal.impl.TermId;
+import com.bigdata.rdf.model.BigdataValue;
+import com.bigdata.rdf.spo.ISPO;
+import com.bigdata.rdf.spo.SPOFilter;
+import com.bigdata.rdf.store.AbstractTripleStore;
+import com.bigdata.relation.accesspath.IAccessPath;
+
+import 
org.linkeddatafragments.datasource.AbstractRequestProcessorForTriplePatterns;
+import org.linkeddatafragments.fragments.ILinkedDataFragment;
+import org.linkeddatafragments.fragments.tpf.ITriplePatternElement;
+import org.linkeddatafragments.fragments.tpf.ITriplePatternFragment;
+import org.linkeddatafragments.fragments.tpf.ITriplePatternFragmentRequest;
+
+/**
+ * A Blazegraph-based data source.
+ *
+ * @author <a href="http://olafhartig.de";>Olaf Hartig</a>
+ */
+public class BlazegraphBasedTPFRequestProcessor extends
+            AbstractRequestProcessorForTriplePatterns<BigdataValue, String, 
String> {
+    /**
+     * Blazegraph data store.
+     */
+    private final AbstractTripleStore store;
+
+    public BlazegraphBasedTPFRequestProcessor(final AbstractTripleStore store) 
{
+        this.store = store;
+    }
+
+    @Override
+    protected Worker getTPFSpecificWorker(
+            final ITriplePatternFragmentRequest<BigdataValue, String, String> 
req)
+                    throws IllegalArgumentException {
+        return new Worker(req);
+    }
+
+    /**
+     * Blazegraph worker class.
+     */
+    protected class Worker extends
+                AbstractRequestProcessorForTriplePatterns.Worker<BigdataValue, 
String, String> {
+        public Worker(
+                final ITriplePatternFragmentRequest<BigdataValue, String, 
String> req) {
+            super(req);
+        }
+
+        @SuppressWarnings("checkstyle:cyclomaticcomplexity")
+        @Override
+        protected ILinkedDataFragment createFragment(
+                final ITriplePatternElement<BigdataValue, String, String> s,
+                final ITriplePatternElement<BigdataValue, String, String> p,
+                final ITriplePatternElement<BigdataValue, String, String> o,
+                final long offset, final long limit) {
+            int numOfValues = 0;
+            if (!s.isVariable())
+                numOfValues++;
+            if (!p.isVariable())
+                numOfValues++;
+            if (!o.isVariable())
+                numOfValues++;
+
+            if (numOfValues > 0) {
+                final BigdataValue[] values = new BigdataValue[numOfValues];
+                int i = 0;
+                if (!s.isVariable())
+                    values[i++] = s.asConstantTerm();
+                if (!p.isVariable())
+                    values[i++] = p.asConstantTerm();
+                if (!o.isVariable())
+                    values[i++] = o.asConstantTerm();
+
+                // Initialize the IVs of the values.
+                store.getLexiconRelation().addTerms(values, numOfValues, 
true); // readOnly=true
+
+                // Check if some IVs have not been initialized. In this case
+                // the corresponding values are not used in any triple in the
+                // store. Hence, there cannot be any matching triple for the
+                // requested triple pattern and, thus, we return an empty TPF.
+                for (int j = 0; j < numOfValues; j++) {
+                    @SuppressWarnings("rawtypes")
+                    final IV iv = values[j].getIV();
+                    if (iv == null || (iv instanceof TermId)
+                            && ((TermId<?>) iv).getTermId() == 0L)
+                        return createEmptyTriplePatternFragment();
+                }
+            }
+
+            final VariablesBasedFilter filter = createFilterIfNeeded(s, p, o);
+            final IAccessPath<ISPO> ap = store.getSPORelation().getAccessPath(
+                    asIVorNull(s), asIVorNull(p), asIVorNull(o), null, // 
c=null
+                    filter);
+
+            return createTriplePatternFragment(ap, offset, limit);
+        }
+
+        /**
+         * Create filter based on triple request.
+         * @param s
+         * @param p
+         * @param o
+         * @return
+         */
+        @SuppressWarnings({"checkstyle:npathcomplexity", 
"checkstyle:cyclomaticcomplexity"})
+        public VariablesBasedFilter createFilterIfNeeded(
+                final ITriplePatternElement<BigdataValue, String, String> s,
+                final ITriplePatternElement<BigdataValue, String, String> p,
+                final ITriplePatternElement<BigdataValue, String, String> o) {
+            if (!s.isSpecificVariable() && !p.isSpecificVariable()
+                    && !o.isSpecificVariable())
+                return null;
+
+            final Set<String> varNames = new HashSet<String>();
+
+            if (s.isNamedVariable()) {
+                varNames.add(s.asNamedVariable());
+            }
+
+            if (p.isNamedVariable()) {
+                if (varNames.contains(p.asNamedVariable()))
+                    return new VariablesBasedFilter(s, p, o);
+
+                varNames.add(p.asNamedVariable());
+            }
+
+            if (o.isNamedVariable() && varNames.contains(o.asNamedVariable())) 
{
+                return new VariablesBasedFilter(s, p, o);
+            }
+
+            varNames.clear();
+
+            if (s.isAnonymousVariable()) {
+                varNames.add(s.asAnonymousVariable());
+            }
+
+            if (p.isAnonymousVariable()) {
+                if (varNames.contains(p.asAnonymousVariable()))
+                    return new VariablesBasedFilter(s, p, o);
+
+                varNames.add(p.asAnonymousVariable());
+            }
+
+            if (o.isAnonymousVariable()
+                    && varNames.contains(o.asAnonymousVariable())) {
+                return new VariablesBasedFilter(s, p, o);
+            }
+
+            return null;
+        }
+
+        /**
+         * Create the fragment.
+         * @param ap Access path
+         * @param offset Offset
+         * @param limit Limit
+         * @return
+         */
+        protected ITriplePatternFragment createTriplePatternFragment(
+                final IAccessPath<ISPO> ap, final long offset,
+                final long limit) {
+            final long count = ap.rangeCount(false); // exact=false, i.e., fast
+                                                     // range count
+
+            if (count == 0L) {
+                return createEmptyTriplePatternFragment();
+            } else {
+                return new BlazegraphBasedTPF(ap, store, count, offset, limit,
+                        request.getFragmentURL(), request.getDatasetURL(),
+                        request.getPageNumber());
+            }
+        }
+
+    } // end of class Worker
+
+    /**
+     * Convert element to IV if it's constant.
+     * @param tpe
+     * @return IV or null if not constant.
+     */
+    @SuppressWarnings("rawtypes")
+    public static IV asIVorNull(
+            final ITriplePatternElement<BigdataValue, String, String> tpe) {
+        return (tpe.isVariable()) ? null : tpe.asConstantTerm().getIV();
+    }
+
+    /**
+     * Filter based on variables.
+     */
+    public static class VariablesBasedFilter extends SPOFilter<ISPO> {
+        private static final long serialVersionUID = 6979067019748992496L;
+
+        /**
+         * Check subject.
+         */
+        private final boolean checkS;
+        /**
+         * Check predicate.
+         */
+        private final boolean checkP;
+        /**
+         * Check object.
+         */
+        private final boolean checkO;
+
+        @SuppressWarnings({"checkstyle:localvariablename", 
"checkstyle:cyclomaticcomplexity"})
+        public VariablesBasedFilter(
+                final ITriplePatternElement<BigdataValue, String, String> s,
+                final ITriplePatternElement<BigdataValue, String, String> p,
+                final ITriplePatternElement<BigdataValue, String, String> o) {
+            boolean _checkS = false;
+            boolean _checkP = false;
+            boolean _checkO = false;
+
+            if (s.isNamedVariable()) {
+                final String sVarName = s.asNamedVariable();
+                if (p.isNamedVariable()
+                        && p.asNamedVariable().equals(sVarName)) {
+                    _checkS = true;
+                    _checkP = true;
+                }
+
+                if (o.isNamedVariable()
+                        && o.asNamedVariable().equals(sVarName)) {
+                    _checkS = true;
+                    _checkO = true;
+                }
+            }
+
+            if (s.isAnonymousVariable()) {
+                final String sVarName = s.asAnonymousVariable();
+                if (p.isAnonymousVariable()
+                        && p.asAnonymousVariable().equals(sVarName)) {
+                    _checkS = true;
+                    _checkP = true;
+                }
+
+                if (o.isAnonymousVariable()
+                        && o.asAnonymousVariable().equals(sVarName)) {
+                    _checkS = true;
+                    _checkO = true;
+                }
+            }
+
+            if (p.isNamedVariable() && o.isNamedVariable()
+                    && p.asNamedVariable().equals(o.asNamedVariable())) {
+                _checkP = true;
+                _checkO = true;
+            }
+
+            if (p.isAnonymousVariable() && o.isAnonymousVariable() && p
+                    .asAnonymousVariable().equals(o.asAnonymousVariable())) {
+                _checkP = true;
+                _checkO = true;
+            }
+
+            checkS = _checkS;
+            checkP = _checkP;
+            checkO = _checkO;
+        }
+
+        @Override
+        @SuppressWarnings("checkstyle:cyclomaticcomplexity")
+        public boolean isValid(Object obj) {
+            if (!canAccept(obj))
+                return true;
+
+            final ISPO spo = (ISPO) obj;
+            final Value s = spo.getSubject();
+            final Value p = spo.getPredicate();
+            final Value o = spo.getObject();
+
+            if (checkS && checkP && !s.equals(p))
+                return false;
+
+            if (checkS && checkO && !s.equals(o))
+                return false;
+
+            if (checkP && checkO && !p.equals(o))
+                return false;
+
+            return true;
+        }
+
+    } // end of class VariablesBasedFilter
+
+}
diff --git 
a/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/BlazegraphDataSource.java
 
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/BlazegraphDataSource.java
new file mode 100644
index 0000000..c8c89ab
--- /dev/null
+++ 
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/BlazegraphDataSource.java
@@ -0,0 +1,47 @@
+package org.wikidata.query.rdf.blazegraph.ldf;
+
+import com.bigdata.rdf.sail.webapp.BigdataRDFContext;
+import com.bigdata.rdf.store.AbstractTripleStore;
+
+import org.linkeddatafragments.datasource.DataSourceBase;
+import org.linkeddatafragments.datasource.IFragmentRequestProcessor;
+import org.linkeddatafragments.fragments.IFragmentRequestParser;
+
+/**
+ * A Blazegraph-based data source.
+ *
+ * @author <a href="http://olafhartig.de";>Olaf Hartig</a>
+ */
+public class BlazegraphDataSource extends DataSourceBase {
+    /**
+     * Blazegraph context.
+     */
+    private final BigdataRDFContext context;
+
+    public BlazegraphDataSource(final String title, final String description,
+            final BigdataRDFContext context) {
+        super(title, description);
+        this.context = context;
+    }
+
+    /**
+     * Get store for current request.
+     *
+     * @return Triple store.
+     */
+    protected AbstractTripleStore getStore() {
+        return context.getTripleStore(context.getConfig().namespace, -1);
+    }
+
+    @Override
+    public IFragmentRequestParser getRequestParser() {
+        return new TPFRequestParserForBlazegraph(
+                getStore().getLexiconRelation());
+    }
+
+    @Override
+    public IFragmentRequestProcessor getRequestProcessor() {
+        return new BlazegraphBasedTPFRequestProcessor(getStore());
+    }
+
+}
diff --git 
a/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/BlazegraphDataSourceType.java
 
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/BlazegraphDataSourceType.java
new file mode 100644
index 0000000..49bbe35
--- /dev/null
+++ 
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/BlazegraphDataSourceType.java
@@ -0,0 +1,42 @@
+package org.wikidata.query.rdf.blazegraph.ldf;
+
+import com.bigdata.rdf.sail.webapp.BigdataRDFContext;
+import com.google.gson.JsonObject;
+
+import org.linkeddatafragments.datasource.IDataSource;
+import org.linkeddatafragments.datasource.IDataSourceType;
+import org.linkeddatafragments.exceptions.DataSourceCreationException;
+
+/**
+ * The type of Blazegraph-based Triple Pattern Fragment data sources.
+ *
+ * @author <a href="http://olafhartig.de";>Olaf Hartig</a>
+ */
+public class BlazegraphDataSourceType implements IDataSourceType {
+    /**
+     * Blazegraph context.
+     */
+    private static BigdataRDFContext context;
+
+    /**
+     * Set Blazegraph context.
+     *
+     * @param rdfContext
+     *            The context object.
+     */
+    public static void setContext(BigdataRDFContext rdfContext) {
+        context = rdfContext;
+    }
+
+    @Override
+    public IDataSource createDataSource(final String title,
+            final String description, final JsonObject settings)
+                    throws DataSourceCreationException {
+        if (context == null) {
+            throw new DataSourceCreationException(title, "Context is not 
set!");
+        }
+
+        return new BlazegraphDataSource(title, description, context);
+    }
+
+}
diff --git 
a/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/LDFServlet.java
 
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/LDFServlet.java
new file mode 100644
index 0000000..96c8720
--- /dev/null
+++ 
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/LDFServlet.java
@@ -0,0 +1,44 @@
+package org.wikidata.query.rdf.blazegraph.ldf;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.linkeddatafragments.servlet.LinkedDataFragmentServlet;
+
+import com.bigdata.rdf.sail.webapp.BigdataRDFServlet;
+
+/**
+ * This class implements LDF servlet.
+ * It is based on LinkedDataFragmentServlet from 
http://linkeddatafragments.org/
+ * and on https://github.com/hartig/BlazegraphBasedTPFServer/
+ */
+public class LDFServlet extends BigdataRDFServlet {
+    /**
+     *
+     */
+    private static final long serialVersionUID = -9156574015263443551L;
+
+    /**
+     * Delegate LDF servlet.
+     * It will be doing all the work.
+     */
+    private LinkedDataFragmentServlet ldfDelegate;
+    /**
+     * Overridden to create and initialize the delegate {@link Servlet}
+     * instances.
+     */
+    @Override
+    public void init() throws ServletException {
+        super.init();
+        BlazegraphDataSourceType.setContext(getBigdataRDFContext());
+        ldfDelegate = new LinkedDataFragmentServlet();
+        ldfDelegate.init(getServletConfig());
+    }
+
+    @Override
+    protected void doGet(final HttpServletRequest req,
+            final HttpServletResponse resp) throws ServletException {
+        ldfDelegate.doGet(req, resp);
+    }
+}
diff --git 
a/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/TPFRequestParserForBlazegraph.java
 
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/TPFRequestParserForBlazegraph.java
new file mode 100644
index 0000000..a931a08
--- /dev/null
+++ 
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/TPFRequestParserForBlazegraph.java
@@ -0,0 +1,19 @@
+package org.wikidata.query.rdf.blazegraph.ldf;
+
+import com.bigdata.rdf.lexicon.LexiconRelation;
+import com.bigdata.rdf.model.BigdataValue;
+
+import org.linkeddatafragments.fragments.tpf.TPFRequestParser;
+
+/**
+ * An {@link TPFRequestParser} for Blazegraph-based backends.
+ *
+ * @author <a href="http://olafhartig.de";>Olaf Hartig</a>
+ */
+public class TPFRequestParserForBlazegraph extends
+            TPFRequestParser<BigdataValue, String, String> {
+
+    public TPFRequestParserForBlazegraph(final LexiconRelation lexicon) {
+        super(new TriplePatternElementParserForBlazegraph(lexicon));
+    }
+}
diff --git 
a/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/TriplePatternElementParserForBlazegraph.java
 
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/TriplePatternElementParserForBlazegraph.java
new file mode 100644
index 0000000..7b6af63
--- /dev/null
+++ 
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/ldf/TriplePatternElementParserForBlazegraph.java
@@ -0,0 +1,69 @@
+package org.wikidata.query.rdf.blazegraph.ldf;
+
+import com.bigdata.rdf.lexicon.LexiconRelation;
+import com.bigdata.rdf.model.BigdataURI;
+import com.bigdata.rdf.model.BigdataValue;
+import com.bigdata.rdf.model.BigdataValueFactory;
+
+import org.linkeddatafragments.util.TriplePatternElementParser;
+
+/**
+ * A {@link TriplePatternElementParser} for Blazegraph-based backends.
+ *
+ * @author <a href="http://olafhartig.de";>Olaf Hartig</a>
+ */
+public class TriplePatternElementParserForBlazegraph
+        extends
+            TriplePatternElementParser<BigdataValue, String, String> {
+    /**
+     * Blazegraph value factory.
+     */
+    private final BigdataValueFactory valueFactory;
+
+    public TriplePatternElementParserForBlazegraph(final LexiconRelation lex) {
+        valueFactory = lex.getValueFactory();
+    }
+
+    @Override
+    public String createNamedVariable(final String varName) {
+        return varName;
+    }
+
+    @Override
+    public String createAnonymousVariable(final String label) {
+        return label;
+    }
+
+    @Override
+    public BigdataValue createBlankNode(final String label) {
+        return valueFactory.createBNode(label);
+    }
+
+    @Override
+    public BigdataValue createURI(final String uri) {
+        return valueFactory.createURI(uri);
+    }
+
+    @Override
+    public BigdataValue createTypedLiteral(final String label,
+            final String typeURI) {
+        final BigdataURI datatypeURI = valueFactory.createURI(typeURI);
+        return valueFactory.createLiteral(label, datatypeURI);
+    }
+
+    @Override
+    public BigdataValue createLanguageLiteral(final String label,
+            final String languageTag) {
+        return valueFactory.createLiteral(label, languageTag);
+    }
+
+    @Override
+    public BigdataValue createPlainLiteral(final String label) {
+        return valueFactory.createLiteral(label);
+    }
+
+    @Override
+    public BigdataValue handleUnparsableParameter(final String parameter) {
+        throw new IllegalArgumentException();
+    }
+}
diff --git a/dist/src/script/ldf-config.json b/dist/src/script/ldf-config.json
new file mode 100644
index 0000000..62c72ea
--- /dev/null
+++ b/dist/src/script/ldf-config.json
@@ -0,0 +1,48 @@
+{
+  "title": "Wikidata Query Service LDF server",
+  "datasourcetypes": {
+    "BlazegraphDataSource"  : 
"org.wikidata.query.rdf.blazegraph.ldf.BlazegraphDataSourceType"
+  },
+
+  "datasources": {
+    "ldf": {
+        "title": "Wikidata",
+        "type": "BlazegraphDataSource",
+        "description": "Blazegraph data source"
+    }
+  },
+
+  "prefixes": {
+    "rdf":         "http://www.w3.org/1999/02/22-rdf-syntax-ns#";,
+    "rdfs":        "http://www.w3.org/2000/01/rdf-schema#";,
+    "xsd":         "http://www.w3.org/2001/XMLSchema#";,
+    "dc":          "http://purl.org/dc/terms/";,
+    "foaf":        "http://xmlns.com/foaf/0.1/";,
+    "void":        "http://rdfs.org/ns/void#";,
+    "xsd":         "http://www.w3.org/2001/XMLSchema#";,
+    "owl":         "http://www.w3.org/2002/07/owl#";,
+    "skos":        "http://www.w3.org/2004/02/skos/core#";,
+    "schema":      "http://schema.org/";,
+    "cc":          "http://creativecommons.org/ns#";,
+    "geo":         "http://www.opengis.net/ont/geosparql#";,
+    "prov":        "http://www.w3.org/ns/prov#";,
+    "wikibase":    "http://wikiba.se/ontology#";,
+    "wdata":       "https://www.wikidata.org/wiki/Special:EntityData/";,
+    "wd":          "http://www.wikidata.org/entity/";,
+    "wds":         "http://www.wikidata.org/entity/statement/";,
+    "wdref":       "http://www.wikidata.org/reference/";,
+    "wdv":         "http://www.wikidata.org/value/";,
+    "wdt":         "http://www.wikidata.org/prop/direct/";,
+    "p":           "http://www.wikidata.org/prop/";,
+    "ps":          "http://www.wikidata.org/prop/statement/";,
+    "psv":         "http://www.wikidata.org/prop/statement/value/";,
+    "psn":         "http://www.wikidata.org/prop/statement/value-normalized/";,
+    "pq":          "http://www.wikidata.org/prop/qualifier/";,
+    "pqv":         "http://www.wikidata.org/prop/qualifier/value/";,
+    "pqn":         "http://www.wikidata.org/prop/qualifier/value-normalized/";,
+    "pr":          "http://www.wikidata.org/prop/reference/";,
+    "prv":         "http://www.wikidata.org/prop/reference/value/";,
+    "prn":         "http://www.wikidata.org/prop/reference/value-normalized/";,
+    "wdno":        "http://www.wikidata.org/prop/novalue/";
+  }
+}
diff --git a/dist/src/script/runBlazegraph.sh b/dist/src/script/runBlazegraph.sh
index 4189eda..9d1c053 100755
--- a/dist/src/script/runBlazegraph.sh
+++ b/dist/src/script/runBlazegraph.sh
@@ -7,6 +7,9 @@
 MEMORY=-Xmx8g
 BLAZEGRAPH_OPTS=""
 CONFIG_FILE=RWStore.properties
+DEBUG=-agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n
+# Disable this for debugging
+DEBUG=
 
 function usage() {
   echo "Usage: $0 [-h <host>] [-d <dir>] [-c <context>] [-p <port>] [-o 
<blazegraph options>] [-f config.properties]"
@@ -33,7 +36,7 @@
 DEFAULT_GLOBE=2
 
 echo "Running Blazegraph from `pwd` on :$PORT/$CONTEXT"
-java -server -XX:+UseG1GC ${MEMORY} 
-Dcom.bigdata.rdf.sail.webapp.ConfigParams.propertyFile=${CONFIG_FILE} \
+java -server -XX:+UseG1GC ${MEMORY} ${DEBUG} 
-Dcom.bigdata.rdf.sail.webapp.ConfigParams.propertyFile=${CONFIG_FILE} \
      -Dorg.eclipse.jetty.server.Request.maxFormContentSize=200000000 \
      -Dcom.bigdata.rdf.sparql.ast.QueryHints.analytic=true \
      
-Dcom.bigdata.rdf.sparql.ast.QueryHints.analyticMaxMemoryPerQuery=1073741824 \
diff --git a/docs/ChangeLog b/docs/ChangeLog
index e926df7..551e471 100644
--- a/docs/ChangeLog
+++ b/docs/ChangeLog
@@ -1,3 +1,8 @@
+0.2.4
+-----
+Add LDF server
+Add external prefix configuration
+
 0.2.3
 -----
 Add normalized quantity predicates
diff --git a/pom.xml b/pom.xml
index 55a428c..df1286f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -409,6 +409,18 @@
         <version>1.9.5</version>
         <scope>test</scope>
       </dependency>
+      <dependency>
+        <groupId>junit</groupId>
+        <artifactId>junit</artifactId>
+        <version>4.12</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>junit</groupId>
+        <artifactId>junit-dep</artifactId>
+        <version>4.11</version>
+        <scope>test</scope>
+      </dependency>
     </dependencies>
   </dependencyManagement>
   <dependencies>
diff --git a/war/pom.xml b/war/pom.xml
index 3292866..4788c94 100644
--- a/war/pom.xml
+++ b/war/pom.xml
@@ -35,6 +35,11 @@
       <artifactId>blazegraph</artifactId>
       <version>${project.parent.version}</version>
     </dependency>
+    <dependency>
+       <groupId>org.linkeddatafragments</groupId>
+       <artifactId>ldfserver</artifactId>
+       <version>0.1.1-wmf</version>
+    </dependency>
   </dependencies>
 
   <build>
diff --git a/war/src/assembly/dist.xml b/war/src/assembly/dist.xml
index 50a7288..76c0c2d 100644
--- a/war/src/assembly/dist.xml
+++ b/war/src/assembly/dist.xml
@@ -11,13 +11,9 @@
 
   <fileSets>
     <fileSet>
+      <useStrictFiltering>true</useStrictFiltering>
       <outputDirectory>WEB-INF</outputDirectory>
       <directory>${project.basedir}/src/config</directory>
-    </fileSet>
-
-    <fileSet>
-      <outputDirectory>html/js</outputDirectory>
-      <directory>${project.basedir}/src/js</directory>
     </fileSet>
   </fileSets>
 
@@ -30,11 +26,11 @@
       </includes>
        <unpackOptions>
          <excludes>
-           <exclude>**/workbench.js</exclude>
            <exclude>**/web.xml</exclude>
          </excludes>
         </unpackOptions>
       <useProjectArtifact>false</useProjectArtifact>
+         <useStrictFiltering>true</useStrictFiltering>
     </dependencySet>
 
     <dependencySet>
@@ -43,7 +39,33 @@
         <include>${project.groupId}:*:jar</include>
       </includes>
       <useProjectArtifact>false</useProjectArtifact>
+         <useStrictFiltering>true</useStrictFiltering>
     </dependencySet>
-  </dependencySets>
 
+    <dependencySet>
+      <outputDirectory>WEB-INF/lib</outputDirectory>
+      <includes>
+        <include>org.linkeddatafragments:ldfserver:jar</include>
+      </includes>
+      <useProjectArtifact>false</useProjectArtifact>
+         <useStrictFiltering>true</useStrictFiltering>
+    </dependencySet>
+
+
+    <dependencySet>
+      <outputDirectory>html</outputDirectory>
+      <unpack>true</unpack>
+      <includes>
+        <include>org.linkeddatafragments:ldfserver</include>
+      </includes>
+       <unpackOptions>
+         <includes>
+           <include>assets/**</include>
+         </includes>
+        </unpackOptions>
+      <useProjectArtifact>false</useProjectArtifact>
+         <useStrictFiltering>true</useStrictFiltering>
+    </dependencySet>
+
+  </dependencySets>
 </assembly>
diff --git a/war/src/config/web.xml b/war/src/config/web.xml
index 619baf1..727477b 100644
--- a/war/src/config/web.xml
+++ b/war/src/config/web.xml
@@ -133,17 +133,45 @@
    <servlet-class>com.bigdata.rdf.sail.webapp.CountersServlet</servlet-class>
    <async-supported>true</async-supported>
   </servlet>
+  <servlet>
+   <servlet-name>LDF API</servlet-name>
+   <display-name>LDF API</display-name>
+   <description>API implementing linked data fragments.</description>
+   
<servlet-class>org.wikidata.query.rdf.blazegraph.ldf.LDFServlet</servlet-class>
+   <async-supported>true</async-supported>
+   <init-param>
+     <description>Configuration file for the LDF server.</description>
+     <param-name>configFile</param-name>
+     <param-value>ldf-config.json</param-value>
+   </init-param>
+  </servlet>
+  <servlet>
+    <servlet-name>ldfassets</servlet-name>
+    <servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class>
+    <init-param>
+        <param-name>relativeResourceBase</param-name>
+        <param-value>/html/</param-value>
+    </init-param>
+   </servlet>
   <!-- Note: The HALoadBalancerServlet is deployed from override-web.xml -->
   <!-- Serve anything under /html/* as a simple file. -->
   <servlet-mapping>
     <servlet-name>default</servlet-name>
     <url-pattern>/html/*</url-pattern>
   </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>ldfassets</servlet-name>
+    <url-pattern>/assets/*</url-pattern>
+  </servlet-mapping>
   <!-- Mapping for the default KB namespace (as configured above). -->
   <servlet-mapping>
   <servlet-name>REST API</servlet-name>
   <url-pattern>/sparql</url-pattern>
   </servlet-mapping>
+  <servlet-mapping>
+  <servlet-name>LDF API</servlet-name>
+  <url-pattern>/ldf</url-pattern>
+  </servlet-mapping>
   <!-- Mapping for access to non-default KB namespaces.
   <servlet-mapping>
   <servlet-name>REST API</servlet-name>

-- 
To view, visit https://gerrit.wikimedia.org/r/317114
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I78b4edd4d725d2b87cfead92a35b31b072f31b40
Gerrit-PatchSet: 10
Gerrit-Project: wikidata/query/rdf
Gerrit-Branch: master
Gerrit-Owner: Smalyshev <[email protected]>
Gerrit-Reviewer: Smalyshev <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to