Merge pull request #997 from afs/rdf-star-expr
JENA-2101: Expression use of <<>>
diff --git a/jena-arq/src/main/java/org/apache/jena/rdfs/assembler/VocabRDFS.java b/jena-arq/src/main/java/org/apache/jena/rdfs/assembler/VocabRDFS.java
index 2745a9b..5ba42bd 100644
--- a/jena-arq/src/main/java/org/apache/jena/rdfs/assembler/VocabRDFS.java
+++ b/jena-arq/src/main/java/org/apache/jena/rdfs/assembler/VocabRDFS.java
@@ -20,12 +20,9 @@
import org.apache.jena.assembler.Assembler;
import org.apache.jena.assembler.JA;
-import org.apache.jena.irix.IRIException;
-import org.apache.jena.irix.IRIx;
import org.apache.jena.rdf.model.Property;
import org.apache.jena.rdf.model.Resource;
import org.apache.jena.rdf.model.ResourceFactory;
-import org.apache.jena.shared.JenaException;
import org.apache.jena.sparql.core.assembler.AssemblerUtils;
import org.apache.jena.sparql.core.assembler.DatasetAssemblerVocab;
import org.apache.jena.sys.JenaSystem;
@@ -64,13 +61,6 @@
private static String iri(String localname) {
String uri = NS + localname;
- try {
- IRIx iri = IRIx.create(uri);
- if ( ! iri.isReference() )
- throw new JenaException("Bad IRI (relative): "+uri);
- return uri;
- } catch (IRIException ex) {
- throw new JenaException("Bad IRI: "+uri);
- }
+ return uri;
}
}
diff --git a/jena-arq/src/main/java/org/apache/jena/riot/RDFParser.java b/jena-arq/src/main/java/org/apache/jena/riot/RDFParser.java
index 4e75027..eaa926b 100644
--- a/jena-arq/src/main/java/org/apache/jena/riot/RDFParser.java
+++ b/jena-arq/src/main/java/org/apache/jena/riot/RDFParser.java
@@ -36,6 +36,7 @@
import org.apache.jena.atlas.web.ContentType;
import org.apache.jena.atlas.web.TypedInputStream;
import org.apache.jena.graph.Graph;
+import org.apache.jena.irix.IRIs;
import org.apache.jena.irix.IRIxResolver;
import org.apache.jena.query.Dataset;
import org.apache.jena.rdf.model.Model;
@@ -446,12 +447,17 @@
} else {
if ( ! strict )
checking$ = checking.orElseGet(()->true);
+ // Languages, like Turtle, where the base defaults to the system base.
+ // Setting the resolver directly overrides this.
+ if ( baseStr == null && resolve )
+ baseStr = IRIs.getBaseStr();
}
if ( sameLang(RDFJSON, lang) )
// The JSON-LD subsystem handles this.
resolve = false;
- IRIxResolver parserResolver = (resolver != null) ? resolver
+ IRIxResolver parserResolver = (resolver != null)
+ ? resolver
: IRIxResolver.create().base(baseStr).resolve(resolve).allowRelative(allowRelative).build();
PrefixMap prefixMap = PrefixMapFactory.create();
ParserProfileStd parserFactory = new ParserProfileStd(factory, errorHandler,
diff --git a/jena-arq/src/main/java/org/apache/jena/riot/lang/CollectorStreamRDF.java b/jena-arq/src/main/java/org/apache/jena/riot/lang/CollectorStreamRDF.java
index 2964be6..f25e66b 100644
--- a/jena-arq/src/main/java/org/apache/jena/riot/lang/CollectorStreamRDF.java
+++ b/jena-arq/src/main/java/org/apache/jena/riot/lang/CollectorStreamRDF.java
@@ -28,7 +28,7 @@
import org.apache.jena.sparql.core.Quad ;
/**
- * StreamRDF implementations which store received triples and quads
+ * StreamRDF implementations which stores received triples and quads
* in a {@link java.util.Collection}.
*
* The resulting collection can be retrieved via the
diff --git a/jena-arq/src/main/java/org/apache/jena/riot/system/Checker.java b/jena-arq/src/main/java/org/apache/jena/riot/system/Checker.java
index a7cb727..9fe0512 100644
--- a/jena-arq/src/main/java/org/apache/jena/riot/system/Checker.java
+++ b/jena-arq/src/main/java/org/apache/jena/riot/system/Checker.java
@@ -29,8 +29,10 @@
import org.apache.jena.iri.IRI;
import org.apache.jena.iri.IRIComponents;
import org.apache.jena.iri.Violation;
+import org.apache.jena.irix.IRIProviderJenaIRI;
import org.apache.jena.irix.IRIs;
import org.apache.jena.irix.SetupJenaIRI;
+import org.apache.jena.irix.SystemIRIx;
import org.apache.jena.sparql.core.Quad;
import org.apache.jena.sparql.graph.NodeConst;
import org.apache.jena.util.SplitIRI;
@@ -121,8 +123,10 @@
public static boolean iriViolations(IRI iri, ErrorHandler errorHandler,
boolean allowRelativeIRIs, boolean includeIRIwarnings,
long line, long col) {
+
if ( !allowRelativeIRIs && iri.isRelative() )
- errorHandler(errorHandler).error("Relative IRI: " + iri, line, col);
+ // Relative IRIs.
+ iriViolationMessage(iri.toString(), true, "Relative IRI: " + iri, line, col, errorHandler);
boolean isOK = true;
@@ -134,26 +138,47 @@
int code = v.getViolationCode();
boolean isError = v.isError();
- // Anything we want to reprioritise?
+ // --- Tune warnings.
+ // IRIProviderJena filters ERRORs and throws an exception on error.
+ // It can't add warnings or remove them at that point.
+ // Do WARN filtering here.
if ( code == Violation.LOWERCASE_PREFERRED && v.getComponent() != IRIComponents.SCHEME ) {
- // Issue warning about the scheme part. Not e.g. DNS names.
+ // Issue warning about the scheme part only. Not e.g. DNS names.
continue;
}
+
+ // Convert selected violations from ERROR to WARN for output/
+ // There are cases where jena-iri always makes a violation an ERROR regardless of SetupJenaIRI
+ // PROHIBITED_COMPONENT_PRESENT
+// if ( code == Violation.PROHIBITED_COMPONENT_PRESENT )
+// isError = false;
+
+ isOK = false;
String msg = v.getShortMessage();
String iriStr = iri.toString();
-
- errorHandler(errorHandler).warning("Bad IRI: " + msg, line, col);
-
-// if ( isError )
-// errorHandler(errorHandler).warning("Bad IRI: " + msg, line, col);
-// else
-// errorHandler(errorHandler).warning("Not advised IRI: " + msg, line, col);
- isOK = true;
+ iriViolationMessage(iriStr, isError, msg, line, col, errorHandler);
}
}
return isOK;
}
+ /**
+ * Common handling messages about IRIs during parsing whether a violation or an
+ * IRIException. Prints a warning, with different messages for IRI error or warning.
+ */
+ public static void iriViolationMessage(String iriStr, boolean isError, String msg, long line, long col, ErrorHandler errorHandler) {
+ try {
+ if ( ! ( SystemIRIx.getProvider() instanceof IRIProviderJenaIRI ) )
+ msg = "<" + iriStr + "> : " + msg;
+
+ if ( isError ) {
+ // ?? Treat as error, catch exceptions?
+ errorHandler(errorHandler).warning("Bad IRI: " + msg, line, col);
+ } else
+ errorHandler(errorHandler).warning("Not advised IRI: " + msg, line, col);
+ } catch (org.apache.jena.iri.IRIException | org.apache.jena.irix.IRIException ex) {}
+ }
+
// ==== Literals
final static private Pattern langPattern = Pattern.compile("[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*");
diff --git a/jena-arq/src/main/java/org/apache/jena/riot/system/ErrorHandlerFactory.java b/jena-arq/src/main/java/org/apache/jena/riot/system/ErrorHandlerFactory.java
index 197acc8..28eafbe 100644
--- a/jena-arq/src/main/java/org/apache/jena/riot/system/ErrorHandlerFactory.java
+++ b/jena-arq/src/main/java/org/apache/jena/riot/system/ErrorHandlerFactory.java
@@ -66,7 +66,8 @@
public static ErrorHandler errorHandlerSimple() { return new ErrorHandlerSimple() ; }
/** Logs warnings and errors while tracking the counts of each and optionally throwing exceptions when errors and/or warnings are encounted */
- public static ErrorHandlerTracking errorHandlerTracking(Logger log, boolean failOnError, boolean failOnWarning) { return new ErrorHandlerTracking(log, failOnError, failOnWarning); }
+ public static ErrorHandlerTracking errorHandlerTracking(Logger log, boolean failOnError, boolean failOnWarning)
+ { return new ErrorHandlerTracking(log, failOnError, failOnWarning); }
/**
* An error handler that throws a {@link RiotParseException}, hence it
diff --git a/jena-arq/src/main/java/org/apache/jena/riot/system/ParserProfileStd.java b/jena-arq/src/main/java/org/apache/jena/riot/system/ParserProfileStd.java
index 165ea1f..a3f3d3a 100644
--- a/jena-arq/src/main/java/org/apache/jena/riot/system/ParserProfileStd.java
+++ b/jena-arq/src/main/java/org/apache/jena/riot/system/ParserProfileStd.java
@@ -34,26 +34,24 @@
import org.apache.jena.sparql.util.FmtUtils;
/**
- * {@link ParserProfileStd} uses a {@link FactoryRDF} to
- * create items in the parsing process.
+ * {@link ParserProfileStd} uses a {@link FactoryRDF} to create items in the parsing
+ * process.
*/
-public class ParserProfileStd implements ParserProfile
-{
- private final FactoryRDF factory;
+public class ParserProfileStd implements ParserProfile {
+ private final FactoryRDF factory;
private final ErrorHandler errorHandler;
- private final Context context;
- private IRIxResolver resolver;
- private final PrefixMap prefixMap;
- private final boolean strictMode;
- private final boolean checking;
+ private final Context context;
+ private IRIxResolver resolver;
+ private final PrefixMap prefixMap;
+ private final boolean strictMode;
+ private final boolean checking;
private static int DftCacheSize = 500;
private final Cache<String, IRI> iriCache;
private boolean allowNodeExtentions;
- public ParserProfileStd(FactoryRDF factory, ErrorHandler errorHandler,
- IRIxResolver resolver, PrefixMap prefixMap,
- Context context, boolean checking, boolean strictMode) {
+ public ParserProfileStd(FactoryRDF factory, ErrorHandler errorHandler, IRIxResolver resolver, PrefixMap prefixMap, Context context,
+ boolean checking, boolean strictMode) {
this.factory = factory;
this.errorHandler = errorHandler;
this.resolver = resolver;
@@ -62,7 +60,7 @@
this.checking = checking;
this.iriCache = checking ? CacheFactory.createCache(DftCacheSize) : null;
this.strictMode = strictMode;
- this.allowNodeExtentions = true; //(context.isTrue(RIOT.ALLOW_NODE_EXT)) ;
+ this.allowNodeExtentions = true; // (context.isTrue(RIOT.ALLOW_NODE_EXT)) ;
}
@Override
@@ -98,21 +96,20 @@
return IRIx.createAny(uriStr);
}
+ // Relative IRIs.
+ // jena-iri : these are errors on the
try {
IRIx iri = resolver.resolve(uriStr);
if ( checking )
doChecking(iri, iri.str(), line, col);
return iri;
+ } catch (RelativeIRIException ex ) {
+ errorHandler.error("Relative IRI: " + uriStr, line, col);
+ return IRIx.createAny(uriStr);
} catch (IRIException ex) {
- // This should only be errors and the errorHandler may be set to "don't continue".
- // if it does continue, assume it prints something.
- if ( SystemIRIx.getProvider() instanceof IRIProviderJenaIRI )
- // Checking using JenaIRI puts the URI string in the message.
- // Puts the IRI in the message.
- errorHandler.error("Bad IRI: "+ex.getMessage(), line, col);
- else
- // Does not put the IRI in the message.
- errorHandler.error("Bad IRI: <" + uriStr + "> : "+ex.getMessage(), line, col);
+ // Same code as Checker.iriViolations
+ String msg = ex.getMessage();
+ Checker.iriViolationMessage(uriStr, true, msg, line, col, errorHandler);
return IRIx.createAny(uriStr);
}
}
@@ -122,11 +119,14 @@
if ( irix instanceof IRIProviderJenaIRI.IRIxJena )
iri = (IRI)irix.getImpl();
else
- iri = iriCache.getOrFill(uriStr, ()->SetupJenaIRI.iriCheckerFactory().create(uriStr));
+ iri = iriCache.getOrFill(uriStr, () -> SetupJenaIRI.iriCheckerFactory().create(uriStr));
Checker.iriViolations(iri, errorHandler, false, true, line, col);
}
- /** Create a triple - this operation call {@link #checkTriple} if checking is enabled. */
+ /**
+ * Create a triple - this operation call {@link #checkTriple} if checking is
+ * enabled.
+ */
@Override
public Triple createTriple(Node subject, Node predicate, Node object, long line, long col) {
if ( checking )
@@ -140,7 +140,7 @@
protected void checkTriple(Node subject, Node predicate, Node object, long line, long col) {
if ( subject == null || (!subject.isURI() && !subject.isBlank()) ) {
- if ( ! allowSpecialNode(subject) ) {
+ if ( !allowSpecialNode(subject) ) {
errorHandler.error("Subject is not a URI or blank node", line, col);
throw new RiotException("Bad subject: " + subject);
}
@@ -150,14 +150,17 @@
throw new RiotException("Bad predicate: " + predicate);
}
if ( object == null || (!object.isURI() && !object.isBlank() && !object.isLiteral()) ) {
- if ( ! allowSpecialNode(object) ) {
+ if ( !allowSpecialNode(object) ) {
errorHandler.error("Object is not a URI, blank node or literal", line, col);
throw new RiotException("Bad object: " + object);
}
}
}
- /** Create a quad - this operation call {@link #checkTriple} if checking is enabled. */
+ /**
+ * Create a quad - this operation call {@link #checkTriple} if checking is
+ * enabled.
+ */
@Override
public Quad createQuad(Node graph, Node subject, Node predicate, Node object, long line, long col) {
if ( checking )
@@ -177,8 +180,8 @@
@Override
public Node createURI(String x, long line, long col) {
// Special cases that don't resolve.
- // <_:....> is a blank node.
- // <::...> is "don't touch" used for a fixed-up prefix name
+ // <_:....> is a blank node.
+ // <::...> is "don't touch" used for a fixed-up prefix name
if ( !RiotLib.isBNodeIRI(x) && !RiotLib.isPrefixIRI(x) )
// Really is an URI!
x = resolveIRI(x, line, col);
diff --git a/jena-arq/src/test/java/org/apache/jena/arq/junit/manifest/Manifest.java b/jena-arq/src/test/java/org/apache/jena/arq/junit/manifest/Manifest.java
index 095f4e3..c1458b4 100644
--- a/jena-arq/src/test/java/org/apache/jena/arq/junit/manifest/Manifest.java
+++ b/jena-arq/src/test/java/org/apache/jena/arq/junit/manifest/Manifest.java
@@ -65,7 +65,6 @@
}
}
-
private Manifest(String fn) {
filename = IRILib.filenameToIRI(fn) ;
manifest = RDFDataMgr.loadModel(filename) ;
diff --git a/jena-arq/src/test/java/org/apache/jena/arq/junit/riot/RiotSyntaxTest.java b/jena-arq/src/test/java/org/apache/jena/arq/junit/riot/RiotSyntaxTest.java
index 24b5ebb..35042ba 100644
--- a/jena-arq/src/test/java/org/apache/jena/arq/junit/riot/RiotSyntaxTest.java
+++ b/jena-arq/src/test/java/org/apache/jena/arq/junit/riot/RiotSyntaxTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.fail;
import org.apache.jena.arq.junit.manifest.ManifestEntry;
+import org.apache.jena.atlas.io.IO;
import org.apache.jena.atlas.lib.FileOps;
import org.apache.jena.atlas.lib.IRILib;
import org.apache.jena.riot.Lang ;
@@ -56,8 +57,13 @@
}
try {
ParseForTest.parse(stream, filename, lang);
- if (! expectLegalSyntax )
+ if (! expectLegalSyntax ) {
+ String s = IO.readWholeFileAsUTF8(fn);
+ System.err.println();
+ System.err.println("== "+filename);
+ System.err.print(s);
fail("Parsing succeeded in a bad syntax test");
+ }
} catch(RiotNotFoundException ex) {
throw ex;
} catch(RiotException ex) {
diff --git a/jena-arq/src/test/java/org/apache/jena/riot/lang/TestLangNTriples.java b/jena-arq/src/test/java/org/apache/jena/riot/lang/TestLangNTriples.java
index 3d378cf..940f9c9 100644
--- a/jena-arq/src/test/java/org/apache/jena/riot/lang/TestLangNTriples.java
+++ b/jena-arq/src/test/java/org/apache/jena/riot/lang/TestLangNTriples.java
@@ -35,7 +35,7 @@
import org.apache.jena.sparql.sse.SSE ;
import org.junit.Test ;
-/** Test of syntax by a triples parser (does not include node validitiy checking) */
+/** Test of syntax by a triples parser (does not include node validity checking) */
public class TestLangNTriples extends AbstractTestLangNTuples
{
diff --git a/jena-arq/src/test/java/org/apache/jena/riot/lang/TestLangTurtle.java b/jena-arq/src/test/java/org/apache/jena/riot/lang/TestLangTurtle.java
index 47b2eb5..3a13aea 100644
--- a/jena-arq/src/test/java/org/apache/jena/riot/lang/TestLangTurtle.java
+++ b/jena-arq/src/test/java/org/apache/jena/riot/lang/TestLangTurtle.java
@@ -160,10 +160,10 @@
@Test(expected=ExError.class)
public void errorBadURI_1() { parse("<http://example/a b> <http://example/p> 123 .") ; }
- @Test(expected=ExError.class)
+ @Test(expected=ExWarning.class)
public void errorBadURI_2() { parse("<http://example/a%XAb> <http://example/p> 123 .") ; }
- @Test //(expected=ExWarning.class)
+ @Test
public void errorBadURI_3() { parse("<http://example/a%Aab> <http://example/p> 123 .") ; }
// Bad URIs
diff --git a/jena-arq/src/test/java/org/apache/jena/riot/lang/CatchParserOutput.java b/jena-arq/src/test/java/org/apache/jena/riot/system/CatchParserOutput.java
similarity index 77%
rename from jena-arq/src/test/java/org/apache/jena/riot/lang/CatchParserOutput.java
rename to jena-arq/src/test/java/org/apache/jena/riot/system/CatchParserOutput.java
index ed1cb95..d70b543 100644
--- a/jena-arq/src/test/java/org/apache/jena/riot/lang/CatchParserOutput.java
+++ b/jena-arq/src/test/java/org/apache/jena/riot/system/CatchParserOutput.java
@@ -16,26 +16,25 @@
* limitations under the License.
*/
-package org.apache.jena.riot.lang;
+package org.apache.jena.riot.system;
import java.util.ArrayList;
import java.util.List;
import org.apache.jena.atlas.lib.Pair;
import org.apache.jena.graph.Triple;
-import org.apache.jena.riot.system.StreamRDF;
import org.apache.jena.sparql.core.Quad;
-class CatchParserOutput implements StreamRDF
+public class CatchParserOutput implements StreamRDF
{
- List<Triple> triples = new ArrayList<>() ;
- List<Quad> quads = new ArrayList<>() ;
- List<Pair<String,String>> prefixes = new ArrayList<>() ;
- List<String> bases = new ArrayList<>() ;
+ public List<Triple> triples = new ArrayList<>() ;
+ public List<Quad> quads = new ArrayList<>() ;
+ public List<Pair<String,String>> prefixes = new ArrayList<>() ;
+ public List<String> bases = new ArrayList<>() ;
- int startCalled = 0 ;
+ public int startCalled = 0 ;
- int finishCalled = 0 ;
+ public int finishCalled = 0 ;
@Override public void start() { startCalled++ ; }
diff --git a/jena-arq/src/test/java/org/apache/jena/riot/system/TS_RiotSystem.java b/jena-arq/src/test/java/org/apache/jena/riot/system/TS_RiotSystem.java
index 4f77e8b..c49b175 100644
--- a/jena-arq/src/test/java/org/apache/jena/riot/system/TS_RiotSystem.java
+++ b/jena-arq/src/test/java/org/apache/jena/riot/system/TS_RiotSystem.java
@@ -44,6 +44,7 @@
, TestFormatRegistration.class
, TestJsonLDReadWrite.class // Some simple testing of the jsonld-java engine.
, TestSerializable.class
+ , TestIRIxRIOT.class
})
public class TS_RiotSystem
diff --git a/jena-arq/src/test/java/org/apache/jena/riot/system/TestChecker.java b/jena-arq/src/test/java/org/apache/jena/riot/system/TestChecker.java
index 63d7549..caeb426 100644
--- a/jena-arq/src/test/java/org/apache/jena/riot/system/TestChecker.java
+++ b/jena-arq/src/test/java/org/apache/jena/riot/system/TestChecker.java
@@ -20,7 +20,6 @@
import org.apache.jena.graph.Node ;
import org.apache.jena.riot.ErrorHandlerTestLib ;
-import org.apache.jena.riot.ErrorHandlerTestLib.ExError ;
import org.apache.jena.riot.ErrorHandlerTestLib.ExWarning ;
import org.apache.jena.shared.impl.JenaParameters ;
import org.apache.jena.sparql.util.NodeFactoryExtra ;
@@ -49,7 +48,7 @@
@Test
public void checker_uri_01() { check("<http://example/x>") ; }
- @Test(expected=ExError.class)
+ @Test(expected=ExWarning.class)
public void checker_uri_02() { check("<x>") ; }
@Test (expected=ExWarning.class)
diff --git a/jena-arq/src/test/java/org/apache/jena/riot/system/TestIRIxRIOT.java b/jena-arq/src/test/java/org/apache/jena/riot/system/TestIRIxRIOT.java
new file mode 100644
index 0000000..dd1d50a
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/riot/system/TestIRIxRIOT.java
@@ -0,0 +1,260 @@
+/*
+ * 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.jena.riot.system;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.jena.atlas.lib.Bytes;
+import org.apache.jena.irix.IRIs;
+import org.apache.jena.irix.IRIxResolver;
+import org.apache.jena.riot.Lang;
+import org.apache.jena.riot.RDFParser;
+import org.apache.jena.riot.RDFParserBuilder;
+import org.apache.jena.riot.RiotException;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/** Test IRIx in parser usage. */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class TestIRIxRIOT {
+
+ // The cases:
+ // _nt :: N-triples, default configuration.
+ // _nt_check :: N-triples, with checking.
+ // _ttl :: Turtle, default configuration (which is checking).
+
+ @Test public void irix_http_1_nt() { testDft("<http://example/>", Lang.NT, 0, 0); }
+ @Test public void irix_http_1_nt_check() { testNT("<http://example/>", TRUE, UNSET, 0, 0); }
+ @Test public void irix_http_1_ttl() { testDft("<http://example/>", Lang.TTL, 0, 0); }
+
+ @Test public void irix_http_2_nt() { testDft("<HTTP://example/>", Lang.NT, 0, 0); }
+ @Test public void irix_http_2_nt_check() { testLang("<HTTP://example/>", Lang.NT, UNSET, TRUE, 0, 1); }
+ @Test public void irix_http_2_ttl() { testDft("<HTTP://example/>", Lang.TTL, 0, 1); }
+
+ @Test public void irix_http_3_nt() { testDft("<http://EXAMPLE/>", Lang.NT, 0, 0); }
+ @Test public void irix_http_3_nt_check() { testLang("<http://EXAMPLE/>", Lang.NT, UNSET, TRUE, 0, 0); }
+ @Test public void irix_http_3_ttl() { testDft("<http://EXAMPLE/>", Lang.TTL, 0, 0); }
+
+ @Test public void irix_http_4_nt() { testDft("<http://user:pw@host/>", Lang.NT, 0, 0); }
+ @Test public void irix_http_4_nt_check() { testLang("<http://user:pw@host/>", Lang.NT, UNSET, TRUE, 0, 2); }
+ @Test public void irix_http_4_ttl() { testDft("<http://user:pw@host/>", Lang.TTL, 0, 2); }
+
+ @Test public void irix_uuid_1_nt() { testDft("<urn:uuid:6cd401dc-a8d2-11eb-9192-1f162b53dc79>", Lang.NT, 0, 0); }
+ @Test public void irix_uuid_1_nt_check() { testLang("<urn:uuid:6cd401dc-a8d2-11eb-9192-1f162b53dc79>", Lang.NT, UNSET, TRUE, 0, 0); }
+ @Test public void irix_uuid_1_ttl() { testDft("<urn:uuid:6cd401dc-a8d2-11eb-9192-1f162b53dc79>", Lang.TTL, 0, 0); }
+
+ @Test public void irix_uuid_2_nt() { testDft("<urn:uuid:bad>", Lang.NT, 0, 1); }
+ @Test public void irix_uuid_2_nt_check() { testLang("<urn:uuid:bad>", Lang.NT, UNSET, TRUE, 0, 1); }
+ @Test public void irix_uuid_2_ttl() { testDft("<urn:uuid:bad>", Lang.TTL, 0, 1); }
+
+ @Test public void irix_uuid_3_nt() { testDft("<urn:uuid:bad>", Lang.NT, 0, 1); }
+ @Test public void irix_uuid_3_nt_check() { testLang("<urn:uuid:bad>", Lang.NT, UNSET, TRUE, 0, 1); }
+ @Test public void irix_uuid_3_ttl() { testDft("<urn:uuid:bad>", Lang.TTL, 0, 1); }
+
+ @Test public void irix_uuid_4_nt() { testDft("<uuid:bad>", Lang.NT, 0, 1); }
+ @Test public void irix_uuid_4_nt_check() { testLang("<uuid:bad>", Lang.NT, UNSET, TRUE, 0, 1); }
+ @Test public void irix_uuid_4_ttl() { testDft("<uuid:bad>", Lang.TTL, 0, 1); }
+
+ @Test public void irix_urn_1_nt() { testDft("<urn:ab:c>", Lang.NT, 0, 0); }
+ @Test public void irix_urn_1_nt_check() { testLang("<urn:ab:c>", Lang.NT, UNSET, TRUE, 0, 0); }
+ @Test public void irix_urn_1_ttl() { testDft("<urn:ab:c>", Lang.TTL, 0, 0); }
+
+ // URNs are required to have 2+ character NID : RFC 8141
+ @Test public void irix_urn_2_nt() { testDft("<urn:x:c>", Lang.NT, 0, 0); }
+ @Test public void irix_urn_2_nt_check() { testLang("<urn:x:c>", Lang.NT, UNSET, TRUE, 0, 1); }
+ @Test public void irix_urn_2_ttl() { testDft("<urn:x:c>", Lang.TTL, 0, 1); }
+
+ @Test public void irix_urn_3_nt() { testDft("<urn:00:c>", Lang.NT, 0, 0); }
+ @Test public void irix_urn_3_nt_check() { testLang("<urn:00:c>", Lang.NT, UNSET, TRUE, 0, 0); }
+ @Test public void irix_urn_3_ttl() { testDft("<urn:00:c>", Lang.TTL, 0, 0); }
+
+ // URIs
+ @Test public void irix_err_1_nt() { testDft("<http://host/bad path/>", Lang.NT, 1, 1); }
+ @Test public void irix_err_1_nt_check() { testLang("<http://host/bad path/>", Lang.NT, UNSET, TRUE, 1, 1); }
+ @Test public void irix_err_1_ttl() { testDft("<http://host/bad path/>", Lang.TTL, 1, 1); }
+
+ // NT: Relative URI
+ @Test public void irix_relative_nt() { testNT("<relative>", UNSET, UNSET, 0, 0); }
+ @Test public void irix_relative_nt_check() { testNT("<relative>", UNSET, TRUE, 0, 1); }
+ @Test public void irix_relative_nt_strict() { testNT("<relative>", TRUE, UNSET, 1, 0); }
+ @Test public void irix_relative_nt_strict_check() { testNT("<relative>", TRUE, TRUE, 1, 0); }
+ @Test public void irix_relative_nt_strict_nocheck() { testNT("<relative>", TRUE, FALSE, 1, 0); }
+
+ // -------- Special cases for Turtle.
+ // Turtle - base defaults to system base in normal use.
+
+ @Test
+ public void irix_relative_3_ttl() {
+ assumeTrue(IRIs.getBaseStr() != null);
+ testTTL("<relative>", UNSET, UNSET, 0, 0);
+ }
+
+ // Turtle with directly set resolver, non-standard setup. no base, resolve, no relative IRIs
+ @Test public void irix_ttl_resolver_0() {
+ // Resolver:: default is allowRelative(true)
+ IRIxResolver resolver = IRIxResolver.create().noBase().build();
+ testTTL("<relative>", resolver, 0, 1);
+ }
+
+ @Test public void irix_ttl_resolver_1() {
+ // Resolver:: no base, no relative IRIs -> error.
+ IRIxResolver resolver = IRIxResolver.create().noBase().allowRelative(false).build();
+ testTTL("<relative>", resolver, 1, 0);
+ }
+
+ // Turtle with directly set resolver, non-standard setup. No base, no resolve, no relative IRIs.
+ @Test public void irix_ttl_resolver_2() {
+ // Resolver:: no base, no relative IRIs, no resolving -> error.
+ IRIxResolver resolver = IRIxResolver.create().noBase().resolve(false).allowRelative(false).build();
+ testTTL("<relative>", resolver, 1, 0);
+ }
+
+ @Test public void irix_ttl_resolver_3() {
+ // Resolver:: no base, allow relative IRIs -> warning.
+ IRIxResolver resolver = IRIxResolver.create().noBase().resolve(true).allowRelative(true).build();
+ testTTL("<relative>", resolver, 0, 1);
+ }
+
+ @Test public void irix_ttl_resolver_4() {
+ // Resolver:: no base, allow relative IRIs, no resolving -> warning.
+ IRIxResolver resolver = IRIxResolver.create().noBase().resolve(false).allowRelative(true).build();
+ testTTL("<relative>", resolver, 0, 1);
+ }
+
+ @Test public void irix_ttl_resolver_5() {
+ // Resolver:: no base, allow relative IRIs, no resolving -> warning.
+ IRIxResolver resolver = IRIxResolver.create().noBase().resolve(false).allowRelative(true).build();
+ testTTL("<relative>", resolver, 0, 1);
+ }
+
+ // --------
+
+ private static final Optional<Boolean> TRUE = Optional.of(true);
+ private static final Optional<Boolean> FALSE = Optional.of(false);
+ private static final Optional<Boolean> UNSET = Optional.empty();
+
+ // Default behaviour of Lang.
+ private static void testDft(String iri, Lang lang, int numErrors, int numWarnings) {
+ testLang(iri, lang, /*base*/null, UNSET, UNSET, numErrors, numWarnings);
+ }
+
+ // Behaviour of Lang, toegther with settable strict and checking.
+ private static void testLang(String iri, Lang lang, Optional<Boolean> strict, Optional<Boolean> checking, int numErrors, int numWarnings) {
+ testLang(iri, lang, /*base*/null, strict, checking, numErrors, numWarnings);
+ }
+
+ // N-triples
+ private static void testNT(String iri, Optional<Boolean> strict, Optional<Boolean> checking, int numErrors, int numWarnings) {
+ testLang(iri, Lang.NT, /*base*/null, strict, checking, numErrors, numWarnings);
+ }
+
+ // Turtle, with base.
+ private static void testTTL(String iri, Optional<Boolean> strict, Optional<Boolean> checking, int numErrors, int numWarnings) {
+ testLang(iri, Lang.TTL, "http://base/", strict, checking, numErrors, numWarnings);
+ }
+
+ // Turtle, with resolver
+ private static void testTTL(String iri, IRIxResolver resolver, int numErrors, int numWarnings) {
+ InputStream in = generateSource(iri);
+ RDFParserBuilder builder = RDFParser.source(in).forceLang(Lang.TTL).resolver(resolver);
+ runTest(builder, iri, numErrors, numWarnings);
+ }
+
+ private static void testLang(String iri, Lang lang, String base, Optional<Boolean> strict, Optional<Boolean> checking, int numErrors, int numWarnings) {
+ InputStream in = generateSource(iri);
+ RDFParserBuilder builder = RDFParser.source(in).forceLang(lang);
+ builder.base(base);
+ if ( strict.isPresent() )
+ builder.strict(strict.get());
+ if ( checking.isPresent() )
+ builder.checking(checking.get());
+ runTest(builder, iri, numErrors, numWarnings);
+ }
+
+ private static void runTest(RDFParserBuilder builder, String iri, int numErrors, int numWarnings) {
+ StreamRDF dest = new CatchParserOutput();
+ ErrorHandlerCollector eh = new ErrorHandlerCollector();
+ builder.errorHandler(eh);
+
+ // Do it!
+ builder.build().parse(dest);
+
+ int numErrorsActual = eh.errors.size();
+ int numWarningsActual = eh.warnings.size();
+
+ String msg = "Errors=("+numErrors+",got="+numErrorsActual+") Warnings=("+numWarnings+",got="+numWarningsActual+")";
+
+ if ( numErrors != numErrorsActual || numWarnings != numWarningsActual ) {
+ System.err.println("== "+iri);
+ System.err.println("-- "+msg);
+ if ( numErrorsActual == 0 )
+ System.err.println("Errors: None");
+ else
+ eh.errors.forEach(m->System.err.println("Error: "+m));
+ if ( numWarningsActual == 0 && numWarnings >= 0 )
+ System.err.println("Warnings: None");
+ else
+ eh.warnings.forEach(m->System.err.println("Warnings: "+m));
+ }
+
+ assertEquals("Errors ("+msg+")", numErrors, numErrorsActual);
+ // Only tested if errors passes.
+ // -1 => ignore
+ if ( numWarnings >= 0 )
+ assertEquals("Warnings ("+msg+")", numWarnings, numWarningsActual);
+ }
+
+ private static InputStream generateSource(String iri) {
+ // N-Triples line with test subject
+ String TEXT = iri+" <x:p> <x:o> .";
+ InputStream inText = new ByteArrayInputStream(Bytes.string2bytes(TEXT));
+ return inText;
+ }
+
+ static class ErrorHandlerCollector implements ErrorHandler {
+ List<String> warnings = new ArrayList<>();
+ List<String> errors = new ArrayList<>();
+ List<String> fatals = new ArrayList<>();
+
+ @Override
+ public void warning(String message, long line, long col) {
+ warnings.add(message);
+ }
+
+ @Override
+ public void error(String message, long line, long col) {
+ errors.add(message);
+ //throw new RiotException(message);
+ }
+
+ @Override
+ public void fatal(String message, long line, long col) {
+ fatals.add(message);
+ throw new RiotException(message);
+ }
+ }
+}
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/EscapeStr.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/EscapeStr.java
index 7d780e5..a6c3455 100644
--- a/jena-base/src/main/java/org/apache/jena/atlas/lib/EscapeStr.java
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/EscapeStr.java
@@ -145,7 +145,7 @@
/** Unicode escapes \-u and \-U only */
public static String unescapeUnicode(String s) {
- return unescape(s, '\\', true) ;
+ return unescape(s, '\\', true) ;
}
// Main worker function for unescaping strings.
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/StrUtils.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/StrUtils.java
index c771acf..5ad6a9d 100644
--- a/jena-base/src/main/java/org/apache/jena/atlas/lib/StrUtils.java
+++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/StrUtils.java
@@ -35,7 +35,7 @@
public class StrUtils //extends StringUtils
{
private StrUtils() {}
-
+
/** strjoin with a newline as the separator */
public static String strjoinNL(String... args) {
return String.join("\n", args);
@@ -56,10 +56,10 @@
public static final int CMP_GREATER = +1 ;
public static final int CMP_EQUAL = 0 ;
public static final int CMP_LESS = -1 ;
-
+
public static final int CMP_UNEQUAL = -9 ;
public static final int CMP_INDETERMINATE = 2 ;
-
+
public static int strCompare(String s1, String s2) {
// Value is the difference of the first differing chars
int x = s1.compareTo(s2) ;
@@ -68,7 +68,7 @@
if ( x == 0 ) return CMP_EQUAL ;
throw new InternalErrorException("String comparison failure") ;
}
-
+
public static int strCompareIgnoreCase(String s1, String s2) {
// x is the difference of the first differing chars
int x = s1.compareToIgnoreCase(s2) ;
@@ -78,14 +78,22 @@
throw new InternalErrorException("String comparison failure") ;
}
+ public static boolean strStartsWithIgnoreCase(String str, String prefix) {
+ return str.regionMatches(true, 0, prefix, 0, prefix.length());
+ }
+
+ public static boolean strEndsWithIgnoreCase(String str, String suffix) {
+ return str.regionMatches(true, str.length()-suffix.length(), suffix, 0, suffix.length());
+ }
+
public static byte[] asUTF8bytes(String s) {
- return s.getBytes(UTF_8) ;
+ return s.getBytes(UTF_8) ;
}
public static String fromUTF8bytes(byte[] bytes) {
- return new String(bytes, UTF_8) ;
+ return new String(bytes, UTF_8) ;
}
-
+
/**
* @param x
* @return <null> if x == null, otherwise, x.toString()
@@ -98,10 +106,10 @@
public static String[] split(String s, String splitStr) {
return stream(s.split(splitStr)).map(String::trim).toArray(String[]::new) ;
}
-
+
/**
* Does one string contain another string?
- *
+ *
* @param str1
* @param str2
* @return true if str1 contains str2
@@ -109,7 +117,7 @@
public final static boolean contains(String str1, String str2) {
return str1.contains(str2) ;
}
-
+
public final static String replace(String string, String target, String replacement) {
return string.replace(target, replacement) ;
}
@@ -117,12 +125,12 @@
public static String substitute(String str, Map<String, String> subs) {
for ( Map.Entry<String, String> e : subs.entrySet() ) {
String param = e.getKey() ;
- if ( str.contains(param) )
+ if ( str.contains(param) )
str = str.replace(param, e.getValue()) ;
}
return str ;
}
-
+
public static String strform(Map<String, String> subs, String... args) {
return substitute(strjoinNL(args), subs) ;
}
@@ -136,20 +144,20 @@
x = StrUtils.chop(x) ;
return x ;
}
-
+
public static List<Character> toCharList(String str) {
return str.codePoints().mapToObj(i -> (char) i).map(Character::valueOf).collect(toList());
}
-
+
// ==== Encoding and decoding strings based on a marker character (e.g. %)
- // and then the hexadecimal representation of the character.
+ // and then the hexadecimal representation of the character.
// Only characters 0-255 can be encoded.
// Decoding is more general.
-
+
/**
* Encode a string using hex values e.g. %20.
- * Encoding only deals with single byte codepoints.
- *
+ * Encoding only deals with single byte codepoints.
+ *
* @param str String to encode
* @param marker Marker character
* @param escapees Characters to encode (must include the marker)
@@ -189,7 +197,7 @@
/**
* Decode a string using marked hex values e.g. %20.
* Multi-byte UTF-8 codepoints are handled.
- *
+ *
* @param str String to decode.
* @param marker The marker character
* @return Decoded string (returns input object if no change)
@@ -198,7 +206,7 @@
if ( str.indexOf(marker) < 0 )
// No marker, no work.
return str;
- // By working in bytes, we deal with mult-byte codepoints.
+ // By working in bytes, we deal with mult-byte codepoints.
byte[] strBytes = StrUtils.asUTF8bytes(str);
final int N = strBytes.length;
// Max length
@@ -224,13 +232,13 @@
String s = new String(bytes, 0, i, StandardCharsets.UTF_8);
return s;
}
-
+
// Same but working on the string. This is the pair of the encoder.
// Encode/decode is normally use is for characters that illegal in a position
// (e.g. URI components, spaces in URIs).
-
- // This string version is brittle - reverses the encoding of encodeHex()
- // but not general use as a decoder of a string.
+
+ // This string version is brittle - reverses the encoding of encodeHex()
+ // but not general use as a decoder of a string.
// Multi-byte codepoints do not get recombined if operating on strings/characters.
private /*public*/ static String _forInfo_decodeHex(String str, char marker) {
int idx = str.indexOf(marker);
@@ -267,7 +275,7 @@
return ch - 'A' + 10;
if ( ch >= 'a' && ch <= 'f' )
return ch - 'a' + 10;
- throw new AtlasException(format("Decoding error: bad character for hex digit (0x%02X) '%c' ",ch, ch));
+ throw new AtlasException(format("Decoding error: bad character for hex digit (0x%02X) '%c' ",ch, ch));
}
public static String escapeString(String x) {
diff --git a/jena-base/src/test/java/org/apache/jena/atlas/lib/TestStrUtils.java b/jena-base/src/test/java/org/apache/jena/atlas/lib/TestStrUtils.java
index 1628866..41dd980 100644
--- a/jena-base/src/test/java/org/apache/jena/atlas/lib/TestStrUtils.java
+++ b/jena-base/src/test/java/org/apache/jena/atlas/lib/TestStrUtils.java
@@ -19,6 +19,8 @@
package org.apache.jena.atlas.lib;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import org.apache.jena.atlas.AtlasException;
import org.junit.Test ;
@@ -26,8 +28,8 @@
public class TestStrUtils
{
static char marker = '_' ;
- static char esc[] = { ' ' , '_' } ;
-
+ static char esc[] = { ' ' , '_' } ;
+
static void test(String x) {
test(x, null);
}
@@ -45,43 +47,72 @@
String x2 = StrUtils.decodeHex(input, marker);
assertEquals(expected, x2);
}
-
- @Test public void enc01() { test("abc") ; }
- @Test public void enc02() { test("") ; }
+ @Test public void enc01() { test("abc") ; }
- @Test public void enc03() { test("_", "_5F" ) ; }
-
- @Test public void enc04() { test(" ", "_20" ) ; }
-
- @Test public void enc05() { test("_ _", "_5F_20_5F" ) ; }
-
- @Test public void enc06() { test("_5F", "_5F5F" ) ; }
-
+ @Test public void enc02() { test("") ; }
+
+ @Test public void enc03() { test("_", "_5F" ) ; }
+
+ @Test public void enc04() { test(" ", "_20" ) ; }
+
+ @Test public void enc05() { test("_ _", "_5F_20_5F" ) ; }
+
+ @Test public void enc06() { test("_5F", "_5F5F" ) ; }
+
@Test public void enc07() { test("_2") ; }
-
- @Test public void enc08() { test("AB_CD", "AB_5FCD") ; }
-
- // JENA-1890: Multibyte characters before the "_"
+
+ @Test public void enc08() { test("AB_CD", "AB_5FCD") ; }
+
+ // JENA-1890: Multibyte characters before the "_"
// 사용_설명서 (Korean: "User's Guide")
-
+
@Test public void enc09() { test("\uC0AC\uC6A9_\uC124\uBA85\uC11C"); }
- // Same string, but using the glyphs for the codepoints, not the \ u value. Same string after Java parsing.
+ // Same string, but using the glyphs for the codepoints, not the \ u value. Same string after Java parsing.
@Test public void enc09a() { test("사용_설명서"); }
-
+
// The decode code works more generally than the encoder.
// This tests the decode of the UTF=-8 byte encoding of 사용_설명서
- // Note "_5F" which is "_" encoded.
+ // Note "_5F" which is "_" encoded.
@Test public void enc10() { testDecode("_EC_82_AC_EC_9A_A9_5F_EC_84_A4_EB_AA_85_EC_84_9C", "사용_설명서"); }
-
+
@Test public void enc11() { testDecode("_41", "A"); }
-
+
@Test(expected=AtlasException.class) public void enc20() { testDecode("_4", null); }
@Test(expected=AtlasException.class) public void enc21() { testDecode("_", null); }
-
+
@Test(expected=AtlasException.class) public void enc22() { testDecode("_X1", null); }
-
+
@Test(expected=AtlasException.class) public void enc23() { testDecode("_1X", null); }
+ @Test public void prefix_ignorecase_1() {
+ boolean b = StrUtils.strStartsWithIgnoreCase("foobar", "FOO");
+ assertTrue(b);
+ }
+
+ @Test public void prefix_ignorecase_2() {
+ boolean b = StrUtils.strStartsWithIgnoreCase("foobar", "bar");
+ assertFalse(b);
+ }
+ @Test public void prefix_ignorecase_3() {
+ boolean b = StrUtils.strStartsWithIgnoreCase("foo", "foobar");
+ assertFalse(b);
+ }
+
+ @Test public void suffix_ignorecase_1() {
+ boolean b = StrUtils.strEndsWithIgnoreCase("foobar", "BAR");
+ assertTrue(b);
+ }
+
+ @Test public void suffix_ignorecase_2() {
+ boolean b = StrUtils.strEndsWithIgnoreCase("foobar", "oo");
+ assertFalse(b);
+ }
+ @Test public void suffix_ignorecase_3() {
+ boolean b = StrUtils.strEndsWithIgnoreCase("bar", "foobar");
+ assertFalse(b);
+ }
+
+
}
diff --git a/jena-core/src/main/java/org/apache/jena/irix/IRIProviderJenaIRI.java b/jena-core/src/main/java/org/apache/jena/irix/IRIProviderJenaIRI.java
index bf2fcf9..4b96884 100644
--- a/jena-core/src/main/java/org/apache/jena/irix/IRIProviderJenaIRI.java
+++ b/jena-core/src/main/java/org/apache/jena/irix/IRIProviderJenaIRI.java
@@ -76,16 +76,14 @@
@Override
public IRIx resolve(String other) {
IRI iri2 = jenaIRI.resolve(other);
- IRIProviderJenaIRI.exceptions(iri2);
- return new IRIxJena(iri2.toString(), iri2);
+ return newIRIxJena(iri2);
}
@Override
public IRIx resolve(IRIx other) {
IRIxJena iriOther = (IRIxJena)other;
IRI iri2 = jenaIRI.resolve(iriOther.jenaIRI);
- IRIProviderJenaIRI.exceptions(iri2);
- return new IRIxJena(iri2.toString(), iri2);
+ return newIRIxJena(iri2);
}
@Override
@@ -104,8 +102,7 @@
IRI iri2 = jenaIRI.relativize(iriOther.jenaIRI, relFlags);
if ( iri2.equals(iriOther.jenaIRI))
return null;
- IRIProviderJenaIRI.exceptions(iri2);
- return new IRIxJena(iri2.toString(), iri2);
+ return newIRIxJena(iri2);
}
@Override
@@ -131,25 +128,27 @@
}
}
+ private static IRIxJena newIRIxJena(IRI iri2) {
+ String iriStr2 = iri2.toString();
+ return newIRIxJena(iri2, iriStr2);
+ }
+
+ private static IRIxJena newIRIxJena(IRI iri2, String iriStr2) {
+ IRIProviderJenaIRI.exceptions(iri2, iriStr2);
+ return new IRIxJena(iriStr2, iri2);
+ }
+
@Override
public IRIx create(String iriStr) throws IRIException {
// "create" - does not throw exceptions
IRI iriObj = iriFactory().create(iriStr);
- // errors and warnings.
- if ( STRICT_FILE && isFILE(iriObj) ) {
- if ( iriStr.startsWith("file://" ) && ! iriStr.startsWith("file:///") )
- throw new IRIException("file: URLs should start file:///");
- }
- if ( isUUID(iriObj) )
- checkUUID(iriObj, iriStr);
- exceptions(iriObj);
- return new IRIProviderJenaIRI.IRIxJena(iriStr, iriObj);
+ return newIRIxJena(iriObj, iriStr);
}
@Override
public void check(String iriStr) throws IRIException {
IRI iri = iriFactory().create(iriStr);
- exceptions(iri);
+ exceptions(iri, iriStr);
}
@Override
@@ -205,7 +204,21 @@
// Should be "false" in a release - this is an assist for development checking.
private static final boolean includeWarnings = false;
- private static IRI exceptions(IRI iri) {
+ private static IRI exceptions(IRI iri, String iriStr) {
+ if ( iriStr == null )
+ iriStr = iri.toString();
+
+ // Additional checks
+
+ // errors and warnings.
+ if ( STRICT_FILE && isFILE(iri) ) {
+ if ( iriStr.startsWith("file://" ) && ! iriStr.startsWith("file:///") )
+ throw new IRIException("file: URLs should start file:///: <"+iriStr+">");
+ }
+
+ if ( isUUID(iri, iriStr) ) {
+ checkUUID(iri, iriStr);
+ }
if (!showExceptions)
return iri;
if (!iri.hasViolation(includeWarnings))
@@ -218,6 +231,7 @@
int code = v.getViolationCode() ;
// Filter codes.
// Global settings below; this section is for conditional filtering.
+ // See also Checker.iriViolations for WARN filtering.
switch(code) {
case Violation.PROHIBITED_COMPONENT_PRESENT:
// Allow "u:p@" when non-strict.
@@ -237,7 +251,7 @@
if ( isFILE(iri) )
continue;
}
- // First error.
+ // Signal first error.
String msg = v.getShortMessage();
throw new IRIException(msg);
}
@@ -246,23 +260,22 @@
// HTTP and HTTPS
private static boolean isHTTP(IRI iri) {
- return "http".equalsIgnoreCase(iri.getScheme()) || "https".equalsIgnoreCase(iri.getScheme());
+ return "http".equalsIgnoreCase(iri.getScheme())
+ || "https".equalsIgnoreCase(iri.getScheme());
}
private static boolean isURN(IRI iri) { return "urn".equalsIgnoreCase(iri.getScheme()); }
private static boolean isFILE(IRI iri) { return "file".equalsIgnoreCase(iri.getScheme()); }
- // Checks trailing part of URI.
- // Works on "urn:" and "urn:uuid:".
- private static Pattern UUID_PATTERN = Pattern.compile(":[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$");
+ private static String UUID_REGEXP = "^(?:urn:uuid|uuid):[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$";
+ private static Pattern UUID_PATTERN = Pattern.compile(UUID_REGEXP, Pattern.CASE_INSENSITIVE);
- private boolean isUUID(IRI iri) {
- if ( "uuid".equalsIgnoreCase(iri.getScheme()) )
- return true;
- return iri.getRawPath().startsWith("uuid:");
+ private static boolean isUUID(IRI iri, String iriStr) {
+ return iriStr.regionMatches(true, 0, "urn:uuid:", 0, "urn:uuid:".length())
+ || iriStr.regionMatches(true, 0, "uuid:", 0, "uuid:".length());
}
- private void checkUUID(IRI iriObj, String original) {
+ private static void checkUUID(IRI iriObj, String original) {
if ( iriObj.getRawFragment() != null )
throw new IRIException("Fragment used with UUID");
if ( iriObj.getRawQuery() != null )
diff --git a/jena-core/src/main/java/org/apache/jena/irix/IRIs.java b/jena-core/src/main/java/org/apache/jena/irix/IRIs.java
index 1efba86..c537056 100644
--- a/jena-core/src/main/java/org/apache/jena/irix/IRIs.java
+++ b/jena-core/src/main/java/org/apache/jena/irix/IRIs.java
@@ -39,7 +39,7 @@
Objects.requireNonNull(iriStr);
IRIx iri = IRIx.create(iriStr);
if ( ! iri.isReference() )
- throw new IRIException("Not an RDF IRI: "+iriStr);
+ throw new IRIException("Not an RDF IRI: <"+iriStr+">");
return iri;
}
diff --git a/jena-core/src/main/java/org/apache/jena/irix/IRIxResolver.java b/jena-core/src/main/java/org/apache/jena/irix/IRIxResolver.java
index 1132e0c..e557df4 100644
--- a/jena-core/src/main/java/org/apache/jena/irix/IRIxResolver.java
+++ b/jena-core/src/main/java/org/apache/jena/irix/IRIxResolver.java
@@ -19,6 +19,7 @@
package org.apache.jena.irix;
import java.util.Objects;
+import java.util.Optional;
import org.apache.jena.atlas.lib.Cache;
import org.apache.jena.atlas.lib.CacheFactory;
@@ -85,10 +86,8 @@
IRIx x = (base != null && resolve)
? base.resolve(str)
: IRIx.create(str);
- if ( ! allowRelative ) {
- if ( ! x.isReference() )
- throw new IRIException("Not an RDF IRI: "+str);
- }
+ if ( ! allowRelative && x.isRelative() )
+ throw new RelativeIRIException("Relative IRI: <"+str+">");
return x;
}
@@ -104,15 +103,13 @@
public static Builder create() { return new Builder(); }
-
/**
* Create a {@link IRIxResolver} with the base URI which is resolved against the
* current system default base.
*/
public static Builder create(IRIxResolver original) {
Builder builder = new Builder();
- builder.base = original.base;
- builder.baseSet = true;
+ builder.base = Optional.ofNullable(original.base);
builder.resolve = original.resolve;
builder.allowRelative = original.allowRelative;
return builder;
@@ -136,29 +133,26 @@
}
public static class Builder {
-
- private boolean baseSet = false;
- private IRIx base = null;
- private boolean resolve = true;
+ // null is "unset".
+ private Optional<IRIx> base = null;
+ private boolean resolve = true;
private boolean allowRelative = true;
private Builder() {}
public Builder base(IRIx baseURI) {
- this.base = baseURI;
- this.baseSet = true;
+ this.base = Optional.ofNullable(baseURI);
return this;
}
public Builder base(String baseStr) {
- base = (baseStr == null) ? null : IRIs.resolveIRI(baseStr);
- this.baseSet = true;
+ IRIx baseIRI = (baseStr == null) ? null : IRIs.resolveIRI(baseStr);
+ this.base = Optional.ofNullable(baseIRI);
return this;
}
public Builder noBase() {
- base = null;
- this.baseSet = true;
+ this.base = Optional.empty();
return this;
}
@@ -173,9 +167,10 @@
}
public IRIxResolver build() {
- if ( ! baseSet )
+ if ( base == null )
throw new IRIException("Base has not been set");
- return new IRIxResolver(base, resolve, allowRelative);
+ IRIx baseIRI = base.orElse(null);
+ return new IRIxResolver(baseIRI, resolve, allowRelative);
}
}
}
diff --git a/jena-core/src/main/java/org/apache/jena/irix/RelativeIRIException.java b/jena-core/src/main/java/org/apache/jena/irix/RelativeIRIException.java
new file mode 100644
index 0000000..ea08fd4
--- /dev/null
+++ b/jena-core/src/main/java/org/apache/jena/irix/RelativeIRIException.java
@@ -0,0 +1,28 @@
+/*
+ * 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.jena.irix;
+
+/**
+ * Exception thrown due to relative IRIs when no permitted.
+ * See {@link IRIxResolver#resolve}.
+ */
+public class RelativeIRIException extends IRIException {
+ public RelativeIRIException(String msg) { super(msg); }
+ @Override public Throwable fillInStackTrace() { return this ; }
+}
diff --git a/jena-core/src/main/java/org/apache/jena/irix/SetupJenaIRI.java b/jena-core/src/main/java/org/apache/jena/irix/SetupJenaIRI.java
index 3497e51..301bd4e 100644
--- a/jena-core/src/main/java/org/apache/jena/irix/SetupJenaIRI.java
+++ b/jena-core/src/main/java/org/apache/jena/irix/SetupJenaIRI.java
@@ -65,6 +65,9 @@
/** IRI Factory with "checker" settings. */
/*package*/ static final IRIFactory setupCheckerIRIFactory() {
+ // See IRIProviderJenaIRI.exceptions for context specific tuning.
+ // See Checker.iriViolations for filtering and output from parsers.
+
IRIFactory iriCheckerFactory = new IRIFactory();
//iriCheckerInst.shouldViolation(false,true);
@@ -81,6 +84,9 @@
// -- Scheme specific rules.
setErrorWarning(iriCheckerFactory, ViolationCodes.SCHEME_PATTERN_MATCH_FAILED, false, true);
+ // jena-iri produces an error for PROHIBITED_COMPONENT_PRESENT regardless.
+ // See Checker.iriViolations for handling this
+ //setErrorWarning(iriCheckerFactory, ViolationCodes.PROHIBITED_COMPONENT_PRESENT, false, true);
// == Scheme
setErrorWarning(iriCheckerFactory, ViolationCodes.UNREGISTERED_IANA_SCHEME, false, false);
diff --git a/jena-core/src/test/java/org/apache/jena/irix/TestIRIx.java b/jena-core/src/test/java/org/apache/jena/irix/TestIRIx.java
index fae9c44..49f7b5c 100644
--- a/jena-core/src/test/java/org/apache/jena/irix/TestIRIx.java
+++ b/jena-core/src/test/java/org/apache/jena/irix/TestIRIx.java
@@ -21,6 +21,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import java.util.Locale;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -84,6 +86,23 @@
@Test public void urn_05() { notStrict("urn", ()->parse("urn:ex:")); }
+ private static String testUUID = "aa045fc2-a781-11eb-9041-afa3877612ee";
+
+ @Test public void uuid_01() { parse("uuid:"+testUUID); }
+
+ @Test public void uuid_02() { parse("uuid:"+(testUUID.toUpperCase(Locale.ROOT))); }
+
+ @Test public void uuid_03() { parse("UUID:"+testUUID); }
+
+ @Test public void uuid_04() { parse("urn:uuid:"+testUUID); }
+
+ @Test public void uuid_05() { parse("urn:uuid:"+(testUUID.toUpperCase(Locale.ROOT))); }
+
+ @Test public void uuid_06() { parse("URN:UUID:"+testUUID); }
+
+ @Test(expected=IRIException.class)
+ public void uuid_07() { parse("urn:uuid:06e775ac-ZZZZ-11b2-801c-8086f2cc00c9"); }
+
// -- Compliance with file scheme: https://tools.ietf.org/html/rfc8089
@Test public void file_01() { parse("file:///path/name"); }
diff --git a/jena-core/src/test/java/org/apache/jena/irix/TestResolve.java b/jena-core/src/test/java/org/apache/jena/irix/TestResolve.java
index 63625d6..cdf670a 100644
--- a/jena-core/src/test/java/org/apache/jena/irix/TestResolve.java
+++ b/jena-core/src/test/java/org/apache/jena/irix/TestResolve.java
@@ -196,6 +196,12 @@
testResolve("http://example/dir1/dir2/", "//EX/OtherPath", "http://EX/OtherPath");
}
+ @Test
+ public void resolve_34() {
+ String uuid = "urn:uuid:e79b5752-a82e-11eb-8c4e-cba73c34870a";
+ testResolve("http://example/base#", uuid, uuid);
+ }
+
private void testResolve(String base, String rel, String expected) {
IRIx baseIRI = IRIx.create(base);
IRIx relIRI = IRIx.create(rel);
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/sys/DatabaseOps.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/sys/DatabaseOps.java
index 4745d10..7a5beb9 100644
--- a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/sys/DatabaseOps.java
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/sys/DatabaseOps.java
@@ -182,7 +182,7 @@
// Is this the same database location?
if ( ! loc1.equals(loc1a) )
- throw new TDBException("Inconsistent (not latested?) : "+loc1a+" : "+loc1);
+ throw new TDBException("Inconsistent (not latest?) : "+loc1a+" : "+loc1);
// -- Checks
// Version
diff --git a/jena-db/jena-tdb2/src/test/java/org/apache/jena/tdb2/sys/TestDatabaseOps.java b/jena-db/jena-tdb2/src/test/java/org/apache/jena/tdb2/sys/TestDatabaseOps.java
index 7584d0f..cfbf730 100644
--- a/jena-db/jena-tdb2/src/test/java/org/apache/jena/tdb2/sys/TestDatabaseOps.java
+++ b/jena-db/jena-tdb2/src/test/java/org/apache/jena/tdb2/sys/TestDatabaseOps.java
@@ -162,6 +162,7 @@
});
DatasetGraphSwitchable dsgs = (DatasetGraphSwitchable)dsg;
+ assertNotNull("DatasetGraphSwitchable created", dsgs.getLocation());
DatasetGraph dsg1 = dsgs.get();
Location loc1 = ((DatasetGraphTDB)dsg1).getLocation();
diff --git a/jena-fuseki2/jena-fuseki-webapp/src/test/resources/log4j2.properties b/jena-fuseki2/jena-fuseki-webapp/src/test/resources/log4j2.properties
index 41cfb2d..7538a8c 100644
--- a/jena-fuseki2/jena-fuseki-webapp/src/test/resources/log4j2.properties
+++ b/jena-fuseki2/jena-fuseki-webapp/src/test/resources/log4j2.properties
@@ -41,6 +41,9 @@
logger.fuseki-admin.name = org.apache.jena.fuseki.Admin
logger.fuseki-admin.level = WARN
+logger.fuseki-config.name = org.apache.jena.fuseki.Config
+logger.fuseki-config.level = WARN
+
logger.jetty.name = org.eclipse.jetty
logger.jetty.level = WARN