/******************************************************************************* * 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.Writer; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import org.openanzo.analysis.RequestAnalysis; import org.openanzo.cache.ICacheProvider; import org.openanzo.datasource.IReplicationService; import org.openanzo.exceptions.AnzoException; import org.openanzo.exceptions.ExceptionConstants; import org.openanzo.ontologies.openanzo.NamedGraph; import org.openanzo.rdf.Literal; import org.openanzo.rdf.RDFFormat; import org.openanzo.rdf.Statement; import org.openanzo.rdf.URI; import org.openanzo.rdf.Value; import org.openanzo.rdf.Constants.NAMESPACES; import org.openanzo.rdf.utils.Collections; import org.openanzo.rdf.utils.ReadWriteUtils; import org.openanzo.rdf.utils.UriGenerator; import org.openanzo.services.DynamicServiceStats; import org.openanzo.services.IOperationContext; import org.openanzo.services.ITracker; import org.openanzo.services.IUpdateResultListener; import org.openanzo.services.Privilege; import org.openanzo.services.serialization.INamedGraphUpdateHandler; import org.openanzo.services.serialization.IReplicationHandler; import org.openanzo.services.serialization.ReplicationHandler; import org.openanzo.services.serialization.Writers; /** * Base implementation of the IReplicationService * * @author Matthew Roy ( <a href="mailto:mroy@cambridgesemantics.com">mroy@cambridgesemantics.com </a>) * */ public abstract class BaseReplicationService extends BaseDatasourceComponent implements IReplicationService { //private static final Logger log = LoggerFactory.getLogger(BaseReplicationService.class); private final ReplicationWithCacheStats stats = new ReplicationWithCacheStats("replicate"); ReplicationCache cache = null; protected void initializeCache(ICacheProvider cacheProvider) { if (cacheProvider != null) { cache = new ReplicationCache(cacheProvider.<URI, NamedGraphRevision> openCache(getDatasource().getInstanceURI() + "_" + "ReplicationService", 1000, true)); } } public void start() throws AnzoException { stats.setEnabled(true); } public void reset() throws AnzoException { stats.reset(); if (cache != null) cache.reset(); } public String getName() { return getDatasource().getName() + ",Service=ReplicationService"; } public String getDescription() { return "Replication Service for " + getDatasource().getName(); } public DynamicServiceStats getStatistics() { return stats; } /** * Get the cacheUpdateListener for this service * * @return the cacheUpdateListener for this service */ public IUpdateResultListener getCacheUpdateListener() { return cache; } public void replicate(IOperationContext context, String reader, String readerFormat, int batchSize, Writer output, String format) throws AnzoException { long start = 0; if (stats.isEnabled()) { start = System.currentTimeMillis(); } if (getLockProvider() != null) getLockProvider().readLock().lock(); logEntry(); try { Collection<Statement> trackers = ReadWriteUtils.readStatements(reader, RDFFormat.forMIMEType(readerFormat)); INamedGraphUpdateHandler writer = Writers.getNamedGraphUpdatesWriter(output, format); ReplicationHandler handler = new ReplicationHandler(writer); replicate(context, trackers, handler, batchSize); } finally { if (stats.isEnabled()) { stats.use("replicate", (System.currentTimeMillis() - start)); } if (getLockProvider() != null) getLockProvider().readLock().unlock(); logExit(); } } public void replicate(IOperationContext context, Collection<Statement> trackers, IReplicationHandler handler, int batchSize) throws AnzoException { long start = 0; if (stats.isEnabled()) { start = System.currentTimeMillis(); } if (getLockProvider() != null) getLockProvider().readLock().lock(); logEntry(); try { Collection<NamedGraphRevision> newGraphs = new ArrayList<NamedGraphRevision>(); Collection<NamedGraphRevision> diffGraphs = new ArrayList<NamedGraphRevision>(); for (Statement statement : trackers) { if (statement.getPredicate().equals(NamedGraph.revisionProperty)) { Value rev = statement.getObject(); if (rev instanceof Literal) { long revision = Long.parseLong(((Literal) rev).getLabel()); URI ngURI = (URI) statement.getSubject(); URI uuid = null; if (ngURI.toString().startsWith(NAMESPACES.NAMEDGRAPH_REVISIONED_UUID_PREFIX)) { uuid = ngURI; try { ngURI = getDatasource().getModelService().getUriForUUID(context, uuid); } catch (AnzoException ae) { if (ae.getErrorCode() != ExceptionConstants.DATASOURCE.NAMEDGRAPH.NOT_FOUND) { throw ae; } } } else if (ngURI.toString().startsWith(NAMESPACES.NAMEDGRAPH_NONREVISIONED_UUID_PREFIX)) { uuid = ngURI; try { ngURI = getDatasource().getModelService().getUriForUUID(context, uuid); } catch (AnzoException ae) { if (ae.getErrorCode() != ExceptionConstants.DATASOURCE.NAMEDGRAPH.NOT_FOUND) { throw ae; } } } else { try { uuid = getDatasource().getModelService().getUUIDforUri(context, ngURI); } catch (AnzoException ae) { if (ae.getErrorCode() != ExceptionConstants.DATASOURCE.NAMEDGRAPH.NOT_FOUND) { throw ae; } } } if (ngURI != null) { URI metadataGraphUri = UriGenerator.generateMetadataGraphUri(ngURI); try { NamedGraphRevision ngr = new NamedGraphRevision(ngURI, metadataGraphUri, uuid, revision, revision == -1, context.getOperationPrincipal().isSysadmin() || Collections.memberOf(getDatasource().getAuthorizationService().getRolesForGraph(context, ngURI, Privilege.READ), context.getOperationPrincipal().getRoles()), context.getOperationPrincipal().isSysadmin() || Collections.memberOf(getDatasource().getAuthorizationService().getRolesForGraph(context, metadataGraphUri, Privilege.READ), context.getOperationPrincipal().getRoles())); if (revision == -1) { newGraphs.add(ngr); } else { diffGraphs.add(ngr); } } catch (AnzoException ae) { if (ae.getErrorCode() != ExceptionConstants.DATASOURCE.NAMEDGRAPH.NOT_FOUND) throw ae; } } } } } handler.start(0); for (Iterator<NamedGraphRevision> iter = newGraphs.iterator(); iter.hasNext();) { NamedGraphRevision ngr = iter.next(); if (cache != null && ngr.uuid != null) { if (cache.lookupCache(ngr.uuid, handler)) { stats.cacheHit.increment(); iter.remove(); if (RequestAnalysis.isAnalysisEnabled(context.getAttributes())) { RequestAnalysis.addAnalysisProperty(RequestAnalysis.ANS_PROP_CACHE_HIT, Boolean.TRUE); } } else { stats.cacheMiss.increment(); if (RequestAnalysis.isAnalysisEnabled(context.getAttributes())) { RequestAnalysis.addAnalysisProperty(RequestAnalysis.ANS_PROP_CACHE_HIT, Boolean.FALSE); } } } } if (newGraphs.size() > 0 || diffGraphs.size() > 0) { replicateInternal(context, newGraphs, diffGraphs, handler, cache); } else { handler.end(); } } finally { if (stats.isEnabled()) { stats.use("replicate", (System.currentTimeMillis() - start)); } if (getLockProvider() != null) getLockProvider().readLock().unlock(); logExit(); } } /** * Determine delta changes between marker and last transaction committed on server * * @param context * {@link IOperationContext} context for this operation * @param trackers * Set of existing {@link ITracker}s. * @param Trackers * Set of {@link ITracker}s. * @param handler * {@link IRepositoryHandler} call-back handler to which changes are written * @throws AnzoException */ protected abstract void replicateInternal(IOperationContext context, Collection<NamedGraphRevision> newGraphs, Collection<NamedGraphRevision> diffGraphs, IReplicationHandler handler, ReplicationCache cache) throws AnzoException; }