/*
* Copyright Aduna (http://www.aduna-software.com/) (c) 2006-2007.
*
* Licensed under the Aduna BSD-style license.
*/
package org.openrdf.repository.http;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import info.aduna.iteration.CloseableIteratorIteration;
import org.openrdf.http.client.HTTPClient;
import org.openrdf.http.protocol.transaction.operations.AddStatementOperation;
import org.openrdf.http.protocol.transaction.operations.ClearNamespacesOperation;
import org.openrdf.http.protocol.transaction.operations.ClearOperation;
import org.openrdf.http.protocol.transaction.operations.RemoveNamespaceOperation;
import org.openrdf.http.protocol.transaction.operations.RemoveStatementsOperation;
import org.openrdf.http.protocol.transaction.operations.SetNamespaceOperation;
import org.openrdf.http.protocol.transaction.operations.TransactionOperation;
import org.openrdf.model.Literal;
import org.openrdf.model.Namespace;
import org.openrdf.model.Resource;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.model.impl.NamespaceImpl;
import org.openrdf.query.BindingSet;
import org.openrdf.query.BooleanQuery;
import org.openrdf.query.GraphQuery;
import org.openrdf.query.Query;
import org.openrdf.query.QueryEvaluationException;
import org.openrdf.query.QueryLanguage;
import org.openrdf.query.TupleQuery;
import org.openrdf.query.TupleQueryResult;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.RepositoryResult;
import org.openrdf.repository.base.RepositoryConnectionBase;
import org.openrdf.rio.RDFFormat;
import org.openrdf.rio.RDFHandler;
import org.openrdf.rio.RDFHandlerException;
import org.openrdf.rio.RDFParseException;
import org.openrdf.rio.helpers.StatementCollector;
/**
* RepositoryConnection that communicates with a server using the HTTP protocol.
* Methods in this class may throw the specific RepositoryException subclasses
* UnautorizedException and NotAllowedException, the semantics of which are
* defined by the HTTP protocol.
*
* @see org.openrdf.http.protocol.UnauthorizedException
* @see org.openrdf.http.protocol.NotAllowedException
* @author Arjohn Kampman
* @author Herko ter Horst
*/
class HTTPRepositoryConnection extends RepositoryConnectionBase {
/*-----------*
* Variables *
*-----------*/
private List<TransactionOperation> txn = Collections.synchronizedList(new ArrayList<TransactionOperation>());
/*--------------*
* Constructors *
*--------------*/
public HTTPRepositoryConnection(HTTPRepository repository) {
super(repository);
}
/*---------*
* Methods *
*---------*/
@Override
public HTTPRepository getRepository() {
return (HTTPRepository)super.getRepository();
}
/**
* Unsupported method, throws an {@link UnsupportedOperationException}.
*/
public Query prepareQuery(QueryLanguage ql, String queryString, String baseURI) {
throw new UnsupportedOperationException();
}
public TupleQuery prepareTupleQuery(QueryLanguage ql, String queryString, String baseURI) {
return new HTTPTupleQuery(this, ql, queryString, baseURI);
}
public GraphQuery prepareGraphQuery(QueryLanguage ql, String queryString, String baseURI) {
return new HTTPGraphQuery(this, ql, queryString, baseURI);
}
public BooleanQuery prepareBooleanQuery(QueryLanguage ql, String queryString, String baseURI) {
return new HTTPBooleanQuery(this, ql, queryString, baseURI);
}
public RepositoryResult<Resource> getContextIDs()
throws RepositoryException
{
try {
List<Resource> contextList = new ArrayList<Resource>();
TupleQueryResult contextIDs = getRepository().getHTTPClient().getContextIDs();
try {
while (contextIDs.hasNext()) {
BindingSet bindingSet = contextIDs.next();
Value context = bindingSet.getValue("contextID");
if (context instanceof Resource) {
contextList.add((Resource)context);
}
}
}
finally {
contextIDs.close();
}
return createRepositoryResult(contextList);
}
catch (QueryEvaluationException e) {
throw new RepositoryException(e);
}
catch (IOException e) {
throw new RepositoryException(e);
}
}
public RepositoryResult<Statement> getStatements(Resource subj, URI pred, Value obj,
boolean includeInferred, Resource... contexts)
throws RepositoryException
{
try {
StatementCollector collector = new StatementCollector();
exportStatements(subj, pred, obj, includeInferred, collector, contexts);
return createRepositoryResult(collector.getStatements());
}
catch (RDFHandlerException e) {
// found a bug in StatementCollector?
throw new RuntimeException(e);
}
}
public void exportStatements(Resource subj, URI pred, Value obj, boolean includeInferred,
RDFHandler handler, Resource... contexts)
throws RDFHandlerException, RepositoryException
{
try {
getRepository().getHTTPClient().getStatements(subj, pred, obj, includeInferred, handler, contexts);
}
catch (IOException e) {
throw new RepositoryException(e);
}
}
public long size(Resource... contexts)
throws RepositoryException
{
try {
return getRepository().getHTTPClient().size(contexts);
}
catch (IOException e) {
throw new RepositoryException(e);
}
}
public void commit()
throws RepositoryException
{
synchronized (txn) {
if (txn.size() > 0) {
try {
getRepository().getHTTPClient().sendTransaction(txn);
txn.clear();
}
catch (IOException e) {
throw new RepositoryException(e);
}
}
}
}
public void rollback() {
txn.clear();
}
@Override
public void close()
throws RepositoryException
{
if (txn.size() > 0) {
logger.warn("Rolling back transaction due to connection close", new Throwable());
rollback();
}
super.close();
}
@Override
protected void addInputStreamOrReader(Object inputStreamOrReader, String baseURI, RDFFormat dataFormat,
Resource... contexts)
throws IOException, RDFParseException, RepositoryException
{
if (isAutoCommit()) {
// Send bytes directly to the server
HTTPClient httpClient = getRepository().getHTTPClient();
if (inputStreamOrReader instanceof InputStream) {
httpClient.upload(((InputStream)inputStreamOrReader), baseURI, dataFormat, false, contexts);
}
else if (inputStreamOrReader instanceof Reader) {
httpClient.upload(((Reader)inputStreamOrReader), baseURI, dataFormat, false, contexts);
}
else {
throw new IllegalArgumentException(
"inputStreamOrReader must be an InputStream or a Reader, is a: "
+ inputStreamOrReader.getClass());
}
}
else {
// Parse files locally
super.addInputStreamOrReader(inputStreamOrReader, baseURI, dataFormat, contexts);
}
}
@Override
protected void addWithoutCommit(Resource subject, URI predicate, Value object, Resource... contexts)
throws RepositoryException
{
txn.add(new AddStatementOperation(subject, predicate, object, contexts));
}
@Override
protected void removeWithoutCommit(Resource subject, URI predicate, Value object, Resource... contexts)
throws RepositoryException
{
txn.add(new RemoveStatementsOperation(subject, predicate, object, contexts));
}
@Override
public void clear(Resource... contexts)
throws RepositoryException
{
txn.add(new ClearOperation(contexts));
autoCommit();
}
public void removeNamespace(String prefix)
throws RepositoryException
{
txn.add(new RemoveNamespaceOperation(prefix));
autoCommit();
}
public void clearNamespaces()
throws RepositoryException
{
txn.add(new ClearNamespacesOperation());
autoCommit();
}
public void setNamespace(String prefix, String name)
throws RepositoryException
{
txn.add(new SetNamespaceOperation(prefix, name));
autoCommit();
}
public RepositoryResult<Namespace> getNamespaces()
throws RepositoryException
{
try {
List<Namespace> namespaceList = new ArrayList<Namespace>();
TupleQueryResult namespaces = getRepository().getHTTPClient().getNamespaces();
try {
while (namespaces.hasNext()) {
BindingSet bindingSet = namespaces.next();
Value prefix = bindingSet.getValue("prefix");
Value namespace = bindingSet.getValue("namespace");
if (prefix instanceof Literal && namespace instanceof Literal) {
String prefixStr = ((Literal)prefix).getLabel();
String namespaceStr = ((Literal)namespace).getLabel();
namespaceList.add(new NamespaceImpl(prefixStr, namespaceStr));
}
}
}
finally {
namespaces.close();
}
return createRepositoryResult(namespaceList);
}
catch (QueryEvaluationException e) {
throw new RepositoryException(e);
}
catch (IOException e) {
throw new RepositoryException(e);
}
}
public String getNamespace(String prefix)
throws RepositoryException
{
try {
return getRepository().getHTTPClient().getNamespace(prefix);
}
catch (IOException e) {
throw new RepositoryException(e);
}
}
/**
* Creates a RepositoryResult for the supplied element set.
*/
protected <E> RepositoryResult<E> createRepositoryResult(Iterable<? extends E> elements) {
return new RepositoryResult<E>(new CloseableIteratorIteration<E, RepositoryException>(
elements.iterator()));
}
}