Package org.openrdf.query.resultio.binary

Source Code of org.openrdf.query.resultio.binary.BinaryQueryResultWriter

/*
* Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2009.
*
* Licensed under the Aduna BSD-style license.
*/
package org.openrdf.query.resultio.binary;

import static org.openrdf.query.resultio.binary.BinaryQueryResultConstants.BNODE_RECORD_MARKER;
import static org.openrdf.query.resultio.binary.BinaryQueryResultConstants.DATATYPE_LITERAL_RECORD_MARKER;
import static org.openrdf.query.resultio.binary.BinaryQueryResultConstants.EMPTY_TUPLE_RECORD_MARKER;
import static org.openrdf.query.resultio.binary.BinaryQueryResultConstants.ERROR_RECORD_MARKER;
import static org.openrdf.query.resultio.binary.BinaryQueryResultConstants.FORMAT_VERSION;
import static org.openrdf.query.resultio.binary.BinaryQueryResultConstants.LANG_LITERAL_RECORD_MARKER;
import static org.openrdf.query.resultio.binary.BinaryQueryResultConstants.MAGIC_NUMBER;
import static org.openrdf.query.resultio.binary.BinaryQueryResultConstants.MALFORMED_QUERY_ERROR;
import static org.openrdf.query.resultio.binary.BinaryQueryResultConstants.NAMESPACE_RECORD_MARKER;
import static org.openrdf.query.resultio.binary.BinaryQueryResultConstants.NULL_RECORD_MARKER;
import static org.openrdf.query.resultio.binary.BinaryQueryResultConstants.PLAIN_LITERAL_RECORD_MARKER;
import static org.openrdf.query.resultio.binary.BinaryQueryResultConstants.QNAME_RECORD_MARKER;
import static org.openrdf.query.resultio.binary.BinaryQueryResultConstants.QUERY_EVALUATION_ERROR;
import static org.openrdf.query.resultio.binary.BinaryQueryResultConstants.REPEAT_RECORD_MARKER;
import static org.openrdf.query.resultio.binary.BinaryQueryResultConstants.TABLE_END_RECORD_MARKER;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.openrdf.model.BNode;
import org.openrdf.model.Literal;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.query.BindingSet;
import org.openrdf.query.TupleQueryResultHandlerException;
import org.openrdf.query.impl.ListBindingSet;
import org.openrdf.query.resultio.TupleQueryResultFormat;
import org.openrdf.query.resultio.TupleQueryResultWriter;

/**
* Writer for the binary tuple result format. The format is explained in
* {@link BinaryQueryResultConstants}.
*
* @author Arjohn Kampman
*/
public class BinaryQueryResultWriter implements TupleQueryResultWriter {

  /*-----------*
   * Variables *
   *-----------*/

  /**
   * The output stream to write the results table to.
   */
  private final DataOutputStream out;

  private final CharsetEncoder charsetEncoder = Charset.forName("UTF-8").newEncoder();

  /**
   * Map containing the namespace IDs (Integer objects) that have been defined
   * in the document, stored using the concerning namespace (Strings).
   */
  private final Map<String, Integer> namespaceTable = new HashMap<String, Integer>(32);

  private int nextNamespaceID;

  private BindingSet previousBindings;

  private List<String> bindingNames;

  /*--------------*
   * Constructors *
   *--------------*/

  public BinaryQueryResultWriter(OutputStream out) {
    assert out != null : "out must not be null";
    this.out = new DataOutputStream(out);
  }

  /*---------*
   * Methods *
   *---------*/

  public final TupleQueryResultFormat getTupleQueryResultFormat() {
    return TupleQueryResultFormat.BINARY;
  }

  public void startQueryResult(List<String> bindingNames)
    throws TupleQueryResultHandlerException
  {
    // Copy supplied column headers list and make it unmodifiable
    bindingNames = new ArrayList<String>(bindingNames);
    this.bindingNames = Collections.unmodifiableList(bindingNames);

    try {
      out.write(MAGIC_NUMBER);
      out.writeInt(FORMAT_VERSION);

      out.writeInt(this.bindingNames.size());

      for (String bindingName : this.bindingNames) {
        writeString(bindingName);
      }

      List<Value> nullTuple = Collections.nCopies(this.bindingNames.size(), (Value)null);
      previousBindings = new ListBindingSet(this.bindingNames, nullTuple);
      nextNamespaceID = 0;
    }
    catch (IOException e) {
      throw new TupleQueryResultHandlerException(e);
    }
  }

