/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.jena.riot.system; import java.io.OutputStream ; import java.io.Writer ; import org.apache.jena.atlas.io.AWriter ; import org.apache.jena.atlas.io.IO ; import org.apache.jena.atlas.lib.CharSpace ; import org.apache.jena.atlas.lib.Sink ; import org.apache.jena.graph.Graph ; import org.apache.jena.graph.Node ; import org.apache.jena.graph.Triple ; import org.apache.jena.riot.lang.StreamRDFCounting ; import org.apache.jena.riot.writer.WriterStreamRDFPlain ; import org.apache.jena.shared.JenaException ; import org.apache.jena.shared.PrefixMapping ; import org.apache.jena.sparql.core.DatasetGraph ; import org.apache.jena.sparql.core.Quad ; /** Various Common StreamRDF setups */ public class StreamRDFLib { /** Send everything to nowhere ... efficiently */ public static StreamRDF sinkNull() { return new StreamRDFBase() ; } /** * Create a {@link StreamRDF} that outputs to an {@link OutputStream}. It is important * to call {@link StreamRDF#start} and {@link StreamRDF#finish} because the output is * buffered. */ public static StreamRDF writer(OutputStream out) { return new WriterStreamRDFPlain(IO.wrapUTF8(out)) ; } /** Create a {@link StreamRDF} that outputs to an {@link AWriter}. */ public static StreamRDF writer(AWriter out) { return new WriterStreamRDFPlain(out) ; } /** * Create a {@link StreamRDF} that outputs to an {@link Writer}. It is important to * call {@link StreamRDF#start} and {@link StreamRDF#finish} because the output is * buffered. */ public static StreamRDF writer(Writer out) { return new WriterStreamRDFPlain(IO.wrap(out)) ; } /** * Create a {@link StreamRDF} that outputs to an {@link OutputStream} with a specific * {@link CharSpace} (ASCII or UTF-8). * <p> * It is important to call {@link StreamRDF#start} * and {@link StreamRDF#finish} because the output is buffered. */ public static StreamRDF writer(OutputStream out, CharSpace charSpace) { switch (charSpace) { case ASCII : return new WriterStreamRDFPlain(IO.wrapASCII(out), charSpace) ; case UTF8 : default : return writer(out) ; } } /** * Create a {@link StreamRDF} that outputs to an {@link OutputStream} with a specific * {@link CharSpace} (ASCII or UTF-8). * <p> * It is important to call {@link StreamRDF#start} * and {@link StreamRDF#finish} because the output is buffered. */ public static StreamRDF writer(AWriter out, CharSpace charSpace) { return new WriterStreamRDFPlain(out, charSpace) ; } /** * Create a {@link StreamRDF} that outputs to an {@link Writer} with a specific * {@link CharSpace} (ASCII or UTF-8) writing out-of-range codepoints (if ASCII) * as "\ uXXXX". * <p> * It is important to call {@link StreamRDF#start} * and {@link StreamRDF#finish} because the output is buffered. */ public static StreamRDF writer(Writer out, CharSpace charSpace) { return new WriterStreamRDFPlain(IO.wrap(out), charSpace) ; } public static StreamRDF graph(Graph graph) { return new ParserOutputGraph(graph) ; } public static StreamRDF dataset(DatasetGraph dataset) { return new ParserOutputDataset(dataset) ; } /** * Output to a sink; prefix and base handled only within the parser. * Unfortunately, Java needs different names for the triples and * quads versions because of type erasure. */ public static StreamRDF sinkTriples(Sink<Triple> sink) { return new ParserOutputSinkTriples(sink) ; } /** * Output to a sink; prefix and base handled only within the parser. * Unfortunately, Java needs different names for the triples and * quads versions because of type erasure. */ public static StreamRDF sinkQuads(Sink<Quad> sink) { return new ParserOutputSinkQuads(sink) ; } /** Convert any triples seen to a quads, adding a graph node of {@link Quad#tripleInQuad} */ public static StreamRDF extendTriplesToQuads(StreamRDF base) { return extendTriplesToQuads(Quad.tripleInQuad, base) ; } /** Convert any triples seen to a quads, adding the specified graph node */ public static StreamRDF extendTriplesToQuads(Node graphNode, StreamRDF base) { return new ParserOutputSinkTriplesToQuads(graphNode, base) ; } public static StreamRDFCounting count() { return new StreamRDFCountingBase(sinkNull()) ; } public static StreamRDFCounting count(StreamRDF other) { return new StreamRDFCountingBase(other) ; } private static class ParserOutputSinkTriplesToQuads extends StreamRDFWrapper { private final Node gn ; ParserOutputSinkTriplesToQuads(Node gn, StreamRDF base) { super(base) ; this.gn = gn ; } @Override public void triple(Triple triple) { other.quad(new Quad(gn, triple)) ; } } private static class ParserOutputSinkTriples extends StreamRDFBase { private final Sink<Triple> sink ; public ParserOutputSinkTriples(Sink<Triple> sink) { this.sink = sink ; } @Override public void triple(Triple triple) { sink.send(triple) ; } @Override public void finish() { sink.flush() ; } } private static class ParserOutputSinkQuads extends StreamRDFBase { private final Sink<Quad> sink ; public ParserOutputSinkQuads(Sink<Quad> sink) { this.sink = sink ; } @Override public void quad(Quad quad) { sink.send(quad) ; } @Override public void finish() { sink.flush() ; } } private static class ParserOutputGraph extends StreamRDFBase { protected final Graph graph ; protected boolean warningIssued = false ; public ParserOutputGraph(Graph graph) { this.graph = graph ; } @Override public void triple(Triple triple) { graph.add(triple) ; } @Override public void quad(Quad quad) { if ( quad.isTriple() || quad.isDefaultGraph() ) graph.add(quad.asTriple()) ; else { if ( ! warningIssued ) { //SysRIOT.getLogger().warn("Only triples or default graph data expected : named graph data ignored") ; // Not ideal - assumes the global default. ErrorHandlerFactory.getDefaultErrorHandler().warning("Only triples or default graph data expected : named graph data ignored", -1, -1) ; } warningIssued = true ; } //throw new IllegalStateException("Quad passed to graph parsing") ; } @Override public void base(String base) { } @Override public void prefix(String prefix, String uri) { try { // Jena applies XML rules to prerfixes. graph.getPrefixMapping().setNsPrefix(prefix, uri) ; } catch (JenaException ex) {} } } private static class ParserOutputDataset extends StreamRDFBase { protected final DatasetGraph dsg ; protected final PrefixMapping prefixMapping ; public ParserOutputDataset(DatasetGraph dsg) { this.dsg = dsg ; this.prefixMapping = dsg.getDefaultGraph().getPrefixMapping() ; // = dsg.getPrefixMapping().setNsPrefix(prefix, uri) ; } @Override public void triple(Triple triple) { dsg.add(Quad.defaultGraphNodeGenerated, triple.getSubject(), triple.getPredicate(), triple.getObject()) ; //throw new IllegalStateException("Triple passed to dataset parsing") ; } @Override public void quad(Quad quad) { if ( quad.isTriple() ) dsg.add(Quad.defaultGraphNodeGenerated, quad.getSubject(), quad.getPredicate(), quad.getObject()) ; else dsg.add(quad) ; } @Override public void base(String base) { } @Override public void prefix(String prefix, String uri) { try { // Jena applies XML rules to prerfixes. prefixMapping.setNsPrefix(prefix, uri) ; } catch (JenaException ex) {} } } }