Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blanknode identifier only #64

Closed
wants to merge 13 commits into from
101 changes: 45 additions & 56 deletions api/src/main/java/com/github/commonsrdf/api/BlankNode.java
Expand Up @@ -13,6 +13,8 @@
*/
package com.github.commonsrdf.api;

import java.util.UUID;

/**
* A <a href= "http://www.w3.org/TR/rdf11-concepts/#dfn-blank-node" >RDF-1.1
* Blank Node</a>, as defined by <a href=
Expand Down Expand Up @@ -55,79 +57,66 @@ public interface BlankNode extends BlankNodeOrIRI {
/**
* Return a <a href=
* "http://www.w3.org/TR/rdf11-concepts/#dfn-blank-node-identifier"
* >label</a> for the blank node. This is not a serialization/syntax label.
* It should be uniquely identifying within the local scope it is created in
* but has no uniqueness guarantees other than that.
* >identifier</a> for the blank node as an {@link UUID}.
* <p>
* This is <strong>not</strong> a serialization/syntax label,
* e.g. not <del><code>_:b2</code></del>.
* <p>
* In particular, the existence of two objects of type {@link BlankNode}
* with the same value returned from {@link #internalIdentifier()} are not
* equivalent unless they are known to have been created in the same local
* scope (see {@link #equals(Object)})
* The returned string MUST uniquely identify the
* only this blank node, but but does not
* come with any guarantees for persistence or resolution.
* <p>
* An example of a local scope may be an instance of a Java Virtual Machine
* (JVM). In the context of a JVM instance, an implementor may support
* insertion and removal of {@link Triple} objects containing Blank Nodes
* without modifying the blank node labels.
* Two objects of the type <code>BlankNode</code> with the same
* value returned from {@link #identifier()} are equivalent,
* and thus are in the same local scope.
* (see {@link #equals(Object)}).
* <p>
* Another example of a local scope may be a <a
* href="http://www.w3.org/TR/rdf11-concepts/#section-rdf-graph">Graph</a>
* or <a
* href="http://www.w3.org/TR/rdf11-concepts/#section-dataset">Dataset</a>
* created from a single document. In this context, an implementor should
* reasonably guarantee that the label returned by getLabel only maps to
* equivalent blank nodes in the same Graph or Dataset, but they may not
* guarantee that it is unique for the JVM instance. In this case, the
* implementor may support a mechanism to provide a mapping for blank nodes
* between Graph or Dataset instances to guarantee their uniqueness.
* On the other hand, two <code>BlankNode</code> objects
* with different <code>identifier()</code> values are not
* necessarily different.
* <p>
* If implementors support <a
* href="http://www.w3.org/TR/rdf11-concepts/#section-skolemization"
* >Skolemisation</a>, they may map instances of {@link BlankNode} objects
* to {@link IRI} objects to reduce scoping issues.
* The identifier MUST be globally unique. It is RECOMMENDED
* for the identifier to be a UUID string.
* If the identifier is a IRI, it is SHOULD be a
* <a href="http://www.w3.org/TR/rdf11-concepts/#section-skolemization">
* skolem IRI</a>.
* <p>
* It is not a requirement for the internal identifier to be a part of the
* {@link #ntriplesString()}, except that two BlankNode instances with the
* same internalIdentifier() and same local scope should have the same
* {@link #ntriplesString()}.
* It is NOT RECOMMENDED for this <code>identifier</code>
* to form part of the {@link #ntriplesString()}.
*
* @see UUID#toString()
* @see #equals(Object)
*
* @return An internal, system identifier for the {@link BlankNode}.
* @return An unique identifier for the {@link BlankNode}.
*/
String internalIdentifier();
String identifier();