  public void endQueryResult()
    throws TupleQueryResultHandlerException
  {
    try {
      out.writeByte(TABLE_END_RECORD_MARKER);
      out.flush();
    }
    catch (IOException e) {
      throw new TupleQueryResultHandlerException(e);
    }
  }

  public void handleSolution(BindingSet bindingSet)
    throws TupleQueryResultHandlerException
  {
    try {
      if (bindingNames.isEmpty()) {
        writeEmptyTuple();
      }
      else {
        for (String bindingName : bindingNames) {
          Value value = bindingSet.getValue(bindingName);

          if (value == null) {
            writeNull();
          }
          else if (value.equals(previousBindings.getValue(bindingName))) {
            writeRepeat();
          }
          else if (value instanceof URI) {
            writeQName((URI)value);
          }
          else if (value instanceof BNode) {
            writeBNode((BNode)value);
          }
          else if (value instanceof Literal) {
            writeLiteral((Literal)value);
          }
          else {
            throw new TupleQueryResultHandlerException("Unknown Value object type: " + value.getClass());
          }
        }

        previousBindings = bindingSet;
      }
    }
    catch (IOException e) {
      throw new TupleQueryResultHandlerException(e);
    }
  }

  private void writeNull()
    throws IOException
  {
    out.writeByte(NULL_RECORD_MARKER);
  }

  private void writeRepeat()
    throws IOException
  {
    out.writeByte(REPEAT_RECORD_MARKER);
  }

  private void writeQName(URI uri)
    throws IOException
  {
    // Check if the URI has a new namespace
    String namespace = uri.getNamespace();

    Integer nsID = namespaceTable.get(namespace);

    if (nsID == null) {
      // Generate a ID for this new namespace
      nsID = writeNamespace(namespace);
    }

    out.writeByte(QNAME_RECORD_MARKER);
    out.writeInt(nsID.intValue());
    writeString(uri.getLocalName());
  }

  private void writeBNode(BNode bnode)
    throws IOException
  {
    out.writeByte(BNODE_RECORD_MARKER);
    writeString(bnode.getID());
  }

  private void writeLiteral(Literal literal)
    throws IOException
  {
    String label = literal.getLabel();
    String language = literal.getLanguage();
    URI datatype = literal.getDatatype();

    int marker = PLAIN_LITERAL_RECORD_MARKER;

    if (datatype != null) {
      String namespace = datatype.getNamespace();

      if (!namespaceTable.containsKey(namespace)) {
        // Assign an ID to this new namespace
        writeNamespace(namespace);
      }

      marker = DATATYPE_LITERAL_RECORD_MARKER;
    }
    else if (language != null) {
      marker = LANG_LITERAL_RECORD_MARKER;
    }

    out.writeByte(marker);
    writeString(label);

    if (datatype != null) {
      writeQName(datatype);
    }
    else if (language != null) {
      writeString(language);
    }
  }

  private void writeEmptyTuple()
    throws IOException
  {
    out.writeByte(EMPTY_TUPLE_RECORD_MARKER);
  }

  /**
   * Writes an error msg to the stream.
   *
   * @param errType
   *        The error type.
   * @param msg
   *        The error message.
   * @throws IOException
   *         When the error could not be written to the stream.
   */
  public void error(QueryErrorType errType, String msg)
    throws IOException
  {
    out.writeByte(ERROR_RECORD_MARKER);

    if (errType == QueryErrorType.MALFORMED_QUERY_ERROR) {
      out.writeByte(MALFORMED_QUERY_ERROR);
    }
    else {
      out.writeByte(QUERY_EVALUATION_ERROR);
    }

    writeString(msg);
  }

  private Integer writeNamespace(String namespace)
    throws IOException
  {
    out.writeByte(NAMESPACE_RECORD_MARKER);
    out.writeInt(nextNamespaceID);
    writeString(namespace);

    Integer result = Integer.valueOf(nextNamespaceID);
    namespaceTable.put(namespace, result);

    nextNamespaceID++;

    return result;
  }

  private void writeString(String s)
    throws IOException
  {
    ByteBuffer byteBuf = charsetEncoder.encode(CharBuffer.wrap(s));
    out.writeInt(byteBuf.remaining());
    out.write(byteBuf.array(), 0, byteBuf.remaining());
  }
}
TOP

Related Classes of org.openrdf.query.resultio.binary.BinaryQueryResultWriter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.