001/*
002 * Licensed to DuraSpace under one or more contributor license agreements.
003 * See the NOTICE file distributed with this work for additional information
004 * regarding copyright ownership.
005 *
006 * DuraSpace licenses this file to you under the Apache License,
007 * Version 2.0 (the "License"); you may not use this file except in
008 * compliance with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.fcrepo.transform.http.responses;
019
020import static com.hp.hpl.jena.query.ResultSetFormatter.output;
021import static com.hp.hpl.jena.query.ResultSetFormatter.toModel;
022import static com.hp.hpl.jena.sparql.resultset.ResultsFormat.FMT_RDF_NT;
023import static com.hp.hpl.jena.sparql.resultset.ResultsFormat.FMT_RDF_TTL;
024import static com.hp.hpl.jena.sparql.resultset.ResultsFormat.FMT_RDF_XML;
025import static com.hp.hpl.jena.sparql.resultset.ResultsFormat.FMT_RS_BIO;
026import static com.hp.hpl.jena.sparql.resultset.ResultsFormat.FMT_RS_CSV;
027import static com.hp.hpl.jena.sparql.resultset.ResultsFormat.FMT_RS_JSON;
028import static com.hp.hpl.jena.sparql.resultset.ResultsFormat.FMT_RS_TSV;
029import static com.hp.hpl.jena.sparql.resultset.ResultsFormat.FMT_RS_XML;
030import static com.hp.hpl.jena.sparql.resultset.ResultsFormat.FMT_UNKNOWN;
031import static org.apache.jena.riot.RDFLanguages.contentTypeToLang;
032import static org.apache.jena.riot.WebContent.contentTypeNTriples;
033import static org.apache.jena.riot.WebContent.contentTypeRDFXML;
034import static org.apache.jena.riot.WebContent.contentTypeResultsBIO;
035import static org.apache.jena.riot.WebContent.contentTypeResultsJSON;
036import static org.apache.jena.riot.WebContent.contentTypeResultsXML;
037import static org.apache.jena.riot.WebContent.contentTypeTextCSV;
038import static org.apache.jena.riot.WebContent.contentTypeTextTSV;
039import static org.apache.jena.riot.WebContent.contentTypeTurtle;
040import static org.apache.jena.riot.WebContent.contentTypeTurtleAlt1;
041import static org.apache.jena.riot.WebContent.contentTypeTurtleAlt2;
042
043import java.io.OutputStream;
044import java.lang.annotation.Annotation;
045import java.lang.reflect.Type;
046
047import javax.ws.rs.Produces;
048import javax.ws.rs.core.MediaType;
049import javax.ws.rs.core.MultivaluedMap;
050import javax.ws.rs.ext.MessageBodyWriter;
051import javax.ws.rs.ext.Provider;
052
053import org.apache.jena.riot.Lang;
054
055import com.hp.hpl.jena.query.ResultSet;
056import com.hp.hpl.jena.rdf.model.Model;
057import com.hp.hpl.jena.sparql.resultset.ResultsFormat;
058
059/**
060 * Stream the results of a SPARQL Query
061 *
062 * @author cbeer
063 */
064@Provider
065@Produces({contentTypeTextTSV, contentTypeTextCSV, contentTypeResultsJSON,
066        contentTypeResultsXML, contentTypeResultsBIO, contentTypeTurtle,
067        contentTypeNTriples, contentTypeRDFXML})
068public class ResultSetStreamingOutput implements MessageBodyWriter<ResultSet> {
069
070
071
072    @Override
073    public boolean isWriteable(final Class<?> type,
074                               final Type genericType,
075                               final Annotation[] annotations,
076                               final MediaType mediaType) {
077        final ResultsFormat resultsFormat = getResultsFormat(mediaType);
078
079        if (resultsFormat == FMT_UNKNOWN) {
080            final Lang format = contentTypeToLang(mediaType.toString());
081
082            return format != null;
083        }
084        return true;
085    }
086
087    @Override
088    public long getSize(final ResultSet resultSet,
089                        final Class<?> type,
090                        final Type genericType,
091                        final Annotation[] annotations,
092                        final MediaType mediaType) {
093        return -1;
094    }
095
096    @Override
097    public void writeTo(final ResultSet resultSet,
098                        final Class<?> type,
099                        final Type genericType,
100                        final Annotation[] annotations,
101                        final MediaType mediaType,
102                        final MultivaluedMap<String, Object> httpHeaders,
103                        final OutputStream entityStream) {
104        final ResultsFormat resultsFormat = getResultsFormat(mediaType);
105
106        if (resultsFormat == FMT_UNKNOWN) {
107            final String format = contentTypeToLang(mediaType.toString()).getName().toUpperCase();
108            final Model model = toModel(resultSet);
109            model.write(entityStream, format);
110        } else {
111            output(entityStream, resultSet, resultsFormat);
112        }
113    }
114
115    /**
116     * Map the HTTP MediaType to a SPARQL ResultsFormat
117     * @param mediaType the media type
118     * @return SPARQL {@link ResultsFormat} for the given {@link MediaType}
119     */
120    public static ResultsFormat getResultsFormat(final MediaType mediaType) {
121        switch (mediaType.toString()) {
122            case contentTypeTextTSV:
123                return FMT_RS_TSV;
124
125            case contentTypeTextCSV:
126                return FMT_RS_CSV;
127
128            case contentTypeResultsJSON:
129                return FMT_RS_JSON;
130
131            case contentTypeResultsXML:
132                return FMT_RS_XML;
133
134            case contentTypeResultsBIO:
135                return FMT_RS_BIO;
136
137            case contentTypeTurtle:
138            case contentTypeTurtleAlt1:
139            case contentTypeTurtleAlt2:
140                return FMT_RDF_TTL;
141
142            case contentTypeNTriples:
143                return FMT_RDF_NT;
144
145            case contentTypeRDFXML:
146                return FMT_RDF_XML;
147            default:
148                return FMT_UNKNOWN;
149        }
150    }
151}