/**
* Check it this BlankNode is equal to another BlankNode. <blockquote> <a
* href
* ="http://www.w3.org/TR/rdf11-concepts/#dfn-blank-node-identifier">Blank
* node identifiers</a> are local identifiers that are used in some concrete
* RDF syntaxes or RDF store implementations. They are always locally scoped
* to the file or RDF store, and are <em>not</em> persistent or portable
* identifiers for blank nodes. Blank node identifiers are <em>not</em> part
* of the RDF abstract syntax, but are entirely dependent on the concrete
* syntax or implementation. The syntactic restrictions on blank node
* identifiers, if any, therefore also depend on the concrete RDF syntax or
* implementation.
* <p>Implementations that handle blank node identifiers in
* concrete syntaxes need to be careful not to create the same blank node
* from multiple occurrences of the same blank node identifier except in
* situations where this is supported by the syntax.
* </blockquote>
* Check it this BlankNode is equal to another BlankNode.
* <p>
* Implementations MUST check the local scope, as two BlankNode in different
* Graphs MUST differ. On the other hand, two BlankNodes found in triples of
* the same Graph instance MUST equal if and only if they have the same
* {@link #internalIdentifier()}.
* </p>
* Two BlankNodes MUST be equal if they have the same {@link #identifier()},
* and MAY be equal if their {@link #identifier()} differ.
* <p>
* Implementations MUST also override {@link #hashCode()} so that two equal
* Literals produce the same hash code.
* </p>
* <code>BlankNode</code> instances produce the same hash code.
* <p>
* Note:
* <blockquote
* cite="http://www.w3.org/TR/rdf11-concepts/#dfn-blank-node">
* Implementations that handle <a
* href="http://www.w3.org/TR/rdf11-concepts/#dfn-blank-node">blank node
* identifiers</a> in concrete syntaxes need to be careful not to create the
* same blank node from multiple occurrences of the same blank node
* identifier except in situations where this is supported by the syntax.
* </blockquote>
*
* @see #identifier()
* @see Object#equals(Object)
* @see #hashCode()
*
* @param other
* Another object
* @return true if other is a BlankNode, is in the same local scope and is
* equal to this BlankNode
* @return true if other is a BlankNode and is equal to this BlankNode
*/
@Override
public boolean equals(Object other);
Expand Down
40 changes: 25 additions & 15 deletions api/src/main/java/com/github/commonsrdf/api/RDFTermFactory.java
Expand Up @@ -14,6 +14,7 @@
package com.github.commonsrdf.api;

import java.util.Locale;
import java.util.UUID;

