/*
* Copyright 2008 Fedora Commons, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mulgara.protocol;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.List;
import org.apache.log4j.Logger;
import org.jrdf.graph.BlankNode;
import org.jrdf.graph.Literal;
import org.jrdf.graph.URIReference;
import org.mulgara.query.Answer;
import org.mulgara.query.TuplesException;
import org.mulgara.query.Variable;
/**
* Converts an answer to a stream, acccording to the protocol of the implementing class.
*
* @created Sep 1, 2008
* @author Paula Gearon
* @copyright © 2008 <a href="http://www.fedora-commons.org/">Fedora Commons</a>
*/
public abstract class AbstractStreamedAnswer {
/** Logger. */
private final static Logger logger = Logger.getLogger(AbstractStreamedAnswer.class);
/** The API {@link Answer}s to convert to the stream. */
protected final List<Answer> answers;
/** The number of columns in the current Answer. */
protected int width;
/** The {@link Variable}s in the current Answer. */
protected Variable[] vars;
/** The writer used for creating the XML. */
protected OutputStreamWriter s = null;
/** The byte output stream used for creating the XML. */
protected OutputStream output = null;
/** The charset encoding to use when writing to the output stream. */
Charset charset = Charset.forName("UTF-8");
/** Adds a literal to the stream */
protected abstract void addLiteral(Literal literal) throws IOException;
/** Adds a blank node to the stream */
protected abstract void addBNode(BlankNode bnode) throws IOException;
/** Adds a URI reference to the stream */
protected abstract void addURI(URIReference uri) throws IOException;
/** Adds a variable binding to the stream */
protected abstract void addBinding(Variable var, Object value) throws TuplesException, IOException;
/** Adds a single result to the stream */
protected abstract void addResult(Answer a) throws TuplesException, IOException;
/** Adds all results to the stream */
protected abstract void addResults(Answer a) throws TuplesException, IOException;
/** Adds a variable in the header to the stream */
protected abstract void addHeaderVariable(Variable var) throws IOException;
/** Adds the entire header to the stream */
protected abstract void addHeader(Answer a) throws IOException;
/** Adds the answer footer to the stream */
protected abstract void addFooter(Answer a) throws IOException;
/** Closes the document in the stream */
protected abstract void addDocFooter() throws IOException;
/** Oopens the document in the stream */
protected abstract void addDocHeader() throws IOException;
/**
* Creates the object around the answer and output stream.
* @param answer The answer to encode.
* @param output The stream to write to.
*/
public AbstractStreamedAnswer(Answer answer, OutputStream output) {
this(Collections.singletonList(answer), output);
}
/**
* Creates the object around the answer and output stream.
* @param answer The answer to encode.
* @param output The stream to write to.
*/
public AbstractStreamedAnswer(Answer answer, OutputStream output, String charsetName) {
this(Collections.singletonList(answer), output, charsetName);
}
/**
* Creates the object around the answer and output stream.
* @param answer The answer to encode.
* @param output The stream to write to.
*/
public AbstractStreamedAnswer(List<Answer> answers, OutputStream output) {
this.answers = answers;
this.output = output;
}
/**
* Creates the object around the answer and output stream.
* @param answer The answer to encode.
* @param output The stream to write to.
*/
public AbstractStreamedAnswer(List<Answer> answers, OutputStream output, String charsetName) {
this(answers, output);
try {
charset = Charset.forName(charsetName);
} catch (Exception e) {
logger.error("Invalid charset. Using UTF-8: " + charsetName);
}
}
/**
* @see org.mulgara.protocol.StreamedXMLAnswer#emit()
*/
public void emit() throws TuplesException, IOException {
if (s == null) {
s = new OutputStreamWriter(output, charset);
generate();
s.flush();
}
}
/**
* Generates the XML document in the {@link #s} buffer.
* @throws TuplesException Indicates an error accessing the Answer.
*/
void generate() throws TuplesException, IOException {
addDocHeader();
for (Answer a: answers) {
width = (a != null) ? a.getNumberOfVariables() : 0;
vars = (a != null) ? a.getVariables() : null;
addHeader(a);
addResults(a);
addFooter(a);
}
addDocFooter();
}
/**
* Frees resources.
* @throws IOException
*/
public void close() throws IOException {
s.flush();
output.close();
}
/**
* Not to be called for when doing an "emit". Only used when more manual control is needed
* due to streaming multiple answers.
*/
public void initOutput() {
if (s == null) s = new OutputStreamWriter(output, charset);
}
}