/*
* 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.OutputStreamWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import org.apache.log4j.Logger;
import org.jrdf.graph.BlankNode;
import org.jrdf.graph.Literal;
import org.jrdf.graph.TypedNodeVisitable;
import org.jrdf.graph.TypedNodeVisitor;
import org.jrdf.graph.URIReference;
import org.mulgara.query.Answer;
import org.mulgara.query.GraphAnswer;
import org.mulgara.query.TuplesException;
/**
* Represents a ConstructAnswer as N3.
* This is a very primitive implementation, with no attempt to use [] for blank nodes
* list structures, or even namespaces.
* TODO: Add prefixes
*
* @created Jan 29, 2009
* @author Paula Gearon
* @copyright © 2009 <a href="http://www.fedora-commons.org/">Fedora Commons</a>
*/
public class StreamedN3Answer implements StreamedAnswer {
/** Logger. */
private final static Logger logger = Logger.getLogger(StreamedN3Answer.class);
/** The answer to convert to RDF/XML. */
private final GraphAnswer ans;
/** The writer to send the data to. */
private final PrintWriter p;
/** The charset encoding to use when writing to the output stream. */
static final String UTF8 = "UTF-8";
/**
* Constructs the object and prepares to writing.
* @param ans The answer to emit.
* @param s The stream to write the answer to.
*/
public StreamedN3Answer(Answer ans, OutputStream s) {
this(ans, s, UTF8);
}
/**
* Constructs the object and prepares to writing.
* @param ans The answer to emit.
* @param s The stream to write the answer to.
*/
public StreamedN3Answer(Answer ans, OutputStream s, String charsetName) {
if (!(ans instanceof GraphAnswer)) throw new IllegalArgumentException("N3 constructor can only be constructed from a GraphAnswer");
this.ans = (GraphAnswer)ans;
assert ans.getVariables().length == 3;
Charset charset = null;
try {
charset = Charset.forName(charsetName);
} catch (Exception e) {
logger.error("Invalid charset. Using UTF-8: " + charsetName);
charset = Charset.forName(UTF8);
}
p = new PrintWriter(new OutputStreamWriter(s, charset));
}
/**
* Converts the Answer to a String and send to output.
* @throws TuplesException Indicates an error accessing the Answer.
*/
public void emit() throws TuplesException, IOException {
NodePrinter np = new NodePrinter();
ans.beforeFirst();
try {
while (ans.next()) {
((TypedNodeVisitable)ans.getObject(0)).accept(np);
((TypedNodeVisitable)ans.getObject(1)).accept(np);
((TypedNodeVisitable)ans.getObject(2)).accept(np);
p.println(".");
}
} catch (ClassCastException e) {
throw new TuplesException("Data in graph is not a node: " + e.getMessage());
} finally {
p.close();
}
}
/**
* Prints out the nodes as per N3.
*/
private class NodePrinter implements TypedNodeVisitor {
/**
* Prints the blank node and a space to the stream.
* @param blankNode The blank node to write.
*/
public void visitBlankNode(BlankNode blankNode) {
p.print("_:");
p.print(blankNode.toString().substring(1));
p.print(" ");
}
/**
* Prints the literal and a space to the stream.
* @param literal The literal to write.
*/
public void visitLiteral(Literal literal) {
p.print(literal.getEscapedForm());
p.print(" ");
}
/**
* Prints the uri surrounded by <> and a space to the stream.
* @param uriReference The uri to write.
*/
public void visitURIReference(URIReference uriReference) {
p.print("<");
p.print(uriReference);
p.print("> ");
}
}
public void addAnswer(Answer data) throws TuplesException, IOException {
throw new UnsupportedOperationException();
}
public void addDocFooter() throws IOException {
throw new UnsupportedOperationException();
}
public void addDocHeader() throws IOException {
throw new UnsupportedOperationException();
}
public void close() throws IOException {
p.close();
}
public void initOutput() {
// do nothing
}
}