All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bigdata.rdf.sail.webapp.client.BackgroundTupleResult Maven / Gradle / Ivy

/*
 * Copyright Aduna (http://www.aduna-software.com/) (c) 2008-2009.
 *
 * Licensed under the Aduna BSD-style license.
 */
package com.bigdata.rdf.sail.webapp.client;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

import org.openrdf.query.BindingSet;
import org.openrdf.query.QueryEvaluationException;
import org.openrdf.query.QueryResultHandlerException;
import org.openrdf.query.TupleQueryResult;
import org.openrdf.query.TupleQueryResultHandler;
import org.openrdf.query.TupleQueryResultHandlerException;
import org.openrdf.query.impl.TupleQueryResultImpl;
import org.openrdf.query.resultio.QueryResultParseException;
import org.openrdf.query.resultio.TupleQueryResultParser;
import org.openrdf.repository.sparql.query.QueueCursor;

/**
 * Provides concurrent access to tuple results as they are being parsed.
 * 
 * @author James Leigh
 */
public class BackgroundTupleResult extends TupleQueryResultImpl implements
		TupleQueryResult, Runnable, TupleQueryResultHandler {

	final private Object closeLock = new Object();

	private volatile boolean closed;

	private Thread parserThread;

	final private TupleQueryResultParser parser;

	final private InputStream in;

	final private QueueCursor queue;

	// No need to synchronize this field because visibility is guaranteed
	// by happens-before of CountDownLatch's countDown() and await()
	private List bindingNames;

	final private CountDownLatch bindingNamesReady = new CountDownLatch(1);

    public BackgroundTupleResult(final TupleQueryResultParser parser,
            final InputStream in) {
        
    	// TODO Why is the capacity so small? Why not 100 or more?
		this(new QueueCursor(10/* capacity */), parser, in);

	}

    public BackgroundTupleResult(final QueueCursor queue,
            final TupleQueryResultParser parser, final InputStream in) {
        super(Collections.emptyList(), queue);
		this.queue = queue;
		this.parser = parser;
		this.in = in;
	}

    @Override
	public void handleClose() throws QueryEvaluationException {
		synchronized (closeLock) {
			if (!closed) {
				closed = true;
				if (parserThread != null) {
					parserThread.interrupt();
				}
				if (in != null) {
					try {
						in.close();
					} catch (IOException e) {
						throw new QueryEvaluationException(e);
					}
				}
			}
		}
	}

    @Override
	public List getBindingNames() {
		try {
            /*
             * Note: close() will interrupt the parserThread if it is running.
             * That will cause the latch to countDown() and unblock this method
             * if the binding names have not yet been parsed from the
             * connection.
             */
		    bindingNamesReady.await();
			queue.checkException();
			if (closed)
				throw new UndeclaredThrowableException(null, "Result closed");
			return bindingNames;
		} catch (InterruptedException e) {
			throw new UndeclaredThrowableException(e);
		} catch (QueryEvaluationException e) {
			throw new UndeclaredThrowableException(e);
		}
	}

    @Override
	public void run() {
		synchronized (closeLock) {
			if (closed) {
				// Result was closed before it was run.
				// Need to unblock latch
				bindingNamesReady.countDown();
				return;
			}
			parserThread = Thread.currentThread();
		}
//		boolean completed = false;
		try {
			/*
			 * Run the parser, pumping events into this class (which is its own
			 * listener).
			 */
			parser.setTupleQueryResultHandler(this);
			parser.parse(in);
//			completed = true;
		} catch (TupleQueryResultHandlerException e) {
			// parsing cancelled or interrupted
		} catch (QueryResultParseException e) {
			queue.toss(e);
		} catch (IOException e) {
			queue.toss(e);
		} catch (NoClassDefFoundError e) {
			queue.toss(new QueryResultParseException(e));
		} finally {
			synchronized (closeLock) {
				parserThread = null;
			}
			queue.done();
			bindingNamesReady.countDown();
		}
	}

	@Override
	public void startQueryResult(final List bindingNames)
			throws TupleQueryResultHandlerException {
		this.bindingNames = bindingNames;
		bindingNamesReady.countDown();
	}

    @Override
	public void handleSolution(final BindingSet bindingSet)
			throws TupleQueryResultHandlerException {
		if (closed)
			throw new TupleQueryResultHandlerException("Result closed");
		try {
			queue.put(bindingSet);
		} catch (InterruptedException e) {
			throw new TupleQueryResultHandlerException(e);
		}
	}

    @Override
	public void endQueryResult() throws TupleQueryResultHandlerException {
		// no-op
	}

    @Override
    public void handleBoolean(boolean arg0) throws QueryResultHandlerException {

        throw new UnsupportedOperationException("Cannot handle boolean results");
        
    }

    @Override
    public void handleLinks(List arg0)
            throws QueryResultHandlerException {
        // no-op
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy