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.domain;
017
018import com.google.common.annotations.VisibleForTesting;
019
020import org.fcrepo.kernel.api.services.ExternalContentService;
021
022import org.springframework.beans.factory.annotation.Autowired;
023
024import javax.ws.rs.WebApplicationException;
025import javax.ws.rs.core.MediaType;
026import javax.ws.rs.core.MultivaluedMap;
027import javax.ws.rs.ext.MessageBodyReader;
028import javax.ws.rs.ext.Provider;
029
030import java.io.IOException;
031import java.io.InputStream;
032import java.lang.annotation.Annotation;
033import java.lang.reflect.Type;
034import java.net.URI;
035import java.net.URISyntaxException;
036import static java.util.Arrays.stream;
037import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
038
039/**
040 * Provide an InputStream either from the POST/PUT body, or by resolving a Content-Location URI
041 * @author cabeer
042 */
043@Provider
044public class ContentLocationMessageBodyReader implements MessageBodyReader<InputStream> {
045
046    /**
047     * The fcrepo node service
048     */
049    @Autowired
050    private ExternalContentService contentService;
051
052    private static final Class<ContentLocation> contentLocationClass = ContentLocation.class;
053
054    @Override
055    public boolean isReadable(final Class<?> type,
056                              final Type genericType,
057                              final Annotation[] annotations,
058                              final MediaType mediaType) {
059        return InputStream.class.isAssignableFrom(type) &&
060                    stream(annotations).map(Annotation::annotationType).anyMatch(contentLocationClass::equals);
061    }
062
063    @Override
064    public InputStream readFrom(final Class<InputStream> type,
065                                final Type genericType,
066                                final Annotation[] annotations,
067                                final MediaType mediaType,
068                                final MultivaluedMap<String, String> httpHeaders,
069                                final InputStream entityStream) throws IOException {
070
071        if (httpHeaders.containsKey("Content-Location")) {
072            final String location = httpHeaders.getFirst("Content-Location");
073
074            try {
075                return contentService.retrieveExternalContent(new URI(location));
076            } catch (final URISyntaxException e) {
077                throw new WebApplicationException(e, BAD_REQUEST);
078            }
079
080        }
081        return entityStream;
082    }
083
084    @VisibleForTesting
085    protected void setContentService(final ExternalContentService externalContentService) {
086        this.contentService = externalContentService;
087    }
088}