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;
019import com.google.common.base.Predicate;
020import com.google.common.collect.Iterables;
021import org.fcrepo.kernel.services.ExternalContentService;
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;
029import java.io.IOException;
030import java.io.InputStream;
031import java.lang.annotation.Annotation;
032import java.lang.reflect.Type;
033import java.net.URI;
034import java.net.URISyntaxException;
035import java.util.Arrays;
036
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    private static final Predicate<Annotation> HAS_CONTENT_LOCATION_PREDICATE = new Predicate<Annotation>() {
047        @Override
048        public boolean apply(final Annotation annotation) {
049            return annotation.annotationType().equals(ContentLocation.class);
050        }
051    };
052    /**
053     * The fcrepo node service
054     */
055    @Autowired
056    private ExternalContentService contentService;
057
058    @Override
059    public boolean isReadable(final Class<?> type,
060                              final Type genericType,
061                              final Annotation[] annotations,
062                              final MediaType mediaType) {
063        return InputStream.class.isAssignableFrom(type) &&
064                   Iterables.any(Arrays.asList(annotations), HAS_CONTENT_LOCATION_PREDICATE);
065    }
066
067    @Override
068    public InputStream readFrom(final Class<InputStream> type,
069                                final Type genericType,
070                                final Annotation[] annotations,
071                                final MediaType mediaType,
072                                final MultivaluedMap<String, String> httpHeaders,
073                                final InputStream entityStream) throws IOException {
074
075        if (httpHeaders.containsKey("Content-Location")) {
076            final String location = httpHeaders.getFirst("Content-Location");
077
078            try {
079                return contentService.retrieveExternalContent(new URI(location));
080            } catch (URISyntaxException e) {
081                throw new WebApplicationException(e, BAD_REQUEST);
082            }
083
084        }
085        return entityStream;
086    }
087
088    @VisibleForTesting
089    protected void setContentService(final ExternalContentService externalContentService) {
090        this.contentService = externalContentService;
091    }
092}