/**
* Factory for creating RDFTerm and Graph instances.
Expand Down Expand Up @@ -41,8 +42,8 @@ public interface RDFTermFactory {
* <p>
* Two BlankNodes created with this method MUST NOT be equal.
* <p>
* If supported, the {@link BlankNode#internalIdentifier()} of the returned
* blank node MUST be an auto-generated value.
* If supported, the {@link BlankNode#identifier()} of the returned
* blank node MUST be a freshly generated UUID.
*
* @return A new BlankNode
* @throws UnsupportedOperationException
Expand All @@ -54,28 +55,37 @@ default BlankNode createBlankNode() throws UnsupportedOperationException {
}

/**
* Create a blank node for the given internal identifier.
* Create a blank node for the given identifier.
* <p>
* Two BlankNodes created with the same identifier using this method MUST be
* equal if they are in the same local scope (e.g. in the same Graph). See
* the equals contract for {@link BlankNode} for more information.
* The identifier MUST be globally unique. It is RECOMMENDED
* for the identifier to be a UUID string, e.g.
* <code>9098f7bd-58fc-32d2-91a2-db6a19aaa46f</code>.
* <p>
* If the identifier is a IRI, it SHOULD be a
* <a href="http://www.w3.org/TR/rdf11-concepts/#section-skolemization">
* skolem IRI</a>.
* <p>
* The identifier is <strong>not</strong> a serialization/syntax label,
* e.g. not <del><code>_:b2</code></del>.
* <p>
* The {@link BlankNode#identifier()} of the returned
* blank node SHOULD be equal to the provided identifier.
* <p>
* Two BlankNodes created with the same identifier using this method
* MUST be equal.
* <p>
* If supported, the {@link BlankNode#internalIdentifier()} of the returned
* blank node MAY be equal to the provided identifier.
*
* @see BlankNode#identifier()
* @see BlankNode#equals(Object)
*
* @param identifier
* A non-empty String that is unique to this blank node in this
* scope, and which may be used as the internal identifier for
* the blank node.
* A string that uniquely identify the blank node
* @return A BlankNode for the given identifier
* @throws IllegalArgumentException
* if the identifier is not acceptable, e.g. was empty or
* contained unsupported characters.
* @throws UnsupportedOperationException
* If the operation is not supported.
*/
default BlankNode createBlankNode(String identifier)
throws IllegalArgumentException, UnsupportedOperationException {
throws UnsupportedOperationException {
throw new UnsupportedOperationException(
"createBlankNode(String) not supported");
}
Expand Down
Expand Up @@ -13,7 +13,8 @@
*/
package com.github.commonsrdf.api;

import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;

import org.junit.Test;

Expand Down Expand Up @@ -44,7 +45,7 @@ public abstract class AbstractBlankNodeTest {

/**
* Test method for
* {@link com.github.commonsrdf.api.BlankNode#internalIdentifier()}.
* {@link com.github.commonsrdf.api.BlankNode#identifier()}.
*/
@Test
public final void testInternalIdentifier() {
Expand All @@ -55,41 +56,45 @@ public String ntriplesString() {
}

@Override
public String internalIdentifier() {
public String identifier() {
return null;
}
};
BlankNode testAutomatic1 = getBlankNode();
BlankNode testAutomatic2 = getBlankNode();
BlankNode testManual3a = getBlankNode("3");
BlankNode testManual3b = getBlankNode("3");
BlankNode testManual4 = getBlankNode("4");

String uuid3 = ("b6415793-b706-4cbe-b406-14bad9c8e66f");
String uuid4 = ("36638869-2d18-4499-8be4-5b7434f9da45");

BlankNode testManual3a = getBlankNode(uuid3);
BlankNode testManual3b = getBlankNode(uuid3);
BlankNode testManual4 = getBlankNode(uuid4);

// Test against our fake stub
assertNotEquals(testNull.internalIdentifier(),
testAutomatic1.internalIdentifier());
assertNotEquals(testAutomatic1.internalIdentifier(),
testNull.internalIdentifier());
assertNotEquals(testNull.internalIdentifier(),
testManual3a.internalIdentifier());
assertNotEquals(testManual3a.internalIdentifier(),
testNull.internalIdentifier());
assertNotEquals(testNull.identifier(),
testAutomatic1.identifier());
assertNotEquals(testAutomatic1.identifier(),
testNull.identifier());
assertNotEquals(testNull.identifier(),
testManual3a.identifier());
assertNotEquals(testManual3a.identifier(),
testNull.identifier());

// Test the two imported instances against each other
assertEquals(testAutomatic1.internalIdentifier(),
testAutomatic1.internalIdentifier());
assertEquals(testAutomatic2.internalIdentifier(),
testAutomatic2.internalIdentifier());
assertNotEquals(testAutomatic1.internalIdentifier(),
testAutomatic2.internalIdentifier());
assertNotEquals(testAutomatic2.internalIdentifier(),
testAutomatic1.internalIdentifier());
assertNotEquals(testAutomatic1.internalIdentifier(),
testManual3a.internalIdentifier());
assertEquals(testManual3b.internalIdentifier(),
testManual3a.internalIdentifier());
assertNotEquals(testManual3a.internalIdentifier(),
testManual4.internalIdentifier());
assertEquals(testAutomatic1.identifier(),
testAutomatic1.identifier());
assertEquals(testAutomatic2.identifier(),
testAutomatic2.identifier());
assertNotEquals(testAutomatic1.identifier(),
testAutomatic2.identifier());
assertNotEquals(testAutomatic2.identifier(),
testAutomatic1.identifier());
assertNotEquals(testAutomatic1.identifier(),
testManual3a.identifier());
assertEquals(testManual3b.identifier(),
testManual3a.identifier());
assertNotEquals(testManual3a.identifier(),
testManual4.identifier());
}

/**
Expand All @@ -105,15 +110,17 @@ public String ntriplesString() {
}

@Override
public String internalIdentifier() {
public String identifier() {
return null;
}
};
BlankNode testAutomatic1 = getBlankNode();
BlankNode testAutomatic2 = getBlankNode();
BlankNode testManual3a = getBlankNode("3");
BlankNode testManual3b = getBlankNode("3");
BlankNode testManual4 = getBlankNode("4");
String uuid3 = "b6415793-b706-4cbe-b406-14bad9c8e66f";
String uuid4 = "36638869-2d18-4499-8be4-5b7434f9da45";
BlankNode testManual3a = getBlankNode(uuid3);
BlankNode testManual3b = getBlankNode(uuid3);
BlankNode testManual4 = getBlankNode(uuid4);

// Test against our fake stub
assertNotEquals(testNull, testAutomatic1);
Expand Down Expand Up @@ -143,15 +150,17 @@ public String ntriplesString() {
}

@Override
public String internalIdentifier() {
public String identifier() {
return null;
}
};
BlankNode testAutomatic1 = getBlankNode();
BlankNode testAutomatic2 = getBlankNode();
BlankNode testManual3a = getBlankNode("3");
BlankNode testManual3b = getBlankNode("3");
BlankNode testManual4 = getBlankNode("4");
String uuid3 = "b6415793-b706-4cbe-b406-14bad9c8e66f";
String uuid4 = "36638869-2d18-4499-8be4-5b7434f9da45";
BlankNode testManual3a = getBlankNode(uuid3);
BlankNode testManual3b = getBlankNode(uuid3);
BlankNode testManual4 = getBlankNode(uuid4);

// Test against our fake stub
assertNotEquals(testNull.hashCode(), testAutomatic1.hashCode());
Expand Down Expand Up @@ -182,15 +191,17 @@ public String ntriplesString() {
}

@Override
public String internalIdentifier() {
public String identifier() {
return null;
}
};
BlankNode testAutomatic1 = getBlankNode();
BlankNode testAutomatic2 = getBlankNode();
BlankNode testManual3a = getBlankNode("3");
BlankNode testManual3b = getBlankNode("3");
BlankNode testManual4 = getBlankNode("4");
String uuid3 = "b6415793-b706-4cbe-b406-14bad9c8e66f";
String uuid4 = "36638869-2d18-4499-8be4-5b7434f9da45";
BlankNode testManual3a = getBlankNode(uuid3);
BlankNode testManual3b = getBlankNode(uuid3);
BlankNode testManual4 = getBlankNode(uuid4);

// Test against our fake stub
assertNotEquals(testNull.ntriplesString(),
Expand Down
Expand Up @@ -66,8 +66,8 @@ public void createGraphAndAdd() {
knows = factory.createIRI("http://xmlns.com/foaf/0.1/knows");
member = factory.createIRI("http://xmlns.com/foaf/0.1/member");
try {
org1 = factory.createBlankNode("org1");
org2 = factory.createBlankNode("org2");
org1 = factory.createBlankNode();
org2 = factory.createBlankNode();
} catch (UnsupportedOperationException ex) {
// leave as null
}
Expand Down Expand Up @@ -119,7 +119,7 @@ public void graphToString() {
.startsWith(
"<http://example.com/alice> <http://xmlns.com/foaf/0.1/name> \"Alice\" ."));
assertTrue(graph.toString().endsWith(
"_:org2 <http://xmlns.com/foaf/0.1/name> \"A company\" ."));
" <http://xmlns.com/foaf/0.1/name> \"A company\" ."));

}

Expand Down