Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ dependencies {
testImplementation("org.junit.jupiter:junit-jupiter") // JUnit 5 for unit testing
testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.12.2") // JUnit 5 runtime for launching tests

testImplementation("org.mockito:mockito-core:5.5.0")
testImplementation("org.mockito:mockito-junit-jupiter:5.5.0")

// === For viewing logs during development (DO NOT include in production) ===
runtimeOnly("org.slf4j:slf4j-simple:2.0.9") // Simple SLF4J implementation for logging
}
Expand Down
62 changes: 62 additions & 0 deletions src/main/java/fr/inria/corese/core/next/api/AbstractBNode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package fr.inria.corese.core.next.api;

import java.util.Objects;

/**
* Abstract base class for blank nodes in an RDF graph.
* <p>
* Provides default implementations for {@link BNode#getID()},
* {@link Object#equals(Object)}, and {@link Object#hashCode()}.
* </p>
*/
public abstract class AbstractBNode implements BNode {

private static final String BLANK_NODE_PREFIX = "_:";

/** Internal identifier for the blank node (unique within a model) */
private final String id;

/** Serial version UID for serialization */
private static final long serialVersionUID = 1L;

/**
* Constructs a blank node with a specific identifier.
* <p>
* <b>Warning:</b> This bypasses the automatic ID generation and should only be
* used when restoring an existing RDF graph (e.g. during parsing or tests).
* </p>
*/
protected AbstractBNode(String id) {
this.id = Objects.requireNonNull(id, "Blank node ID must not be null");
}

@Override
public String getID() {
return id;
}

@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof BNode))
return false;
BNode other = (BNode) o;
return id.equals(other.getID());
}

@Override
public int hashCode() {
return id.hashCode();
}

@Override
public String stringValue() {
return BLANK_NODE_PREFIX + id;
}

@Override
public String toString() {
return BLANK_NODE_PREFIX + id;
}
}
119 changes: 80 additions & 39 deletions src/main/java/fr/inria/corese/core/next/api/Model.java
Original file line number Diff line number Diff line change
@@ -1,104 +1,145 @@
package fr.inria.corese.core.next.api;

import fr.inria.corese.core.next.impl.exception.IncorrectOperationException;

import java.io.Serializable;
import java.util.Optional;
import java.util.Set;

import fr.inria.corese.core.next.impl.exception.IncorrectOperationException;

