LoggingRepositoryConnection.java
/*******************************************************************************
* Copyright (c) 2021 Eclipse RDF4J contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/
package org.eclipse.rdf4j.spring.operationlog;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.lang.invoke.MethodHandles;
import java.net.URL;
import org.eclipse.rdf4j.common.iteration.CloseableIteration;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Resource;
import org.eclipse.rdf4j.model.Statement;
import org.eclipse.rdf4j.model.Value;
import org.eclipse.rdf4j.query.GraphQuery;
import org.eclipse.rdf4j.query.MalformedQueryException;
import org.eclipse.rdf4j.query.QueryLanguage;
import org.eclipse.rdf4j.query.TupleQuery;
import org.eclipse.rdf4j.query.Update;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.eclipse.rdf4j.repository.RepositoryException;
import org.eclipse.rdf4j.repository.RepositoryResult;
import org.eclipse.rdf4j.repository.base.RepositoryConnectionWrapper;
import org.eclipse.rdf4j.rio.RDFFormat;
import org.eclipse.rdf4j.rio.RDFParseException;
import org.eclipse.rdf4j.spring.dao.exception.RDF4JSpringException;
import org.eclipse.rdf4j.spring.operationlog.log.OperationLog;
import org.eclipse.rdf4j.spring.operationlog.log.PseudoOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Florian Kleedorfer
* @since 4.0.0
*/
public class LoggingRepositoryConnection extends RepositoryConnectionWrapper {
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
OperationLog operationLog;
public LoggingRepositoryConnection(RepositoryConnection delegate, OperationLog operationLog) {
super(delegate.getRepository(), delegate);
this.operationLog = operationLog;
}
@Override
public TupleQuery prepareTupleQuery(QueryLanguage ql, String queryString, String baseURI)
throws MalformedQueryException, RepositoryException {
logWarning();
return new LoggingTupleQuery(
getDelegate().prepareTupleQuery(ql, queryString, baseURI), operationLog);
}
@Override
public TupleQuery prepareTupleQuery(String query)
throws RepositoryException, MalformedQueryException {
logWarning();
return new LoggingTupleQuery(getDelegate().prepareTupleQuery(query), operationLog);
}
@Override
public TupleQuery prepareTupleQuery(QueryLanguage ql, String query)
throws RepositoryException, MalformedQueryException {
logWarning();
return new LoggingTupleQuery(getDelegate().prepareTupleQuery(ql, query), operationLog);
}
@Override
public GraphQuery prepareGraphQuery(QueryLanguage ql, String queryString, String baseURI)
throws MalformedQueryException, RepositoryException {
logWarning();
return new LoggingGraphQuery(
getDelegate().prepareGraphQuery(ql, queryString, baseURI), operationLog);
}
@Override
public GraphQuery prepareGraphQuery(String query)
throws RepositoryException, MalformedQueryException {
logWarning();
return new LoggingGraphQuery(getDelegate().prepareGraphQuery(query), operationLog);
}
@Override
public GraphQuery prepareGraphQuery(QueryLanguage ql, String query)
throws RepositoryException, MalformedQueryException {
logWarning();
return new LoggingGraphQuery(getDelegate().prepareGraphQuery(ql, query), operationLog);
}
@Override
public Update prepareUpdate(QueryLanguage ql, String updateString, String baseURI)
throws MalformedQueryException, RepositoryException {
logWarning();
return new LoggingUpdate(
getDelegate().prepareUpdate(ql, updateString, baseURI), operationLog);
}
@Override
public RepositoryResult<Statement> getStatements(
Resource subj, IRI pred, Value obj, Resource... contexts) throws RepositoryException {
logWarning();
return operationLog.runWithLog(
PseudoOperation.forGetSatements(subj, pred, obj, contexts),
() -> getDelegate().getStatements(subj, pred, obj, contexts));
}
@Override
public void add(RepositoryResult<Statement> statements, Resource... contexts)
throws RepositoryException {
operationLog.runWithLog(
PseudoOperation.forAdd(statements, contexts),
() -> getDelegate().add(statements, contexts));
}
@Override
public void add(File file, String baseURI, RDFFormat dataFormat, Resource... contexts)
throws IOException, RDFParseException, RepositoryException {
operationLog.runWithLog(
PseudoOperation.forAdd(file, baseURI, dataFormat, contexts),
wrapInRuntimeException(
() -> getDelegate().add(file, baseURI, dataFormat, contexts)));
}
@Override
public void add(InputStream in, String baseURI, RDFFormat dataFormat, Resource... contexts)
throws IOException, RDFParseException, RepositoryException {
operationLog.runWithLog(
PseudoOperation.forAdd(in, baseURI, dataFormat, contexts),
wrapInRuntimeException(() -> getDelegate().add(in, baseURI, dataFormat, contexts)));
}
@Override
public void add(Iterable<? extends Statement> statements, Resource... contexts)
throws RepositoryException {
operationLog.runWithLog(
PseudoOperation.forAdd(statements, contexts),
() -> getDelegate().add(statements, contexts));
}
@Override
public void add(
CloseableIteration<? extends Statement> statementIter, Resource... contexts)
throws RepositoryException {
operationLog.runWithLog(
PseudoOperation.forAdd(statementIter, contexts),
wrapInRuntimeException(() -> getDelegate().add(statementIter, contexts)));
}
@Override
public void add(Reader reader, String baseURI, RDFFormat dataFormat, Resource... contexts)
throws IOException, RDFParseException, RepositoryException {
operationLog.runWithLog(
PseudoOperation.forAdd(reader, baseURI, dataFormat, contexts),
wrapInRuntimeException(
() -> getDelegate().add(reader, baseURI, dataFormat, contexts)));
}
@Override
public void add(Resource subject, IRI predicate, Value object, Resource... contexts)
throws RepositoryException {
operationLog.runWithLog(
PseudoOperation.forAdd(subject, predicate, object, contexts),
() -> getDelegate().add(subject, predicate, object, contexts));
}
@Override
public void add(Statement st, Resource... contexts) throws RepositoryException {
operationLog.runWithLog(
PseudoOperation.forAdd(st, contexts), () -> getDelegate().add(st, contexts));
}
@Override
public void add(URL url, String baseURI, RDFFormat dataFormat, Resource... contexts)
throws IOException, RDFParseException, RepositoryException {
operationLog.runWithLog(
PseudoOperation.forAdd(url, baseURI, dataFormat, contexts),
wrapInRuntimeException(
() -> getDelegate().add(url, baseURI, dataFormat, contexts)));
}
@Override
public void remove(RepositoryResult<Statement> statements, Resource... contexts)
throws RepositoryException {
operationLog.runWithLog(
PseudoOperation.forRemove(statements, contexts),
wrapInRuntimeException(() -> getDelegate().remove(statements, contexts)));
}
@Override
public void remove(Iterable<? extends Statement> statements, Resource... contexts)
throws RepositoryException {
operationLog.runWithLog(
PseudoOperation.forRemove(statements, contexts),
() -> getDelegate().remove(statements, contexts));
}
@Override
public void remove(
CloseableIteration<? extends Statement> statementIter, Resource... contexts)
throws RepositoryException {
operationLog.runWithLog(
PseudoOperation.forRemove(statementIter, contexts),
wrapInRuntimeException(() -> getDelegate().remove(statementIter, contexts)));
}
@Override
public void remove(Resource subject, IRI predicate, Value object, Resource... contexts)
throws RepositoryException {
operationLog.runWithLog(
PseudoOperation.forRemove(subject, predicate, object, contexts),
() -> getDelegate().remove(subject, predicate, object, contexts));
}
@Override
public void remove(Statement st, Resource... contexts) throws RepositoryException {
operationLog.runWithLog(
PseudoOperation.forRemove(st, contexts), () -> getDelegate().remove(st, contexts));
}
@Override
public void clear(Resource... contexts) throws RepositoryException {
operationLog.runWithLog(
PseudoOperation.forClear(contexts), () -> getDelegate().clear((contexts)));
}
@Override
public RepositoryResult<Statement> getStatements(
Resource subj, IRI pred, Value obj, boolean includeInferred, Resource... contexts)
throws RepositoryException {
return operationLog.runWithLog(
PseudoOperation.forGetSatements(subj, pred, obj, includeInferred, contexts),
() -> getDelegate().getStatements(subj, pred, obj, includeInferred, contexts));
}
@Override
public boolean hasStatement(
Resource subj, IRI pred, Value obj, boolean includeInferred, Resource... contexts)
throws RepositoryException {
return operationLog.runWithLog(
PseudoOperation.forHasStatement(subj, pred, obj, includeInferred, contexts),
() -> getDelegate().hasStatement(subj, pred, obj, includeInferred, contexts));
}
@Override
public boolean hasStatement(Statement st, boolean includeInferred, Resource... contexts)
throws RepositoryException {
return operationLog.runWithLog(
PseudoOperation.forHasStatement(st, includeInferred, contexts),
() -> getDelegate().hasStatement(st, includeInferred, contexts));
}
@Override
public long size(Resource... contexts) throws RepositoryException {
return operationLog.runWithLog(
PseudoOperation.forSize(contexts), () -> getDelegate().size(contexts));
}
@Override
public void removeNamespace(String prefix) throws RepositoryException {
super.removeNamespace(prefix);
}
private Runnable wrapInRuntimeException(ExceptionThrowingRunnable task) {
return () -> {
try {
task.run();
} catch (Exception e) {
throw new RDF4JSpringException(e);
}
};
}
private interface ExceptionThrowingRunnable {
void run() throws Exception;
}
private void logWarning() {
logger.warn(
"rdf4j operations (queries and updates) are being timed and logged. "
+ "Don't do this in production as the log is not limited in size! "
+ "You can disable this feature by setting the configuration property "
+ "'org.eclipse.rdf4j.spring.operationlog.enabled' to 'false'");
}
}