/*******************************************************************************
* Copyright (c) 2007 Cambridge Semantics Incorporated.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* File: $Source$
* Created by: Matthew Roy ( <a href="mailto:mroy@cambridgesemantics.com">mroy@cambridgesemantics.com </a>)
* Created on: Nov 1, 2007
* Revision: $Id$
*
* Contributors:
* Cambridge Semantics Incorporated - initial API and implementation
*******************************************************************************/
package org.openanzo.datasource.services;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import org.openanzo.analysis.RequestAnalysis;
import org.openanzo.cache.ICacheProvider;
import org.openanzo.datasource.IModelService;
import org.openanzo.exceptions.AnzoException;
import org.openanzo.exceptions.ExceptionConstants;
import org.openanzo.glitter.dataset.DefaultQueryDataset;
import org.openanzo.glitter.dataset.QueryDataset;
import org.openanzo.ontologies.openanzo.AnzoFactory;
import org.openanzo.ontologies.openanzo.Dataset;
import org.openanzo.rdf.AnzoGraph;
import org.openanzo.rdf.Constants;
import org.openanzo.rdf.IAnzoGraph;
import org.openanzo.rdf.IRDFHandler;
import org.openanzo.rdf.MemQuadStore;
import org.openanzo.rdf.NamedGraph;
import org.openanzo.rdf.RDFFormat;
import org.openanzo.rdf.Resource;
import org.openanzo.rdf.Statement;
import org.openanzo.rdf.StatementCollector;
import org.openanzo.rdf.URI;
import org.openanzo.rdf.Value;
import org.openanzo.rdf.Constants.OPTIONS;
import org.openanzo.rdf.utils.Collections;
import org.openanzo.rdf.utils.ReadWriteUtils;
import org.openanzo.rdf.utils.StatementUtils;
import org.openanzo.rdf.utils.UriGenerator;
import org.openanzo.services.DynamicServiceStats;
import org.openanzo.services.IOperationContext;
import org.openanzo.services.IUpdateResultListener;
import org.openanzo.services.Privilege;
import org.openanzo.services.serialization.IValueSetHandler;
import org.openanzo.services.serialization.WriterStringValueSetHandler;
import org.openanzo.services.serialization.handlers.URIStringValueSetHandler;
import org.openanzo.services.serialization.transport.QueryUriSetSerializer;
/**
* Base implementation of IModelService service
*
* @author Matthew Roy ( <a href="mailto:mroy@cambridgesemantics.com">mroy@cambridgesemantics.com </a>)
*
*/
public abstract class BaseModelService extends BaseDatasourceComponent implements IModelService {
/** Log for this Service */
//private static final Logger log = LoggerFactory.getLogger(BaseModelService.class);
private final ModelServiceWithCacheStats stats = new ModelServiceWithCacheStats("containsNamedGraph", "findStatements", "getNamedGraphRevision", "getSize", "getStoredNamedGraphs", "getUriForUUID", "getUUIDforUri", "resolveNamedDataset");
protected ModelServiceCache cache;
/**
* Initialize the model cache
*
* @param cacheProvider
* cache provider to use
*/
protected void initializeCache(ICacheProvider cacheProvider) {
if (cacheProvider != null) {
this.cache = new ModelServiceCache(getDatasource().getName() + "/ModelService", cacheProvider);
}
}
/**
* @return the cache
*/
public ModelServiceCache getCache() {
return cache;
}
/**
* Get the cacheUpdateListener for this service
*
* @return the cacheUpdateListener for this service
*/
public IUpdateResultListener getCacheUpdateListener() {
return cache;
}
public String getName() {
return getDatasource().getName() + ",Service=ModelService";
}
public String getDescription() {
return "Model Service for " + getDatasource().getName();
}
public DynamicServiceStats getStatistics() {
return stats;
}
public void reset() throws AnzoException {
stats.reset();
if (cache != null) {
cache.reset();
}
}
public void start() throws AnzoException {
stats.setEnabled(true);
}
protected boolean canRead(IOperationContext context, URI namedGraphUri) throws AnzoException {
try {
return namedGraphUri != null && (context.getOperationPrincipal().isSysadmin() || namedGraphUri.equals(Constants.GRAPHS.GRAPHS_DATASET) || namedGraphUri.equals(Constants.GRAPHS.METADATA_GRAPHS_DATASET) || Collections.memberOf(getDatasource().getAuthorizationService().getRolesForGraph(context, namedGraphUri, Privilege.READ), context.getOperationPrincipal().getRoles()));
} catch (AnzoException ae) {
if (ae.getErrorCode() == ExceptionConstants.DATASOURCE.NAMEDGRAPH.NOT_FOUND) {
return false;
} else {
throw ae;
}
}
}
/**
* Return the number of triples in graph
*
* @param context
* {@link IOperationContext} context for this operation
* @param namedGraphUri
* {@link URI} of named graph
* @return Number of statements in named graph
* @throws AnzoException
*/
public long getSize(IOperationContext context, URI namedGraphUri) throws AnzoException {
long start = 0;
if (stats.isEnabled()) {
start = System.currentTimeMillis();
}
if (getLockProvider() != null)
getLockProvider().readLock().lock();
logEntry();
try {
Long size = (cache != null) ? cache.getSize(namedGraphUri) : null;
if (size == null) {
stats.getGetSizeMiss().increment();
size = getSizeInternal(context, namedGraphUri);
if (cache != null)
cache.cacheSize(namedGraphUri, size);
if (RequestAnalysis.isAnalysisEnabled(context.getAttributes())) {
RequestAnalysis.addAnalysisProperty(RequestAnalysis.ANS_PROP_CACHE_HIT, Boolean.FALSE);
}
} else {
stats.getGetSizeHit().increment();
if (RequestAnalysis.isAnalysisEnabled(context.getAttributes())) {
RequestAnalysis.addAnalysisProperty(RequestAnalysis.ANS_PROP_CACHE_HIT, Boolean.TRUE);
}
}
if (!canRead(context, namedGraphUri)) {
return 0;
} else {
return size;
}
} finally {
if (stats.isEnabled()) {
stats.use("getSize", (System.currentTimeMillis() - start));
}
if (getLockProvider() != null)
getLockProvider().readLock().unlock();
logExit();
}
}
/**
* Write the number of triples in graph to a an output writer
*
* @param context
* {@link IOperationContext} context for this operation
* @param namedGraphUri
* {@link URI} of named graph
* @param output
* {@link Writer} onto which output is written
* @throws AnzoException
*/
public void getSize(IOperationContext context, URI namedGraphUri, Writer output) throws AnzoException {
long size = getSize(context, namedGraphUri);
org.openanzo.rdf.utils.SerializationUtils.writeValue(size, output, null);
}
public URI getUriForUUID(IOperationContext context, URI namedGraphUUID) throws AnzoException {
long start = 0;
if (stats.isEnabled()) {
start = System.currentTimeMillis();
}
if (getLockProvider() != null)
getLockProvider().readLock().lock();
logEntry();
try {
URI uri = (cache != null) ? cache.getUriForUUID(namedGraphUUID) : null;
if (uri == null) {
stats.getGetUriForUUIDMiss().increment();
uri = getUriForUUIDInternal(context, namedGraphUUID);
if (cache != null)
cache.cacheUriForUUID(namedGraphUUID, uri);
if (RequestAnalysis.isAnalysisEnabled(context.getAttributes())) {
RequestAnalysis.addAnalysisProperty(RequestAnalysis.ANS_PROP_CACHE_HIT, Boolean.FALSE);
}
} else {
stats.getGetUriForUUIDHit().increment();
if (RequestAnalysis.isAnalysisEnabled(context.getAttributes())) {
RequestAnalysis.addAnalysisProperty(RequestAnalysis.ANS_PROP_CACHE_HIT, Boolean.TRUE);
}
}
if (!canRead(context, uri)) {
return null;
} else {
return uri;
}
} finally {
if (stats.isEnabled()) {
stats.use("getUriForUUID", (System.currentTimeMillis() - start));
}
if (getLockProvider() != null)
getLockProvider().readLock().unlock();
logExit();
}
}
public void getUriForUUID(IOperationContext context, URI namedGraphUUID, Writer output) throws AnzoException {
URI uri = getUriForUUID(context, namedGraphUUID);
org.openanzo.rdf.utils.SerializationUtils.writeValue(uri, output, null);
}
public URI getUUIDforUri(IOperationContext context, URI namedGraphURI) throws AnzoException {
long start = 0;
if (stats.isEnabled()) {
start = System.currentTimeMillis();
}
if (getLockProvider() != null)
getLockProvider().readLock().lock();
logEntry();
try {
URI uri = (cache != null) ? cache.getUUIDforURI(namedGraphURI) : null;
if (uri == null) {
stats.getGetUriForUUIDMiss().increment();
uri = getUUIDforUriInternal(context, namedGraphURI);
if (cache != null)
cache.cacheUUIDforURI(namedGraphURI, uri);
if (RequestAnalysis.isAnalysisEnabled(context.getAttributes())) {
RequestAnalysis.addAnalysisProperty(RequestAnalysis.ANS_PROP_CACHE_HIT, Boolean.FALSE);
}
} else {
stats.getGetUriForUUIDHit().increment();
if (RequestAnalysis.isAnalysisEnabled(context.getAttributes())) {
RequestAnalysis.addAnalysisProperty(RequestAnalysis.ANS_PROP_CACHE_HIT, Boolean.TRUE);
}
}
if (!canRead(context, namedGraphURI)) {
return null;
} else {
return uri;
}
} finally {
if (stats.isEnabled()) {
stats.use("", (System.currentTimeMillis() - start));
}
if (getLockProvider() != null)
getLockProvider().readLock().unlock();
logExit();
}
}
public void getUUIDforUri(IOperationContext context, URI namedGraphURI, Writer output) throws AnzoException {
URI uri = getUUIDforUri(context, namedGraphURI);
org.openanzo.rdf.utils.SerializationUtils.writeValue(uri, output, null);
}
/**
* Get the set of NamedGraphs stored on the server that the user has permission to see
*
* @param context
* {@link IOperationContext} context for this operation
* @param valueSetHandler
* {@link IValueSetHandler} call-back handler that handles the values found
*
* @throws AnzoException
*/
private void getStoredNamedGraphs(IOperationContext context, IValueSetHandler<String> valueSetHandler) throws AnzoException {
long start = 0;
if (stats.isEnabled()) {
start = System.currentTimeMillis();
}
if (getLockProvider() != null)
getLockProvider().readLock().lock();
logEntry();
try {
getStoredNamedGraphsInternal(context, valueSetHandler);
} finally {
if (stats.isEnabled()) {
stats.use("getStoredNamedGraphs", (System.currentTimeMillis() - start));
}
if (getLockProvider() != null)
getLockProvider().readLock().unlock();
logExit();
}
}
/**
* Get the set of NamedGraphs stored on the server that the user has permission to see
*
* @param context
* {@link IOperationContext} context for this operation
* @return the set of {@link URI}s for named graphs stored on the server that the user has permission to see
* @throws AnzoException
*/
public Set<URI> getStoredNamedGraphs(IOperationContext context) throws AnzoException {
long start = 0;
if (stats.isEnabled()) {
start = System.currentTimeMillis();
}
if (getLockProvider() != null)
getLockProvider().readLock().lock();
logEntry();
try {
URIStringValueSetHandler handler = new URIStringValueSetHandler();
getStoredNamedGraphsInternal(context, handler);
return handler.getURIs();
} finally {
if (stats.isEnabled()) {
stats.use("getStoredNamedGraphs", (System.currentTimeMillis() - start));
}
if (getLockProvider() != null)
getLockProvider().readLock().unlock();
logExit();
}
}
/**
* Get the set of NamedGraphs stored on the server that the user has permission to see
*
* @param context
* {@link IOperationContext} context for this operation
* @param output
* {@link Writer} to use to set write output
* @param format
* format of data to write
* @throws AnzoException
*/
public void getStoredNamedGraphs(IOperationContext context, Writer output, String format) throws AnzoException {
getStoredNamedGraphs(context, new WriterStringValueSetHandler(output, format));
}
HashSet<URI> resolvingUris = new HashSet<URI>();
ReentrantLock resolvingLock = new ReentrantLock();
Condition resolved = resolvingLock.newCondition();
public QueryDataset resolveNamedDataset(IOperationContext context, URI namedDatasetUri) throws AnzoException {
long start = 0;
if (stats.isEnabled()) {
start = System.currentTimeMillis();
}
if (getLockProvider() != null)
getLockProvider().readLock().lock();
try {
QueryDataset uriSet = null;
if (!canRead(context, namedDatasetUri)) {
return new DefaultQueryDataset();
}
resolvingLock.lock();
try {
if (resolvingUris.contains(namedDatasetUri)) {
try {
resolved.await();
} catch (InterruptedException ie) {
throw new AnzoException(ExceptionConstants.CORE.INTERRUPTED, ie);
}
}
resolvingUris.add(namedDatasetUri);
} finally {
resolvingLock.unlock();
}
try {
Boolean skipCache = context.getAttribute(OPTIONS.SKIPCACHE, Boolean.class);
uriSet = ((skipCache == null || !skipCache) && (cache != null)) ? cache.getNamedDataset(namedDatasetUri) : null;
if (uriSet == null) {
stats.getResolveNamedDatasetMiss().increment();
uriSet = resolveNamedDatasetInternal(context, namedDatasetUri);
if ((skipCache == null || !skipCache) && cache != null)
cache.cacheNamedDataset(namedDatasetUri, uriSet);
if (RequestAnalysis.isAnalysisEnabled(context.getAttributes())) {
RequestAnalysis.addAnalysisProperty(RequestAnalysis.ANS_PROP_DATASET_CACHE_HIT, Boolean.FALSE);
}
} else {
stats.getResolveNamedDatasetHit().increment();
if (RequestAnalysis.isAnalysisEnabled(context.getAttributes())) {
RequestAnalysis.addAnalysisProperty(RequestAnalysis.ANS_PROP_DATASET_CACHE_HIT, Boolean.TRUE);
}
}
if (stats.isEnabled()) {
stats.use("resolveNamedDataset", (System.currentTimeMillis() - start));
}
} finally {
resolvingLock.lock();
try {
if (resolvingUris.remove(namedDatasetUri)) {
resolved.signalAll();
}
} finally {
resolvingLock.unlock();
}
}
if (uriSet == null || !canRead(context, namedDatasetUri)) {
return new DefaultQueryDataset();
}
return uriSet;
} finally {
if (getLockProvider() != null)
getLockProvider().readLock().unlock();
}
}
public void resolveNamedDataset(IOperationContext context, URI namedDatasetUri, Writer output, String resultFormat) throws AnzoException {
QueryDataset result = resolveNamedDataset(context, namedDatasetUri);
String resultString = QueryUriSetSerializer.serialize(result, resultFormat);
try {
output.write(resultString);
} catch (IOException ioe) {
throw new AnzoException(ExceptionConstants.IO.WRITE_ERROR, ioe);
}
}
protected QueryDataset resolveNamedDatasetInternal(IOperationContext context, URI namedDatasetURI) throws AnzoException {
long start = -1;
if (RequestAnalysis.isAnalysisEnabled(context.getAttributes())) {
start = System.currentTimeMillis();
}
DefaultQueryDataset uriSet = new DefaultQueryDataset(new TreeSet<URI>(), new TreeSet<URI>(), new TreeSet<URI>());
IAnzoGraph graph = getNamedGraphRevision(context, namedDatasetURI, -1);
if (graph == null) {
return uriSet;
}
Dataset dataset = AnzoFactory.getDataset(namedDatasetURI, graph);
boolean includeMetadataGraphs = false;
if (dataset.getIncludeMetadataGraphs() != null) {
includeMetadataGraphs = (!namedDatasetURI.equals(Constants.GRAPHS.GRAPHS_DATASET) && !namedDatasetURI.equals(Constants.GRAPHS.METADATA_GRAPHS_DATASET));
if (includeMetadataGraphs && dataset.getIncludeMetadataGraphs() != null) {
includeMetadataGraphs = dataset.getIncludeMetadataGraphs();
}
}
for (Statement stmt : graph.find(namedDatasetURI, Dataset.defaultGraphProperty, null)) {
if (stmt.getObject() instanceof URI) {
URI uri = (URI) stmt.getObject();
uriSet.defaultGraphs.add(uri);
if (includeMetadataGraphs && !UriGenerator.isMetadataGraphUri(uri)) {
uriSet.defaultGraphs.add(UriGenerator.generateMetadataGraphUri(uri));
}
}
}
for (Statement stmt : graph.find(namedDatasetURI, Dataset.namedGraphProperty, null)) {
if (stmt.getObject() instanceof URI) {
URI uri = (URI) stmt.getObject();
uriSet.namedGraphs.add(uri);
if (includeMetadataGraphs && !UriGenerator.isMetadataGraphUri(uri)) {
uriSet.namedGraphs.add(UriGenerator.generateMetadataGraphUri(uri));
}
}
}
for (Statement stmt : graph.find(namedDatasetURI, Dataset.defaultNamedGraphProperty, null)) {
if (stmt.getObject() instanceof URI) {
URI uri = (URI) stmt.getObject();
uriSet.namedGraphs.add(uri);
uriSet.defaultGraphs.add(uri);
if (includeMetadataGraphs && !UriGenerator.isMetadataGraphUri(uri)) {
URI muri = UriGenerator.generateMetadataGraphUri(uri);
uriSet.namedGraphs.add(muri);
uriSet.defaultGraphs.add(muri);
}
}
}
if (RequestAnalysis.isAnalysisEnabled(context.getAttributes())) {
long end = System.currentTimeMillis();
RequestAnalysis.addAnalysisProperty("expandDataset", String.valueOf(end - start));
}
return uriSet;
}
/**
* Get the {@link URI} of the graph's metadata graph
*
* @param context
* Operation {@link IOperationContext} context for this operation
* @param namedGraphUri
* {@link URI} of named graph
* @return the {@link URI} of the graph's metadata graph
* @throws AnzoException
*/
public boolean containsNamedGraph(IOperationContext context, URI namedGraphUri) throws AnzoException {
long start = 0;
if (stats.isEnabled()) {
start = System.currentTimeMillis();
}
if (getLockProvider() != null)
getLockProvider().readLock().lock();
logEntry();
try {
Boolean contains = (cache != null) ? cache.getContains(namedGraphUri) : null;
if (contains == null) {
stats.getContainsNamedGraphMiss().increment();
contains = containsNamedGraphInternal(context, namedGraphUri);
if (cache != null)
cache.cacheContains(namedGraphUri, contains);
if (RequestAnalysis.isAnalysisEnabled(context.getAttributes())) {
RequestAnalysis.addAnalysisProperty(RequestAnalysis.ANS_PROP_CACHE_HIT, Boolean.FALSE);
}
} else {
stats.getContainsNamedGraphHit().increment();
if (RequestAnalysis.isAnalysisEnabled(context.getAttributes())) {
RequestAnalysis.addAnalysisProperty(RequestAnalysis.ANS_PROP_CACHE_HIT, Boolean.TRUE);
}
}
if (contains && canRead(context, namedGraphUri)) {
return true;
} else {
return false;
}
} finally {
if (stats.isEnabled()) {
stats.use("containsNamedGraph", (System.currentTimeMillis() - start));
}
if (getLockProvider() != null)
getLockProvider().readLock().unlock();
logExit();
}
}
public void containsNamedGraph(IOperationContext context, URI namedGraphUri, Writer output) throws AnzoException {
boolean contains = containsNamedGraph(context, namedGraphUri);
org.openanzo.rdf.utils.SerializationUtils.writeValue(contains, output, null);
}
/**
* Find the set of statements that match the statement pattern
*
* @param subj
* Subject {@link Resource} to match, or wildcard if null
* @param pred
* Predicate {@link URI} to match, or wildcard if null
* @param obj
* Object {@link Value} to match, or wildcard if null
* @param namedGraphURI
* {@link Resource} of named graph to match, or wildcard if null
* @return the set of {@link Statement} that match the quad pattern
* @throws AnzoException
*/
public Collection<Statement> findStatements(IOperationContext context, Resource subj, URI pred, Value obj, URI[] namedGraphURI) throws AnzoException {
long start = 0;
if (stats.isEnabled()) {
start = System.currentTimeMillis();
}
if (getLockProvider() != null)
getLockProvider().readLock().lock();
String queryString = StatementUtils.buildQueryString(subj, pred, obj, namedGraphURI);
try {
boolean useCache = cache != null && namedGraphURI != null && namedGraphURI.length > 0;
Collection<Statement> stmts = useCache ? cache.getFindStatements(queryString) : null;
if (stmts == null) {
stats.getFindStatementsMiss().increment();
StatementCollector sc = new StatementCollector();
findStatementsInternal(context, subj, pred, obj, namedGraphURI, sc);
stmts = sc.getStatements();
if (useCache)
cache.cacheFind(queryString, stmts);
if (RequestAnalysis.isAnalysisEnabled(context.getAttributes())) {
RequestAnalysis.addAnalysisProperty(RequestAnalysis.ANS_PROP_CACHE_HIT, Boolean.FALSE);
}
} else {
stats.getFindStatementsHit().increment();
if (RequestAnalysis.isAnalysisEnabled(context.getAttributes())) {
RequestAnalysis.addAnalysisProperty(RequestAnalysis.ANS_PROP_CACHE_HIT, Boolean.TRUE);
}
}
if (stats.isEnabled()) {
stats.use("findStatements", (System.currentTimeMillis() - start));
}
Collection<Statement> results = new ArrayList<Statement>();
HashMap<URI, Boolean> ok = new HashMap<URI, Boolean>();
if (stmts != null) {
for (Statement stmt : stmts) {
Boolean canRead = (context.getOperationPrincipal().isSysadmin()) ? Boolean.TRUE : ok.get(stmt.getNamedGraphUri());
if (canRead == null) {
canRead = canRead(context, stmt.getNamedGraphUri());
}
if (canRead) {
results.add(stmt);
}
}
}
return results;
} finally {
if (getLockProvider() != null)
getLockProvider().readLock().unlock();
}
}
/**
* Find the set of statements that match the statement pattern
*
* @param context
* Operation {@link IOperationContext} context for this operation
* @param subj
* Subject {@link Resource} to match, or wildcard if null
* @param pred
* Predicate {@link URI} to match, or wildcard if null
* @param obj
* Object {@link Value} to match, or wildcard if null
* @param namedGraphURI
* {@link Resource} of named graph to match, or wildcard if null
* @param writer
* {@link Writer} to which results are written
* @param format
* format of output data
* @throws AnzoException
*/
public void findStatements(IOperationContext context, Resource subj, URI pred, Value obj, URI[] namedGraphURI, Writer writer, String format) throws AnzoException {
IRDFHandler rdfWriter = ReadWriteUtils.getWriter(writer, RDFFormat.forMIMEType(format));
Collection<Statement> results = findStatements(context, subj, pred, obj, namedGraphURI);
rdfWriter.startRDF();
if (results != null) {
for (Statement stmt : results) {
rdfWriter.handleStatement(stmt);
}
}
rdfWriter.endRDF();
}
/**
* Get the contents of a named graph at a given revision
*
* @param context
* {@link IOperationContext} context for this operation
* @param namedGraphUri
* {@link URI} of named graph
* @param revision
* Revision of named graph to retrieve
* @return the {@link IAnzoGraph} containing results
* @throws AnzoException
*/
public IAnzoGraph getNamedGraphRevision(IOperationContext context, URI namedGraphUri, long revision) throws AnzoException {
long start = 0;
if (stats.isEnabled()) {
start = System.currentTimeMillis();
}
if (getLockProvider() != null)
getLockProvider().readLock().lock();
logEntry();
try {
Collection<Statement> stmts = (cache != null) ? cache.getGraph(namedGraphUri, revision) : null;
if (stmts == null) {
stats.getGetNamedGraphRevisionMiss().increment();
stmts = getNamedGraphRevisionInternal(context, namedGraphUri, revision);
if (cache != null)
cache.cacheGraph(namedGraphUri, stmts, revision);
if (RequestAnalysis.isAnalysisEnabled(context.getAttributes())) {
RequestAnalysis.addAnalysisProperty(RequestAnalysis.ANS_PROP_CACHE_HIT, Boolean.FALSE);
}
} else {
stats.getGetNamedGraphRevisionHit().increment();
if (RequestAnalysis.isAnalysisEnabled(context.getAttributes())) {
RequestAnalysis.addAnalysisProperty(RequestAnalysis.ANS_PROP_CACHE_HIT, Boolean.TRUE);
}
}
if (!canRead(context, namedGraphUri)) {
return null;
}
MemQuadStore quadStore = new MemQuadStore();
quadStore.add(stmts);
return new AnzoGraph(namedGraphUri, new NamedGraph(UriGenerator.generateMetadataGraphUri(namedGraphUri), quadStore), quadStore);
} finally {
if (stats.isEnabled()) {
stats.use("getNamedGraphRevision", (System.currentTimeMillis() - start));
}
if (getLockProvider() != null)
getLockProvider().readLock().unlock();
logExit();
}
}
/**
* Get the contents of a named graph at a given revision
*
* @param context
* {@link IOperationContext} context for this operation
* @param namedGraphUri
* {@link URI} of named graph
* @param revision
* Revision of named graph to retrieve
* @param writer
* {@link Writer} to which results are written
* @param formatString
* format of results for output data
* @throws AnzoException
*/
public void getNamedGraphRevision(IOperationContext context, URI namedGraphUri, long revision, Writer writer, String formatString) throws AnzoException {
RDFFormat format = RDFFormat.forMIMEType(formatString);
if (format.supportsNamedGraphs()) {
IRDFHandler handler = ReadWriteUtils.getWriter(writer, format);
if (handler != null) {
long start = 0;
if (stats.isEnabled()) {
start = System.currentTimeMillis();
}
if (getLockProvider() != null)
getLockProvider().readLock().lock();
logEntry();
try {
handler.startRDF();
Collection<Statement> stmts = (cache != null) ? cache.getGraph(namedGraphUri, revision) : null;
if (stmts == null) {
stats.getGetNamedGraphRevisionMiss().increment();
stmts = getNamedGraphRevisionInternal(context, namedGraphUri, revision);
if (cache != null)
cache.cacheGraph(namedGraphUri, stmts, revision);
if (RequestAnalysis.isAnalysisEnabled(context.getAttributes())) {
RequestAnalysis.addAnalysisProperty(RequestAnalysis.ANS_PROP_CACHE_HIT, Boolean.FALSE);
}
} else {
stats.getGetNamedGraphRevisionHit().increment();
if (!canRead(context, namedGraphUri)) {
stmts = null;
}
if (RequestAnalysis.isAnalysisEnabled(context.getAttributes())) {
RequestAnalysis.addAnalysisProperty(RequestAnalysis.ANS_PROP_CACHE_HIT, Boolean.TRUE);
}
}
if (stmts != null) {
for (Statement stmt : stmts) {
handler.handleStatement(stmt);
}
}
} finally {
handler.endRDF();
if (stats.isEnabled()) {
stats.use("getNamedGraphRevision", (System.currentTimeMillis() - start));
}
if (getLockProvider() != null)
getLockProvider().readLock().unlock();
logExit();
}
}
} else {
throw new AnzoException(ExceptionConstants.IO.NO_GRAPH_SUPPORT_RDFFORMAT, formatString);
}
}
/**
* Find the statements that match the provided quad pattern
*
* @param context
* {@link IOperationContext} context for this operation
* @param subj
* Subject {@link Resource} to match, or wildcard if null
* @param pred
* Predicate {@link URI} to match, or wildcard if null
* @param obj
* Object {@link Value} to match, or wildcard if null
* @param namedGraphURI
* {@link Resource} of named graph to match, or wildcard if null
* @param handler
* {@link IRDFHandler} which handles the result statements
* @throws AnzoException
*/
protected abstract void findStatementsInternal(IOperationContext context, Resource subj, URI pred, Value obj, URI[] namedGraphURI, IRDFHandler handler) throws AnzoException;
/**
* Get the size of a named graph
*
* @param context
* {@link IOperationContext} context for this operation
*
* @param namedGraphUri
* {@link URI} of named graph
* @return Number of triples in named graph
* @throws AnzoException
* Throws an exception if graph not found or user does not have permission to read graph. Note: If user doesn't have permission to see graph,
* unknown graph error is still thrown in order to prevent probing queries to determine existing of graphs
*/
protected abstract long getSizeInternal(IOperationContext context, URI namedGraphUri) throws AnzoException;
/**
* Get the URI of a NamedGraph given a UUID
*
* @param context
* {@link IOperationContext} context for this operation
*
* @param namedGraphUri
* UUID {@link URI} of named graph
* @return URI of named graph
* @throws AnzoException
* Throws an exception if graph not found or user does not have permission to read graph. Note: If user doesn't have permission to see graph,
* unknown graph error is still thrown in order to prevent probing queries to determine existing of graphs
*/
protected abstract URI getUriForUUIDInternal(IOperationContext context, URI namedGraphUUIDUri) throws AnzoException;
/**
* Get the UUID of a NamedGraph given a URI
*
* @param context
* {@link IOperationContext} context for this operation
*
* @param namedGraphUri
* UUID {@link URI} of named graph
* @return URI of named graph
* @throws AnzoException
* Throws an exception if graph not found or user does not have permission to read graph. Note: If user doesn't have permission to see graph,
* unknown graph error is still thrown in order to prevent probing queries to determine existing of graphs
*/
protected abstract URI getUUIDforUriInternal(IOperationContext context, URI namedGraphUri) throws AnzoException;
/**
* Return true if named graph is within this model
*
* @param context
* {@link IOperationContext} context for this operation
*
* @param namedGraphUri
* {@link URI} of named graph
* @return {@link boolean} if named graph is within this model
* @throws AnzoException
* Throws an exception if graph not found or user does not have permission to read graph. Note: If user doesn't have permission to see graph,
* unknown graph error is still thrown in order to prevent probing queries to determine existing of graphs
*/
protected abstract boolean containsNamedGraphInternal(IOperationContext context, URI namedGraphUri) throws AnzoException;
/**
* Get stored NamedGraphs that user can read
*
* @param context
* {@link IOperationContext} context for this operation
*
* @param valueSetHandler
* {@link IValueSetHandler} call-back handler for handling the values
* @throws AnzoException
*/
protected abstract void getStoredNamedGraphsInternal(IOperationContext context, IValueSetHandler<String> valueSetHandler) throws AnzoException;
/**
* Get the contents of a named graph at a given revision, and pass the results to an IBocaHandler. If the revision number is -1, this method should return
* the latest revision.
*
* @param context
* {@link IOperationContext} context for this operation
* @param namedGraphUri
* {@link URI} of named graph
* @param revision
* Revision to retrieve, or -1 for the latest revision.
* @param handler
* {@link IRepositoryHandler} call-back handler to which results are written
* @return true unless there was an exception
* @throws AnzoException
* If the graph is non-revisioned and the revision requested was not -1, throws an exception with identifier
* DATASOURCE.NAMEDGRAPH.NON_REVISIONED_GRAPH.
*/
protected abstract Collection<Statement> getNamedGraphRevisionInternal(IOperationContext context, URI namedGraphUri, long revision) throws AnzoException;
}