Package lupos.endpoint.client.formatreader

Source Code of lupos.endpoint.client.formatreader.XMLFormatReader

/**
* Copyright (c) 2013, Institute of Information Systems (Sven Groppe and contributors of LUPOSDATE), University of Luebeck
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
*   - Redistributions of source code must retain the above copyright notice, this list of conditions and the following
*     disclaimer.
*   - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
*     following disclaimer in the documentation and/or other materials provided with the distribution.
*   - Neither the name of the University of Luebeck nor the names of its contributors may be used to endorse or promote
*     products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package lupos.endpoint.client.formatreader;

import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import lupos.datastructures.bindings.Bindings;
import lupos.datastructures.bindings.BindingsFactory;
import lupos.datastructures.items.Triple;
import lupos.datastructures.items.Variable;
import lupos.datastructures.items.literal.Literal;
import lupos.datastructures.items.literal.LiteralFactory;
import lupos.datastructures.parallel.BoundedBuffer;
import lupos.datastructures.queryresult.BooleanResult;
import lupos.datastructures.queryresult.ParallelIterator;
import lupos.datastructures.queryresult.QueryResult;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class XMLFormatReader extends DefaultMIMEFormatReader {

  public final static String MIMETYPE = "application/sparql-results+xml";

  // the type of state used for sax parsing
  private static enum TYPE {
    uri, literal, typedliteral, languagetaggedliteral, blanknode, undefined
  }

  // the type of state for storing the value used for sax parsing
  private static enum TARGET_TYPE {
    var, subject, predicate, object, undefined
  }

  final ReentrantLock lock = new ReentrantLock();
  final Condition decisionMade = this.lock.newCondition();
  private volatile boolean decision = false;
  private volatile boolean booleanResult = false;
  private volatile boolean resultOfBooleanResult;

  protected static int BUFFERSIZE = 50;

  private final boolean writeQueryTriples;

  public XMLFormatReader(final boolean writeQueryTriples) {
    super("XML", XMLFormatReader.MIMETYPE+(writeQueryTriples?"+querytriples":""));
    this.writeQueryTriples = writeQueryTriples;
  }

  public XMLFormatReader(){
    this(false);
  }

  @Override
  public String getMIMEType() {
    return XMLFormatReader.MIMETYPE+(this.writeQueryTriples?"+querytriples":"");
  }

  @Override
  public QueryResult getQueryResult(final InputStream inputStream, final BindingsFactory bindingsFactory) {
    final BoundedBuffer<Bindings> boundedBuffer = new BoundedBuffer<Bindings>(BUFFERSIZE);

    final ParseThread parseThread = new ParseThread(inputStream, boundedBuffer, bindingsFactory);
    parseThread.start();

    this.lock.lock();
    try {
      // wait until it is clear whether it is a boolean result or a "normal" queryresult
      while(!this.decision){
        this.decisionMade.await();
      }
    } catch (final InterruptedException e) {
      System.err.println();
      e.printStackTrace();
    } finally {
      this.lock.unlock();
    }

    if(this.booleanResult){
      final BooleanResult result = new BooleanResult();
      if(this.resultOfBooleanResult){
        result.add(bindingsFactory.createInstance());
      }
      return result;
    } else {
      // This allows to follow the iterator concept also here:
      // the XML is parsed whenever the iterator is asked for the next element (method next).
      // Only some intermediate results (=bindings) are parsed beforehand and stored in the bounded buffer!
      return QueryResult.createInstance(new ParallelIterator<Bindings>(){

        @Override
        public boolean hasNext() {
          try {
            return boundedBuffer.hasNext();
          } catch (final InterruptedException e) {
            System.err.println(e);
            e.printStackTrace();
          }
          return false;
        }

        @Override
        public Bindings next() {
          try {
            return boundedBuffer.get();
          } catch (final InterruptedException e) {
            System.err.println(e);
            e.printStackTrace();
          }
          return null;
        }

        @Override
        public void remove() {
          throw new UnsupportedOperationException();
        }

        @Override
        public void close() {
          boundedBuffer.stopIt();
        }

        @Override
        public void finalize(){
          this.close();
        }
      });
    }
  }

  public class ParseThread extends Thread {

    private final InputStream inputStream;
    private final BoundedBuffer<Bindings> boundedBuffer;
    private final BindingsFactory bindingsFactory;

    public ParseThread(final InputStream inputStream, final BoundedBuffer<Bindings> boundedBuffer, final BindingsFactory bindingsFactory){
      this.inputStream = inputStream;
      this.boundedBuffer = boundedBuffer;
      this.bindingsFactory = bindingsFactory;
    }

    @Override
    public void run(){
      final SAXParserFactory factory = SAXParserFactory.newInstance();
      try {
        final SAXParser saxParser = factory.newSAXParser();
        final ResultsHandler resultsHandler = new ResultsHandler(this.boundedBuffer, this.bindingsFactory);
        saxParser.parse(this.inputStream, resultsHandler);
        this.boundedBuffer.endOfData();
      } catch (final ParserConfigurationException e) {
        System.err.println(e);
        e.printStackTrace();
      } catch (final SAXException e) {
        System.err.println(e);
        e.printStackTrace();
      } catch (final IOException e) {
        System.err.println(e);
        e.printStackTrace();
      }
    }
  }

  public class ResultsHandler extends DefaultHandler {


    private final BoundedBuffer<Bindings> boundedBuffer;

    private Bindings currentBindings;
    private Variable currentVariable;
    private TYPE currentType = TYPE.undefined;
    private TARGET_TYPE currentTargetType = TARGET_TYPE.undefined;
    private Triple currentTriple;
    private String currentAttribute = null;
    private String content = "";
    private final BindingsFactory bindingsFactory;

    public ResultsHandler(final BoundedBuffer<Bindings> boundedBuffer, final BindingsFactory bindingsFactory){
      this.boundedBuffer = boundedBuffer;
      this.bindingsFactory = bindingsFactory;
    }

    @Override
    public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException {
      this.currentType = TYPE.undefined;
      this.content = "";
      if(qName.equalsIgnoreCase("results")){
        this.currentTargetType = TARGET_TYPE.undefined;
        XMLFormatReader.this.lock.lock();
        try {
          XMLFormatReader.this.decision=true;
          XMLFormatReader.this.decisionMade.signalAll();
        } finally {
          XMLFormatReader.this.lock.unlock();
        }
      }  else if(qName.equalsIgnoreCase("result")){
        this.currentTargetType = TARGET_TYPE.undefined;
        this.currentBindings = this.bindingsFactory.createInstance();
      } else if(qName.equalsIgnoreCase("binding")){
        final String variableName = attributes.getValue("name");
        if(variableName==null){
          throw new RuntimeException("There is no name element given in a bindings-tag!");
        } else {
          this.currentTargetType = TARGET_TYPE.var;
          this.currentVariable = new Variable(variableName);
        }
      } else if(qName.equalsIgnoreCase("uri")){
        this.currentType = TYPE.uri;
      } else if(qName.equalsIgnoreCase("bnode")){
        this.currentType = TYPE.blanknode;
      } else if(qName.equalsIgnoreCase("literal")){
        final String datatype = attributes.getValue("datatype");
        if(datatype!=null){
          this.currentType = TYPE.typedliteral;
          this.currentAttribute = "<"+datatype+">";
          return;
        }
        final String lang = attributes.getValue("xml:lang");
        if(lang!=null){
          this.currentType = TYPE.languagetaggedliteral;
          this.currentAttribute = lang;
          return;
        }
        this.currentType = TYPE.literal;
      } else if(qName.equalsIgnoreCase("subject")){
        this.currentTargetType = TARGET_TYPE.subject;
      } else if(qName.equalsIgnoreCase("predicate")){
        this.currentTargetType = TARGET_TYPE.predicate;
      } else if(qName.equalsIgnoreCase("object")){
        this.currentTargetType = TARGET_TYPE.object;
      } else if(qName.equalsIgnoreCase("querytriple")){
        this.currentTriple = new Triple();
      }
      // do nothing for boolean-tag, which will be handled, when the tag is closed!
    }

    @Override
    public void endElement(final String uri, final String localName, final String qName) throws SAXException {
      if(qName.equalsIgnoreCase("result")){
        try {
          this.boundedBuffer.put(this.currentBindings);
        } catch (final InterruptedException e) {
          System.err.println(e);
          e.printStackTrace();
        }
      } else if(qName.equalsIgnoreCase("uri") ||
          qName.equalsIgnoreCase("bnode") ||
          qName.equalsIgnoreCase("literal")){
        this.handleValue();
      } else if(qName.equalsIgnoreCase("boolean")){
        XMLFormatReader.this.lock.lock();
        try {
          XMLFormatReader.this.booleanResult=true;
          XMLFormatReader.this.resultOfBooleanResult = this.content.equals("true");
          XMLFormatReader.this.decision=true;
          XMLFormatReader.this.decisionMade.signalAll();
        } finally {
          XMLFormatReader.this.lock.unlock();
        }
      } else if(qName.equalsIgnoreCase("querytriple")){
        this.currentBindings.addTriple(this.currentTriple);
      }
      this.currentType = TYPE.undefined;
    }

    private void handleValue(){
      Literal literal = null;
      switch(this.currentType){
      default:
      case undefined:
        break;
      case uri:
        literal = LiteralFactory.createURILiteralWithoutException("<"+this.content+">");
        break;
      case literal:
        literal = LiteralFactory.createLiteral("\""+this.content+"\"");
        break;
      case typedliteral:
        literal = LiteralFactory.createTypedLiteralWithoutException("\""+this.content+"\"", this.currentAttribute);
        break;
      case languagetaggedliteral:
        literal = LiteralFactory.createLanguageTaggedLiteral("\""+this.content+"\"", this.currentAttribute);
        break;
      case blanknode:
        literal = LiteralFactory.createAnonymousLiteral("_:"+this.content);
        break;
      }
      if(literal!=null){
        switch(this.currentTargetType){
          case var:
            this.currentBindings.add(this.currentVariable, literal);
            break;
          case subject:
            this.currentTriple.setPos(0, literal);
            break;
          case predicate:
            this.currentTriple.setPos(1, literal);
            break;
          case object:
            this.currentTriple.setPos(2, literal);
            break;
          case undefined:
            throw new RuntimeException("Retrieved sparql xml has bad structure!");
        }
      }
    }

    @Override
    public void characters(final char ch[], final int start, final int length) throws SAXException {
      // for a text node, the XML parser may be calls characters(...) several times,
      // such that the characters must be collected...
      this.content += new String(ch, start, length);
    }
  }
}
TOP

Related Classes of lupos.endpoint.client.formatreader.XMLFormatReader

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.