001/*
002 * Copyright 2015 DuraSpace, Inc.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.fcrepo.http.commons.responses;
017
018import static javax.ws.rs.core.MediaType.APPLICATION_XHTML_XML_TYPE;
019import static javax.ws.rs.core.MediaType.APPLICATION_XML;
020import static javax.ws.rs.core.MediaType.TEXT_HTML_TYPE;
021import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
022import static org.fcrepo.http.commons.domain.RDFMediaType.JSON_LD;
023import static org.fcrepo.http.commons.domain.RDFMediaType.N3;
024import static org.fcrepo.http.commons.domain.RDFMediaType.N3_ALT2;
025import static org.fcrepo.http.commons.domain.RDFMediaType.NTRIPLES;
026import static org.fcrepo.http.commons.domain.RDFMediaType.RDF_XML;
027import static org.fcrepo.http.commons.domain.RDFMediaType.TURTLE;
028import static org.fcrepo.http.commons.domain.RDFMediaType.TURTLE_X;
029import static org.openrdf.rio.RDFFormat.NO_CONTEXTS;
030import static org.openrdf.rio.RDFFormat.NO_NAMESPACES;
031import static org.slf4j.LoggerFactory.getLogger;
032
033import java.io.OutputStream;
034import java.lang.annotation.Annotation;
035import java.lang.reflect.Type;
036import java.nio.charset.Charset;
037
038import javax.annotation.PostConstruct;
039import javax.ws.rs.Produces;
040import javax.ws.rs.core.MediaType;
041import javax.ws.rs.core.MultivaluedMap;
042import javax.ws.rs.ext.MessageBodyWriter;
043import javax.ws.rs.ext.Provider;
044
045import org.openrdf.rio.RDFFormat;
046import org.openrdf.rio.RDFWriterRegistry;
047import org.openrdf.rio.ntriples.NTriplesWriterFactory;
048import org.slf4j.Logger;
049
050/**
051 * Provides serialization for streaming RDF results.
052 *
053 * @author ajs6f
054 * @since Nov 19, 2013
055 */
056@Provider
057@Produces({TURTLE, N3, N3_ALT2, RDF_XML, NTRIPLES, APPLICATION_XML, TEXT_PLAIN, TURTLE_X, JSON_LD})
058public class RdfStreamProvider implements MessageBodyWriter<RdfNamespacedStream> {
059
060    private static final Logger LOGGER = getLogger(RdfStreamProvider.class);
061
062    @Override
063    public boolean isWriteable(final Class<?> type, final Type genericType,
064            final Annotation[] annotations, final MediaType mediaType) {
065        LOGGER.debug(
066                "Checking to see if we can serialize type: {} to mimeType: {}",
067                type.getName(), mediaType.toString());
068        if (!RdfNamespacedStream.class.isAssignableFrom(type)) {
069            return false;
070        }
071        if (mediaType.equals(TEXT_HTML_TYPE)
072                || mediaType.equals(APPLICATION_XHTML_XML_TYPE)
073                || (mediaType.getType().equals("application") && mediaType
074                        .getSubtype().equals("html"))) {
075            LOGGER.debug("Was asked for an HTML mimeType, returning false.");
076            return false;
077        }
078        LOGGER.debug("Assuming that this is an attempt to retrieve RDF, returning true.");
079        return true;
080    }
081
082    @Override
083    public long getSize(final RdfNamespacedStream t, final Class<?> type,
084            final Type genericType, final Annotation[] annotations,
085            final MediaType mediaType) {
086        // We do not know how long the stream is
087        return -1;
088    }
089
090    @Override
091    public void writeTo(final RdfNamespacedStream nsStream, final Class<?> type,
092        final Type genericType, final Annotation[] annotations,
093        final MediaType mediaType,
094        final MultivaluedMap<String, Object> httpHeaders,
095        final OutputStream entityStream) {
096
097        LOGGER.debug("Serializing an RdfStream to mimeType: {}", mediaType);
098        final RdfStreamStreamingOutput streamOutput = new RdfStreamStreamingOutput(nsStream.stream,
099                nsStream.namespaces, mediaType);
100        streamOutput.write(entityStream);
101    }
102
103    /**
104     * Add the correct mimeType for n-triples.
105     */
106    @PostConstruct
107    public void registerMimeTypes() {
108        RDFWriterRegistry.getInstance().add(new NTriplesWithCorrectMimeType());
109    }
110
111    /**
112     * OpenRDF uses the wrong mimeType for n-triples, so we offer the correct
113     * one as well.
114     *
115     * @author ajs6f
116     * @since Nov 20, 2013
117     */
118    public static class NTriplesWithCorrectMimeType extends
119        NTriplesWriterFactory {
120
121        private static final RDFFormat NTRIPLESWITHCORRECTMIMETYPE =
122            new RDFFormat("N-Triples-with-correct-mimeType",
123                    NTRIPLES, Charset.forName("US-ASCII"), "nt",
124                    NO_NAMESPACES, NO_CONTEXTS);
125
126        @Override
127        public RDFFormat getRDFFormat() {
128            return NTRIPLESWITHCORRECTMIMETYPE;
129        }
130    }
131
132}