Repository: marmotta Updated Branches: refs/heads/ldp 9c04ea008 -> 8497e8419
MARMOTTA-440: started with a parser for the application/rdf-patch format (http://afs.github.io/rdf-patch/) Project: http://git-wip-us.apache.org/repos/asf/marmotta/repo Commit: http://git-wip-us.apache.org/repos/asf/marmotta/commit/8497e841 Tree: http://git-wip-us.apache.org/repos/asf/marmotta/tree/8497e841 Diff: http://git-wip-us.apache.org/repos/asf/marmotta/diff/8497e841 Branch: refs/heads/ldp Commit: 8497e8419e8bb3d936f63ee6e16c0bc35ed7c4ec Parents: 9c04ea0 Author: Jakob Frank <[email protected]> Authored: Mon Feb 24 20:23:00 2014 +0100 Committer: Jakob Frank <[email protected]> Committed: Mon Feb 24 20:23:00 2014 +0100 ---------------------------------------------------------------------- platform/marmotta-ldp/pom.xml | 36 +++- .../platform/ldp/patch/model/PatchLine.java | 45 +++++ .../marmotta-ldp/src/main/javacc/rdf-patch.jj | 181 +++++++++++++++++++ .../platform/ldp/patch/RdfPatchParserTest.java | 89 +++++++++ .../src/test/resources/illustrative.in.ttl | 11 ++ .../src/test/resources/illustrative.rdfp | 6 + 6 files changed, 367 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/marmotta/blob/8497e841/platform/marmotta-ldp/pom.xml ---------------------------------------------------------------------- diff --git a/platform/marmotta-ldp/pom.xml b/platform/marmotta-ldp/pom.xml index 6f7986d..6f8bdff 100644 --- a/platform/marmotta-ldp/pom.xml +++ b/platform/marmotta-ldp/pom.xml @@ -75,7 +75,41 @@ </pluginManagement> <plugins> - + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>javacc-maven-plugin</artifactId> + <version>2.6</version> + <executions> + <execution> + <id>javacc</id> + <goals> + <goal>javacc</goal> + </goals> + <configuration> + <lookAhead>150</lookAhead> + <isStatic>false</isStatic> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <executions> + <execution> + <id>add-source</id> + <phase>generate-sources</phase> + <goals> + <goal>add-source</goal> + </goals> + <configuration> + <sources> + <source>${project.build.directory}/generated-sources/javacc/</source> + </sources> + </configuration> + </execution> + </executions> + </plugin> <plugin> <groupId>org.apache.marmotta</groupId> <artifactId>buildinfo-maven-plugin</artifactId> http://git-wip-us.apache.org/repos/asf/marmotta/blob/8497e841/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/patch/model/PatchLine.java ---------------------------------------------------------------------- diff --git a/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/patch/model/PatchLine.java b/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/patch/model/PatchLine.java new file mode 100644 index 0000000..971b86a --- /dev/null +++ b/platform/marmotta-ldp/src/main/java/org/apache/marmotta/platform/ldp/patch/model/PatchLine.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.marmotta.platform.ldp.patch.model; + +import org.openrdf.model.Statement; + +/** + * Created by jakob on 2/24/14. + */ +public class PatchLine { + public enum Operator {DEL, ADD} + + + private final Operator operator; + private final Statement statement; + + public PatchLine(Operator operator, Statement statement) { + + this.operator = operator; + this.statement = statement; + } + + public Operator getOperator() { + return operator; + } + + public Statement getStatement() { + return statement; + } +} http://git-wip-us.apache.org/repos/asf/marmotta/blob/8497e841/platform/marmotta-ldp/src/main/javacc/rdf-patch.jj ---------------------------------------------------------------------- diff --git a/platform/marmotta-ldp/src/main/javacc/rdf-patch.jj b/platform/marmotta-ldp/src/main/javacc/rdf-patch.jj new file mode 100644 index 0000000..a8a685f --- /dev/null +++ b/platform/marmotta-ldp/src/main/javacc/rdf-patch.jj @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2013 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + options +{ + STATIC=false; + LOOKAHEAD=150; + CACHE_TOKENS=true; +// FORCE_LA_CHECK=true; +// CHOICE_AMBIGUITY_CHECK=5; +// LOOKAHEAD=2147483647; +// DEBUG_PARSER=true; +// DEBUG_TOKEN_MANAGER=true; +// DEBUG_LOOKAHEAD=true; +} + +PARSER_BEGIN(RdfPatchParser) +package org.apache.marmotta.platform.ldp.patch; + +import org.openrdf.model.*; +import org.openrdf.model.impl.*; + +import org.apache.marmotta.platform.ldp.patch.model.*; +import org.openrdf.rio.turtle.TurtleUtil; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +public class RdfPatchParser { + + private HashMap<String, String> namespaces = new HashMap<String, String>(); + + private URI createURI(String uri) { + return new URIImpl(unwrapUri(uri)); + } + + private URI createURI(String prefix, String local) { + return new URIImpl(namespaces.get(prefix)+local); + } + + private BNode createBNode(String id) { + return new BNodeImpl(id); + } + + private Literal createLiteral(String value, String lang, String type) { + value = TurtleUtil.decodeString(value.substring(1, value.length() -2)); + if (lang != null) { + return new LiteralImpl(value, lang); + } else if (type != null) { + return new LiteralImpl(value, createURI(type)); + } else { + return new LiteralImpl(value); + } + } + + private Literal createLongLiteral(String value, String lang, String type) { + value = value.substring(2, value.length() - 4); + return createLiteral(value, lang, type); + } + + private String unwrapUri(String uri) { + if (uri.startsWith("<")) { + uri = uri.substring(1); + } + if (uri.endsWith(">")) { + uri = uri.substring(0, uri.length()-1); + } + return uri; + } + +} +PARSER_END(RdfPatchParser) + +SKIP : { + " " +| "\r" +| "\t" +| "\n" +} + +MORE: { + "\"\"\"" : WithinLongString | + "\"" : WithinString +} + +<WithinString> TOKEN: { + <STRLIT: "\""> : DEFAULT +} + +<WithinLongString> TOKEN: { + <STRLONGLIT: "\"\"\""> : DEFAULT +} + + +<WithinString> MORE: { + <~["\n","\r"]> +} + +<WithinLongString> MORE: { + <~[]> +} + +TOKEN : { + < ADD: "A" > | + < DEL: "D" > | + < REPEAT: "R" > | + < UNDEFINED: "U" > | + < PREFIX: "@prefix" > | + < DOT: "." > | + < COLON: ":" > | + < BNODE: "_:" > | + < URI: "<" (~[ ">","<", "\"", "{", "}", "^", "\\", "|", "`", "\u0000"-"\u0020"])+ ">" > | + < IDENT: ["a"-"z","A"-"Z","0"-"9","_"](["a"-"z","A"-"Z","0"-"9","_","'","-", "."])* > | + < LANG: "@" > | + < TYPE: "^^" > +} + +SPECIAL_TOKEN : { + <COMMENT: "#" (~["\n","\r"])* ("\n"|"\r"|"\r\n")> +} + + + +public List<PatchLine> parsePatch() : { + Token id, prefix; + Statement statement; + LinkedList<PatchLine> diff = new LinkedList<PatchLine>(); + namespaces.clear(); +} +{ + ( <PREFIX> id = <IDENT> <COLON> prefix = <URI> <DOT> { namespaces.put(id.image, unwrapUri(prefix.image));} )* {} + ( + ( <ADD> statement = parseStatement() <DOT> { diff.add(new PatchLine(PatchLine.Operator.ADD, statement)); } ) | + ( <DEL> statement = parseStatement() <DOT> { diff.add(new PatchLine(PatchLine.Operator.DEL, statement)); } ) + )* + <EOF> + { + return diff; + } +} + +private Statement parseStatement() : { + Token t1 = null, t2 = null, t3 = null; + Resource subject; + URI predicate; + Value object; +} +{ + ( t1 = <URI> { subject = createURI(t1.image); } | + t1 = <IDENT> <COLON> t2 = <IDENT> { subject = createURI(t1.image, t2.image); } | + <BNODE> t1 = <IDENT> { subject = createBNode(t1.image); } | + <REPEAT> { subject = null; } + ) + ( t1 = <URI> { predicate = createURI(t1.image); } | + <REPEAT> { predicate = null; } + ) + ( t1 = <URI> { object = createURI(t1.image); } | + <BNODE> t1 = <IDENT> { object = createBNode(t1.image); } | + t1 = <STRLIT> (<LANG> t2 = <IDENT>)? (<TYPE> t3 = <URI>)? { + object = createLiteral(t1.image, t2!=null?t2.image:null, t3!=null?t3.image:null); + } | + t1 = <STRLONGLIT> (<LANG> t2 = <IDENT>)? (<TYPE> t3 = <URI>)? { + object = createLongLiteral(t1.image, t2!=null?t2.image:null, t3!=null?t3.image:null); + } | + <REPEAT> { object = null; } + ) + { return new StatementImpl(subject, predicate, object); } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/marmotta/blob/8497e841/platform/marmotta-ldp/src/test/java/org/apache/marmotta/platform/ldp/patch/RdfPatchParserTest.java ---------------------------------------------------------------------- diff --git a/platform/marmotta-ldp/src/test/java/org/apache/marmotta/platform/ldp/patch/RdfPatchParserTest.java b/platform/marmotta-ldp/src/test/java/org/apache/marmotta/platform/ldp/patch/RdfPatchParserTest.java new file mode 100644 index 0000000..6c63013 --- /dev/null +++ b/platform/marmotta-ldp/src/test/java/org/apache/marmotta/platform/ldp/patch/RdfPatchParserTest.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.marmotta.platform.ldp.patch; + +import org.apache.marmotta.commons.vocabulary.FOAF; +import org.apache.marmotta.platform.ldp.patch.model.PatchLine; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.openrdf.model.*; +import org.openrdf.model.impl.LiteralImpl; +import org.openrdf.model.impl.URIImpl; + +import java.util.Iterator; +import java.util.List; + +/** + * Created by jakob on 2/24/14. + */ +public class RdfPatchParserTest { + + + private RdfPatchParser parser; + private URI alice, bob, charlie; + private Literal lcBob, ucBob; + + @Before + public void setUp() { + parser = new RdfPatchParser(this.getClass().getResourceAsStream("/illustrative.rdfp")); + + alice = new URIImpl("http://example/alice"); + bob = new URIImpl("http://example/bob"); + charlie = new URIImpl("http://example/charlie"); + + lcBob = new LiteralImpl("bob"); + ucBob = new LiteralImpl("Bob"); + } + + @After + public void tearDown() { + parser = null; + } + + + @Test + public void testParsing() throws ParseException { + List<PatchLine> patchLines = parser.parsePatch(); + + Iterator<PatchLine> it = patchLines.iterator(); + + Assert.assertTrue(it.hasNext()); + checkPatchLine(it.next(), PatchLine.Operator.DEL, bob, FOAF.name, lcBob); + + Assert.assertTrue(it.hasNext()); + checkPatchLine(it.next(), PatchLine.Operator.ADD, null, FOAF.name, lcBob); + + Assert.assertTrue(it.hasNext()); + checkPatchLine(it.next(), PatchLine.Operator.ADD, null, FOAF.knows, alice); + + Assert.assertTrue(it.hasNext()); + checkPatchLine(it.next(), PatchLine.Operator.DEL, null, null, charlie); + } + + private void checkPatchLine(PatchLine line, PatchLine.Operator operator, Resource subejct, URI predicate, Value object) { + Assert.assertEquals("Wrong patch operation", operator, line.getOperator()); + + Statement statement = line.getStatement(); + Assert.assertEquals("Wrong subject", subejct, statement.getSubject()); + Assert.assertEquals("Wrong predicate", predicate, statement.getPredicate()); + Assert.assertEquals("Wrong object", object, statement.getObject()); + } + +} http://git-wip-us.apache.org/repos/asf/marmotta/blob/8497e841/platform/marmotta-ldp/src/test/resources/illustrative.in.ttl ---------------------------------------------------------------------- diff --git a/platform/marmotta-ldp/src/test/resources/illustrative.in.ttl b/platform/marmotta-ldp/src/test/resources/illustrative.in.ttl new file mode 100644 index 0000000..be04c27 --- /dev/null +++ b/platform/marmotta-ldp/src/test/resources/illustrative.in.ttl @@ -0,0 +1,11 @@ +@prefix foaf: <http://xmlns.com/foaf/0.1/> . + +<http://example/bob> a foaf:Person; + foaf:name "bob" ; + foaf:knows <http://example/charlie>. + +<http://example/alice> a foaf:Person; + foaf:name "Alice" . + +<http://example/charlie> a foaf:Person; + foaf:name "Charlie" . http://git-wip-us.apache.org/repos/asf/marmotta/blob/8497e841/platform/marmotta-ldp/src/test/resources/illustrative.rdfp ---------------------------------------------------------------------- diff --git a/platform/marmotta-ldp/src/test/resources/illustrative.rdfp b/platform/marmotta-ldp/src/test/resources/illustrative.rdfp new file mode 100644 index 0000000..69ac715 --- /dev/null +++ b/platform/marmotta-ldp/src/test/resources/illustrative.rdfp @@ -0,0 +1,6 @@ +@prefix foaf: <http://xmlns.com/foaf/0.1/> . + +D <http://example/bob> foaf:name "bob" . +A <http://example/bob> foaf:name "Bob" . +A R foaf:knows <http://example/alice> . +D R R <http://example/charlie> .
