package org.neo4j.rdf.store;
import java.util.ArrayList;
import java.util.Collection;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.graphdb.Transaction;
import org.neo4j.rdf.fulltext.FulltextIndex;
import org.neo4j.rdf.fulltext.QueryResult;
import org.neo4j.rdf.model.CompleteStatement;
import org.neo4j.rdf.model.Context;
import org.neo4j.rdf.model.Statement;
import org.neo4j.rdf.model.Uri;
import org.neo4j.rdf.model.Value;
import org.neo4j.rdf.model.Wildcard;
import org.neo4j.rdf.model.WildcardStatement;
import org.neo4j.rdf.store.representation.AbstractNode;
import org.neo4j.rdf.store.representation.AbstractRepresentation;
import org.neo4j.rdf.store.representation.RepresentationExecutor;
import org.neo4j.rdf.store.representation.RepresentationStrategy;
import org.neo4j.rdf.store.representation.standard.AbstractUriBasedExecutor;
/**
* Default implementation of an {@link RdfStore}.
*/
public abstract class RdfStoreImpl implements RdfStore
{
private final GraphDatabaseService graphDb;
private final RepresentationStrategy representationStrategy;
private boolean shutdownNeo4jInstancesUponShutdown;
/**
* @param graphDb the {@link GraphDatabaseService}.
* @param representationStrategy the {@link RepresentationStrategy}
* to use when storing statements.
*/
public RdfStoreImpl( GraphDatabaseService graphDb,
RepresentationStrategy representationStrategy )
{
this.graphDb = graphDb;
this.representationStrategy = representationStrategy;
}
/**
* @param shutdownNeo4jInstances If {@code true} then the call to
* {@link #shutDown()} will also shutdown.
*/
public void setShutdownNeo4jInstancesUponShutdown( boolean shutdownNeo4jInstances )
{
this.shutdownNeo4jInstancesUponShutdown = shutdownNeo4jInstances;
}
protected GraphDatabaseService graphDb()
{
return this.graphDb;
}
public RepresentationStrategy getRepresentationStrategy()
{
return this.representationStrategy;
}
public void addStatements( CompleteStatement... statements )
{
Transaction tx = graphDb.beginTx();
try
{
for ( Statement statement : statements )
{
addStatement( statement );
}
tx.success();
}
catch ( RuntimeException e )
{
e.printStackTrace();
throw e;
}
finally
{
tx.finish();
}
}
protected void addStatement( Statement statement )
{
AbstractRepresentation fragment = representationStrategy
.getAbstractRepresentation( statement,
new AbstractRepresentation() );
getExecutor().addToNodeSpace( fragment );
}
private RepresentationExecutor getExecutor()
{
return this.representationStrategy.getExecutor();
}
protected Node lookupNode( Value uri )
{
return getRepresentationStrategy().getExecutor().lookupNode(
new AbstractNode( uri ) );
}
protected RelationshipType relType( final String name )
{
return new RelationshipType()
{
public String name()
{
return name;
}
};
}
protected RelationshipType relType( Value value )
{
return relType( ( ( Uri ) value ).getUriAsString() );
}
protected RelationshipType relType( Statement statement )
{
return relType( statement.getPredicate() );
}
public Iterable<CompleteStatement> getStatements(
WildcardStatement statement, boolean includeInferredStatements )
{
// if ( weCanHandleStatement( statement ) )
// {
// // TODO: pseudo code below
// return graphMatchingFacade().getMatchingStatements(
// representationStrategy.getAbstractRepresentation( statement ) );
// }
throw new UnsupportedOperationException( "We can't handle get() for " +
"this statement: " + statement );
}
// private boolean weCanHandleStatement( WildcardStatement statement )
// {
// return false;
// }
public Iterable<QueryResult> searchFulltext( String query )
{
throw new UnsupportedOperationException( "No implementation here" );
}
public Iterable<QueryResult> searchFulltextWithSnippets( String query,
int snippetCountLimit )
{
throw new UnsupportedOperationException( "No implementation here" );
}
public int size( Context... contexts )
{
throw new UnsupportedOperationException();
}
protected boolean wildcardPattern( WildcardStatement statement,
boolean subjectWildcard, boolean predicateWildcard,
boolean objectWildcard )
{
return valueIsWildcard( statement.getSubject() ) == subjectWildcard &&
valueIsWildcard( statement.getPredicate() ) == predicateWildcard &&
valueIsWildcard( statement.getObject() ) == objectWildcard;
}
private boolean valueIsWildcard( Value potentialWildcard )
{
return potentialWildcard instanceof Wildcard;
}
// public Iterable<Statement> oldGetStatements( WildcardStatement statement,
// boolean includeInferredStatements )
// {
// S, null, null : No
// S, P, null : Yes
// null, null, O : No
// null, P, O : Yes (for objecttype)
// if ( theseAreNull( statementWithOptionalNulls, false, true, true ) )
// {
//
// }
// else if ( theseAreNull( statementWithOptionalNulls,
// false, false, true ) )
// {
//
// }
// else if ( theseAreNull( statementWithOptionalNulls,
// true, true, false ) )
// {
// }
// else if ( theseAreNull( statementWithOptionalNulls,
// true, false, false ) )
// {
//
// }
// String query = SparqlBuilder.getQuery( statementWithOptionalNulls );
//
// throw new UnsupportedOperationException();
// }
// private boolean theseAreNull( Statement statementWithOptionalNulls,
// boolean subjectIsNull, boolean predicateIsNull, boolean objectIsNull )
// {
// return objectComparesToNull( statementWithOptionalNulls.getSubject(),
// subjectIsNull )
// && objectComparesToNull( statementWithOptionalNulls.getPredicate(),
// predicateIsNull )
// && objectComparesToNull( statementWithOptionalNulls.getObject(),
// objectIsNull );
// }
// private boolean objectComparesToNull( Object object, boolean shouldBeNull )
// {
// return shouldBeNull ? object == null : object != null;
// }
public void removeStatements( WildcardStatement statement )
{
Collection<Statement> statementsToRemove = new ArrayList<Statement>();
for ( Statement statementFromGet : getStatements( statement, false ) )
{
statementsToRemove.add( statementFromGet );
}
for ( Statement statementToRemove : statementsToRemove )
{
removeStatementSimple( statementToRemove );
}
}
private void removeStatementSimple( Statement statement )
{
Transaction tx = graphDb.beginTx();
try
{
AbstractRepresentation fragment = representationStrategy
.getAbstractRepresentation( statement,
new AbstractRepresentation() );
getExecutor().removeFromNodeSpace( fragment );
tx.success();
}
finally
{
tx.finish();
}
}
public void shutDown()
{
// TemporaryLogger.getLogger().info( getClass().getName() +
// " shutDown called", new Exception( "Just a stack trace to see " +
// "where the shut down method is called" ) );
FulltextIndex index = getFulltextIndex();
if ( index != null )
{
index.shutDown();
}
// Shut down the Neo4j stuff if that flag is set.
if ( this.shutdownNeo4jInstancesUponShutdown )
{
// TODO This isn't a very nice check (instanceof)
RepresentationExecutor executor = this.getExecutor();
if ( executor instanceof AbstractUriBasedExecutor )
{
( (AbstractUriBasedExecutor) executor ).index().shutdown();
}
graphDb.shutdown();
}
}
/**
* @return the {@link FulltextIndex} instance on the executor, or
* <code>null</code> if no fulltext index is used.
*/
public FulltextIndex getFulltextIndex()
{
return ( ( AbstractUriBasedExecutor )
getRepresentationStrategy().getExecutor() ).getFulltextIndex();
}
/**
* Performs a reindex of the entire fulltext index. Please call
* {@link FulltextIndex#clear()} before using this.
*/
public void reindexFulltextIndex()
{
throw new UnsupportedOperationException();
}
protected static class InferenceOptions
{
private boolean includeSubClassOf;
private boolean includeSubPropertyOf;
protected InferenceOptions( boolean includeSubClassOf,
boolean includeSubPropertyOf )
{
this.includeSubClassOf = includeSubClassOf;
this.includeSubPropertyOf = includeSubPropertyOf;
}
public boolean isIncludeSubClassOf()
{
return includeSubClassOf;
}
public boolean isIncludeSubPropertyOf()
{
return includeSubPropertyOf;
}
}
// private static interface GraphMatchingFacade
// {
// /**
// * Takes an abstract representation of a <i>single</i> statement with
// * optional wildcards, and returns all matching statements in the
// * node space.
// * @param oneStatementWithWildcards an abstract representaiton of a
// * single statement, potentially with wildcards
// * @return all statements that match
// * <code>oneStatementWithWildcards</code>
// */
// Iterable<Statement> getMatchingStatements( AbstractRepresentation
// oneStatementWithWildcards );
// }
/* private GraphMatchingFacade graphMatchingFacade()
{
return new GraphMatchingFacade()
{
public Iterable<Statement> getMatchingStatements(
AbstractRepresentation statementRepresentation )
{
Map<PatternElement, AbstractElement>
patternToRepresentationMap =
buildPatternGraphFromAbstractRepresentation(
statementRepresentation );
Iterable<PatternMatch> matches = runMatchingEngine(
figureOutPatternStartNode( patternToRepresentationMap ),
figureOutGraphDbStartNode( statementRepresentation ) );
for ( PatternMatch match : matches )
{
// get abstract element for every pattern element
// get value for every abstract element
// construct statements
}
return null;
}
private Map<PatternElement, AbstractElement>
buildPatternGraphFromAbstractRepresentation(
AbstractRepresentation statementRepresentation )
{
return null;
}
private PatternNode figureOutPatternStartNode(
Map<PatternElement, AbstractElement> map )
{
return null;
}
private Iterable<PatternMatch> runMatchingEngine(
PatternNode patternStartNode, Node graphDbStartNode )
{
return PatternMatcher.getMatcher().match( patternStartNode,
graphDbStartNode );
}
private Node figureOutGraphDbStartNode( AbstractRepresentation
statementRepresentation )
{
// Resolve abstract nodes in representation to nodes
// through the executor
// Investigate meta model, check instance counts etc
// Return a smart start node
return null;
}
};
}*/
}