/**
* This class represents an RDF model, a set of statements.
* This is the central class to handle RDF data.
* Statements can have zero or several resources as contexts to represents the different graphs in the model.
* A model also handles a set of namespaces. There can be different prefixes for the same namespace, although it is ill-advised, how it affects serialization is implementation-dependant. There cannot be two namespaces with the same prefix.
* Statements can have zero or several resources as contexts to represent the
* different graphs in the model.
* A model also handles a set of namespaces. There can be different prefixes for
* the same namespace, although it is ill-advised, how it affects serialization
* is implementation-dependant. There cannot be two namespaces with the same
* prefix.
* Statements can have zero or several resources as contexts, representing
* different named graphs within the modela
*/
public interface Model extends Set<Statement>, Serializable {
public interface Model extends Set<Statement>, Serializable, NamespaceAware {

/**
* @return a "read-only" view of this model. "query" operations are possible, such as {@code filter()} on {@code contains()} but modifications will throw {@link IncorrectOperationException}.
* @return a "read-only" view of this model. "query" operations are possible,
* such as {@code filter()} on {@code contains()} but modifications will
* throw {@link IncorrectOperationException}.
*/
Model unmodifiable();

/**
*
* @param prefix a prefix for the namespace. It should be unique in the model.
* @param name the IRI of the namespace. It should be a valid IRI.
* @param name the IRI of the namespace. It should be a valid IRI.
* @return the new Namespace created with the given prefix and name.
* @throws IncorrectOperationException if the Model is unmodifiable.
*/
Namespace setNamespace(String prefix, String name);

/**
* Set the namespace of this model. The prefix should be unique in the model.
*
* @param namespace the namespace object to be added.
* @throws IncorrectOperationException if the Model is unmodifiable.
*/
void setNamespace(Namespace namespace);

/**
* @param prefix the prefix of the namespace to be removed.
* @return the removed namespace, or an empty Optional if no namespace with the given prefix was found.
* @return the removed namespace, or an empty Optional if no namespace with the
* given prefix was found.
* @throws IncorrectOperationException if the Model is unmodifiable.
*/
Optional<Namespace> removeNamespace(String prefix);

/**
* Check if a statement is present in the model. Can be used to query for statement pattern using {@code null} values.
* @param subj a Resource, subject of the statement. Can be {@code null} to match any subject.
* @param pred an IRI, predicate of the statement. Can be {@code null} to match any predicate.
* @param obj a Value, object of the statement. Can be {@code null} to match any object.
* @param contexts any Resource, context of the statement. Optional parameter. Can be {@code null} to match any context.
* @return true if a statement with the associated context is in the model, false otherwise.
* Check if a statement is present in the model. Can be used to query for
* statement pattern using {@code null} values.
*
* @param subj a Resource, subject of the statement. Can be {@code null} to
* match any subject.
* @param pred an IRI, predicate of the statement. Can be {@code null} to
* match any predicate.
* @param obj a Value, object of the statement. Can be {@code null} to
* match any object.
* @param contexts any Resource, context of the statement. Optional parameter.
* Can be {@code null} to match any context.
* @return true if a statement with the associated context is in the model,
* false otherwise.
*/
boolean contains(Resource subj, IRI pred, Value obj, Resource... contexts);

/**
* Add a statement to the model.
* @param subj a Resource, subject of the statement. Cannot be {@code null}.
* @param pred an IRI, predicate of the statement. Cannot be {@code null}.
* @param obj a Value, object of the statement. Cannot be {@code null}.
* @param contexts any Resource, context of the statement. Optional parameter. Can be {@code null}.
* @return true if the statement was added, false if it was already present.
* @throws IncorrectOperationException if the Model is unmodifiable.
* Adds a statement to the model with optional context(s).
* If multiple contexts are provided, the statement is added once per context.
*
* @param subj the subject of the statement (must not be {@code null})
* @param pred the predicate of the statement (must not be {@code null})
* @param obj the object of the statement (must not be {@code null})
* @param contexts optional contexts in which to add the statement;
* may be {@code null} or empty to add to the default graph
* @return {@code true} if the model was modified, {@code false} otherwise
* @throws IncorrectOperationException if the model is unmodifiable
* @throws IllegalArgumentException if {@code subj}, {@code pred}, or
* {@code obj} is {@code null}
*/
boolean add(Resource subj, IRI pred, Value obj, Resource... contexts);

/**
* Remove statements from the model according to their context. If no context is given, all statements are removed, regardless of context.
* @param context a Resource, context of the statement. Optional parameter. Can be {@code null} to match any context.
* Remove statements from the model according to their context. If no context is
* given, all statements are removed, regardless of context.
*
* @param context a Resource, context of the statement. Optional parameter. Can
* be {@code null} to match any context.
* @return true if any statement was removed, false if none were present.
* @throws IncorrectOperationException if the Model is unmodifiable.
*/
boolean clear(Resource... context);

/**
* Remove a statements from the model. If no context is given, all corresponding statements are removed, regardless of context.
* @param subj a Resource, subject of the statement. Can be {@code null}.
* @param pred an IRI, predicate of the statement. Can be {@code null}.
* @param obj a Value, object of the statement. Can be {@code null}.
* @param contexts any Resource, context of the statement. Optional parameter. Can be {@code null} to match any context.
* Remove statements from the model. If no context is given, all corresponding
* statements are removed, regardless of context.
*
* @param subj a Resource, subject of the statement. Can be {@code null}.
* @param pred an IRI, predicate of the statement. Can be {@code null}.
* @param obj a Value, object of the statement. Can be {@code null}.
* @param contexts any Resource, context of the statement. Optional parameter.
* Can be {@code null} to match any context.
* @return true if any statement was removed, false if none were present.
* @throws IncorrectOperationException if the Model is unmodifiable.
*/
boolean remove(Resource subj, IRI pred, Value obj, Resource... contexts);

/**
* The returned iterator must throw {@link IncorrectOperationException} if the model is unmodifiable and a modification is attempted.
* @param subj a Resource, subject of the statement. Can be {@code null} to match any subject.
* @param pred a an IRI, predicate of the statement. Can be {@code null} to match any predicate.
* @param obj a Value, object of the statement. Can be {@code null} to match any object.
* @param contexts any Resource, context of the statement. Optional parameter. Can be {@code null} to match any context.
* The returned iterator must throw {@link IncorrectOperationException} if the
* model is unmodifiable and a modification is attempted.
*
* @param subj a Resource, subject of the statement. Can be {@code null} to
* match any subject.
* @param pred a an IRI, predicate of the statement. Can be {@code null} to
* match any predicate.
* @param obj a Value, object of the statement. Can be {@code null} to
* match any object.
* @param contexts any Resource, context of the statement. Optional parameter.
* Can be {@code null} to match any context.
* @return an iterator on a selection of statements.
*/
Iterable<Statement> getStatements(Resource subj, IRI pred, Value obj,
Resource... contexts);
Resource... contexts);

/**
* Filter the model according to the given statement pattern. The filter is inclusive, meaning that if a statement matches the pattern, it will be included in the result.
* @param subj a Resource, subject of the statement. Can be {@code null} to match any subject.
* @param pred an IRI, predicate of the statement. Can be {@code null} to match any predicate.
* @param obj a Value, object of the statement. Can be {@code null} to match any object.
* @param contexts any Resource, context of the statement. Optional parameter. Can be {@code null} to match any context.
* Filter the model according to the given statement pattern. The filter is
* inclusive, meaning that if a statement matches the pattern, it will be
* included in the result.
*
* @param subj a Resource, subject of the statement. Can be {@code null} to
* match any subject.
* @param pred an IRI, predicate of the statement. Can be {@code null} to
* match any predicate.
* @param obj a Value, object of the statement. Can be {@code null} to
* match any object.
* @param contexts any Resource, context of the statement. Optional parameter.
* Can be {@code null} to match any context.
* @return a new Model containing all statements matching the given pattern.
*/
Model filter(Resource subj, IRI pred, Value obj, Resource... contexts);
Expand Down
29 changes: 29 additions & 0 deletions src/main/java/fr/inria/corese/core/next/api/NamespaceAware.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package fr.inria.corese.core.next.api;

import java.util.Optional;
import java.util.Set;

/**
* An interface for models or stores that support RDF namespaces.
*/
public interface NamespaceAware {

/**
* Returns the set of namespaces defined in the model.
*
* @return a set of Namespace objects
*/
Set<Namespace> getNamespaces();

/**
* Returns the namespace associated with the given prefix, if any.
*
* @param prefix the namespace prefix
* @return an Optional containing the Namespace, or empty if none found
*/
default Optional<Namespace> getNamespace(String prefix) {
return getNamespaces().stream()
.filter(ns -> ns.getPrefix().equals(prefix))
.findFirst();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package fr.inria.corese.core.next.api.base.model;

import fr.inria.corese.core.next.api.BNode;

/**
* Abstract implementation of the {@link BNode} interface, providing common functionality for blank node representations.
* A blank node (BNode) https://www.w3.org/TR/rdf12-concepts/#section-blank-nodes
*/
public abstract class AbstractBNode implements BNode {

/**
* Returns the string value of this blank node, which is its unique identifier.
* This method is an implementation of {@link BNode#stringValue()} and simply returns the result of {@link #getID()}.
*
* @return The string value of the blank node (its unique identifier).
*/
@Override
public String stringValue() {
return getID();
}

/**
* Checks whether this blank node is equal to another object.
* Two blank nodes are considered equal if they are the same object in memory or if they have the same unique identifier (ID).
* This method is an implementation of {@link BNode#equals(Object)}.
*
* @param o The object to compare this blank node to.
* @return {@code true} if the two blank nodes are the same object or have the same unique identifier; {@code false} otherwise.
*/
@Override
public boolean equals(Object o) {
return this == o || o instanceof BNode
&& getID().equals(((BNode) o).getID());
}

/**
* Returns the hash code for this blank node. The hash code is based on the unique identifier of the blank node,
* using the hash code of the ID returned by {@link #getID()}.
* This method is an implementation of {@link BNode#hashCode()}.
*
* @return The hash code for this blank node.
*/
@Override
public int hashCode() {
return getID().hashCode();
}

/**
* Returns a string representation of this blank node in the form "_:{ID}" where {ID} is the unique identifier of the blank node.
*
* @return A string representing this blank node, prefixed with "_:" and followed by its unique identifier.
*/
@Override
public String toString() {
return "_:" + getID();
}
}
Loading