Skip to content

Commit dfe70ff

Browse files
author
James Leigh
committed
Fix #712: Add ValidatingValueFactory wrapper
Signed-off-by: James Leigh <james.leigh@ontotext.com>
1 parent 1f4c411 commit dfe70ff

3 files changed

Lines changed: 258 additions & 1 deletion

File tree

core/model/src/main/java/org/eclipse/rdf4j/model/datatypes/XMLDatatypeUtil.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import java.math.BigDecimal;
1111
import java.math.BigInteger;
1212
import java.net.URISyntaxException;
13+
import java.util.IllformedLocaleException;
14+
import java.util.Locale;
1315
import java.util.StringTokenizer;
1416

1517
import javax.xml.datatype.DatatypeConfigurationException;
@@ -274,6 +276,9 @@ else if (datatype.equals(XMLSchema.QNAME)) {
274276
else if (datatype.equals(XMLSchema.ANYURI)) {
275277
result = isValidAnyURI(value);
276278
}
279+
else if (datatype.equals(XMLSchema.LANGUAGE)) {
280+
result = isValidLanguage(value);
281+
}
277282

278283
return result;
279284
}
@@ -676,6 +681,15 @@ public static boolean isValidAnyURI(String value) {
676681
}
677682
}
678683

684+
public static boolean isValidLanguage(String value) {
685+
try {
686+
new Locale.Builder().setLanguageTag(value);
687+
return true;
688+
} catch (IllformedLocaleException e) {
689+
return false;
690+
}
691+
}
692+
679693
private static boolean isPrefixStartChar(int c) {
680694
return ASCIIUtil.isLetter(c) || c >= 0x00C0 && c <= 0x00D6 || c >= 0x00D8 && c <= 0x00F6
681695
|| c >= 0x00F8 && c <= 0x02FF || c >= 0x0370 && c <= 0x037D || c >= 0x037F && c <= 0x1FFF
Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2017 Eclipse RDF4J contributors, Aduna, and others.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Distribution License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/org/documents/edl-v10.php.
7+
*******************************************************************************/
8+
package org.eclipse.rdf4j.model.impl;
9+
10+
import java.math.BigDecimal;
11+
import java.math.BigInteger;
12+
import java.net.URISyntaxException;
13+
import java.util.Date;
14+
15+
import javax.xml.datatype.XMLGregorianCalendar;
16+
17+
import org.eclipse.rdf4j.common.net.ParsedIRI;
18+
import org.eclipse.rdf4j.model.BNode;
19+
import org.eclipse.rdf4j.model.IRI;
20+
import org.eclipse.rdf4j.model.Literal;
21+
import org.eclipse.rdf4j.model.Resource;
22+
import org.eclipse.rdf4j.model.Statement;
23+
import org.eclipse.rdf4j.model.URI;
24+
import org.eclipse.rdf4j.model.Value;
25+
import org.eclipse.rdf4j.model.ValueFactory;
26+
import org.eclipse.rdf4j.model.datatypes.XMLDatatypeUtil;
27+
import org.eclipse.rdf4j.model.util.URIUtil;
28+
29+
/**
30+
* Validating wrapper to {@link ValueFactory}. Use this class in situations where a caller may be prone to
31+
* errors.
32+
*
33+
* @author James Leigh
34+
*/
35+
public class ValidatingValueFactory implements ValueFactory {
36+
37+
private static final int[][] PN_CHARS_U = {
38+
new int[] { '0', '9' },
39+
new int[] { '_', '_' },
40+
new int[] { 'A', 'Z' },
41+
new int[] { 'a', 'z' },
42+
new int[] { 0x00C0, 0x00D6 },
43+
new int[] { 0x00D8, 0x00F6 },
44+
new int[] { 0x00F8, 0x02FF },
45+
new int[] { 0x0370, 0x037D },
46+
new int[] { 0x037F, 0x1FFF },
47+
new int[] { 0x200C, 0x200D },
48+
new int[] { 0x2070, 0x218F },
49+
new int[] { 0x2C00, 0x2FEF },
50+
new int[] { 0x3001, 0xD7FF },
51+
new int[] { 0xF900, 0xFDCF },
52+
new int[] { 0xFDF0, 0xFFFD },
53+
new int[] { 0x10000, 0xEFFFF } };
54+
55+
private static final int[][] PN_CHARS = {
56+
new int[] { '-', '-' },
57+
new int[] { 0x00B7, 0x00B7 },
58+
new int[] { 0x0300, 0x036F },
59+
new int[] { 0x203F, 0x2040 },
60+
new int[] { '0', '9' },
61+
new int[] { '_', '_' },
62+
new int[] { 'A', 'Z' },
63+
new int[] { 'a', 'z' },
64+
new int[] { 0x00C0, 0x00D6 },
65+
new int[] { 0x00D8, 0x00F6 },
66+
new int[] { 0x00F8, 0x02FF },
67+
new int[] { 0x0370, 0x037D },
68+
new int[] { 0x037F, 0x1FFF },
69+
new int[] { 0x200C, 0x200D },
70+
new int[] { 0x2070, 0x218F },
71+
new int[] { 0x2C00, 0x2FEF },
72+
new int[] { 0x3001, 0xD7FF },
73+
new int[] { 0xF900, 0xFDCF },
74+
new int[] { 0xFDF0, 0xFFFD },
75+
new int[] { 0x10000, 0xEFFFF } };
76+
77+
private final ValueFactory delegate;
78+
79+
public ValidatingValueFactory() {
80+
this(SimpleValueFactory.getInstance());
81+
}
82+
83+
public ValidatingValueFactory(ValueFactory delegate) {
84+
this.delegate = delegate;
85+
}
86+
87+
@Override
88+
public IRI createIRI(String iri) {
89+
try {
90+
if (!new ParsedIRI(iri).isAbsolute()) {
91+
throw new IllegalArgumentException("IRI must be absolute");
92+
}
93+
return delegate.createIRI(iri);
94+
}
95+
catch (URISyntaxException e) {
96+
throw new IllegalArgumentException(e);
97+
}
98+
}
99+
100+
@Override
101+
public IRI createIRI(String namespace, String localName) {
102+
if (!URIUtil.isCorrectURISplit(namespace, localName)) {
103+
return createIRI(namespace + localName);
104+
}
105+
try {
106+
if (!new ParsedIRI(namespace + localName).isAbsolute()) {
107+
throw new IllegalArgumentException("Namespace must be absolute");
108+
}
109+
return delegate.createIRI(namespace, localName);
110+
}
111+
catch (URISyntaxException e) {
112+
throw new IllegalArgumentException(e);
113+
}
114+
}
115+
116+
@Override
117+
public BNode createBNode(String nodeID) {
118+
if (nodeID.length() < 1) {
119+
throw new IllegalArgumentException("Blank node ID cannot be empty");
120+
}
121+
if (!isMember(PN_CHARS_U, nodeID.codePointAt(0))) {
122+
throw new IllegalArgumentException("Blank node ID must start with alphanumber or underscore");
123+
}
124+
for (int i = 0, n = nodeID.codePointCount(0, nodeID.length()); i < n; i++) {
125+
if (!isMember(PN_CHARS, nodeID.codePointAt(nodeID.offsetByCodePoints(0, i)))) {
126+
throw new IllegalArgumentException("Illegal blank node ID character");
127+
}
128+
}
129+
return delegate.createBNode(nodeID);
130+
}
131+
132+
@Override
133+
public Literal createLiteral(String label, IRI datatype) {
134+
if (!XMLDatatypeUtil.isValidValue(label, datatype)) {
135+
throw new IllegalArgumentException("Not a validate literal value");
136+
}
137+
return delegate.createLiteral(label, datatype);
138+
}
139+
140+
public Literal createLiteral(String label, String language) {
141+
if (!XMLDatatypeUtil.isValidLanguage(language)) {
142+
throw new IllegalArgumentException("Not a validate language tag");
143+
}
144+
return delegate.createLiteral(label, language);
145+
}
146+
147+
@Override
148+
public URI createURI(String uri) {
149+
return createIRI(uri);
150+
}
151+
152+
@Override
153+
public URI createURI(String namespace, String localName) {
154+
return createIRI(namespace, localName);
155+
}
156+
157+
@Override
158+
public Literal createLiteral(String label, URI datatype) {
159+
if (datatype instanceof IRI) {
160+
return createLiteral(label, (IRI)datatype);
161+
}
162+
else {
163+
return createLiteral(label, createIRI(datatype.stringValue()));
164+
}
165+
}
166+
167+
public BNode createBNode() {
168+
return delegate.createBNode();
169+
}
170+
171+
public Literal createLiteral(String label) {
172+
return delegate.createLiteral(label);
173+
}
174+
175+
public Literal createLiteral(boolean value) {
176+
return delegate.createLiteral(value);
177+
}
178+
179+
public Literal createLiteral(byte value) {
180+
return delegate.createLiteral(value);
181+
}
182+
183+
public Literal createLiteral(short value) {
184+
return delegate.createLiteral(value);
185+
}
186+
187+
public Literal createLiteral(int value) {
188+
return delegate.createLiteral(value);
189+
}
190+
191+
public Literal createLiteral(long value) {
192+
return delegate.createLiteral(value);
193+
}
194+
195+
public Literal createLiteral(float value) {
196+
return delegate.createLiteral(value);
197+
}
198+
199+
public Literal createLiteral(double value) {
200+
return delegate.createLiteral(value);
201+
}
202+
203+
public Literal createLiteral(BigDecimal bigDecimal) {
204+
return delegate.createLiteral(bigDecimal);
205+
}
206+
207+
public Literal createLiteral(BigInteger bigInteger) {
208+
return delegate.createLiteral(bigInteger);
209+
}
210+
211+
public Literal createLiteral(XMLGregorianCalendar calendar) {
212+
return delegate.createLiteral(calendar);
213+
}
214+
215+
public Literal createLiteral(Date date) {
216+
return delegate.createLiteral(date);
217+
}
218+
219+
public Statement createStatement(Resource subject, IRI predicate, Value object) {
220+
return delegate.createStatement(subject, predicate, object);
221+
}
222+
223+
public Statement createStatement(Resource subject, IRI predicate, Value object, Resource context) {
224+
return delegate.createStatement(subject, predicate, object, context);
225+
}
226+
227+
public Statement createStatement(Resource subject, URI predicate, Value object) {
228+
return delegate.createStatement(subject, predicate, object);
229+
}
230+
231+
public Statement createStatement(Resource subject, URI predicate, Value object, Resource context) {
232+
return delegate.createStatement(subject, predicate, object, context);
233+
}
234+
235+
private boolean isMember(int[][] set, int cp) {
236+
for (int i = 0; i < set.length; i++) {
237+
if (set[i][0] <= cp && cp <= set[i][1]) {
238+
return true;
239+
}
240+
}
241+
return false;
242+
}
243+
}

core/model/src/main/java/org/eclipse/rdf4j/model/util/URIUtil.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public static boolean isCorrectURISplit(String namespace, String localName) {
103103

104104
if (lastNsChar == '#') {
105105
// correct split if namespace has no other '#'
106-
return namespace.lastIndexOf('#', nsLength - 2) == -1;
106+
return namespace.lastIndexOf('#', nsLength - 2) == -1 && localName.indexOf('#') == -1;
107107
}
108108
else if (lastNsChar == '/') {
109109
// correct split if local name has no '/' and URI contains no '#'

0 commit comments

Comments
 (0)