001/*
002 * The contents of this file are subject to the license and copyright
003 * detailed in the LICENSE and NOTICE files at the root of the source
004 * tree.
005 */
006package org.fcrepo.camel.ldpath;
007
008import static org.slf4j.LoggerFactory.getLogger;
009
010import org.apache.marmotta.ldclient.api.endpoint.Endpoint;
011import org.apache.marmotta.ldclient.provider.rdf.LinkedDataProvider;
012import org.fcrepo.client.FcrepoHttpClientBuilder;
013import org.fcrepo.client.FcrepoLink;
014
015import java.io.IOException;
016import java.io.UncheckedIOException;
017import java.util.Collections;
018import java.util.List;
019import java.util.Objects;
020import java.util.Optional;
021
022import org.apache.http.client.HttpClient;
023import org.apache.http.client.methods.HttpHead;
024import org.apache.http.Header;
025import org.apache.http.HttpResponse;
026import org.slf4j.Logger;
027
028
029/**
030 * An extension Linked Data provider to support Binary nodes in Fedora.
031 *
032 * @author Mohamed Mohideen Abdul Rasheed
033 */
034public class FedoraProvider extends LinkedDataProvider {
035
036    private static final Logger LOGGER = getLogger(FedoraProvider.class);
037
038    public static final String PROVIDER_NAME = "Fedora";
039
040    private final HttpClient httpClient;
041
042    private final String NON_RDF_SOURCE_URI = "http://www.w3.org/ns/ldp#NonRDFSource";
043
044    /**
045     * FedoraProvider
046     * @param builder FcrepoHttpClientBuilder for building HttpClient
047     */
048    public FedoraProvider(final FcrepoHttpClientBuilder builder) {
049        Objects.requireNonNull(builder);
050        httpClient = builder.build();
051    }
052
053    /*
054     * Return the name of this data provider. To be used e.g. in the configuration and in log messages.
055     */
056    @Override
057    public String getName() {
058        return PROVIDER_NAME;
059    }
060
061    /*
062     * Return the describedBy URL for NonRdfSource resources. Return the resourseUri otherwise.
063     */
064    @Override
065    public List<String> buildRequestUrl(final String resourceUri, final Endpoint endpoint) {
066        LOGGER.debug("Processing: " + resourceUri);
067        Objects.requireNonNull(resourceUri);
068        try {
069            final Optional<String> nonRdfSourceDescUri =
070                    getNonRDFSourceDescribedByUri(resourceUri);
071            if ( nonRdfSourceDescUri.isPresent() ) {
072                return Collections.singletonList(nonRdfSourceDescUri.get());
073            }
074        } catch (final IOException ex) {
075            throw new UncheckedIOException(ex);
076        }
077        return Collections.singletonList(resourceUri);
078    }
079
080    /*
081    * Get the describedBy Uri if the resource has a NON_RDF_SOURCE_URI link header.
082    */
083    private Optional<String> getNonRDFSourceDescribedByUri(final String resourceUri) throws IOException {
084        Optional<String> nonRdfSourceDescUri = Optional.empty();
085        final Header[] links = getLinkHeaders(resourceUri);
086        if ( links != null ) {
087            String descriptionUri = null;
088            boolean isNonRDFSource = false;
089            for ( final Header h : links ) {
090                final FcrepoLink link = new FcrepoLink(h.getValue());
091                if ( link.getRel().equals("describedby") ) {
092                    descriptionUri = link.getUri().toString();
093                } else if ( link.getUri().toString().contains(NON_RDF_SOURCE_URI)) {
094                    isNonRDFSource = true;
095                }
096            }
097            LOGGER.debug("isNonRDFSource: " + isNonRDFSource);
098            if (isNonRDFSource && descriptionUri != null) {
099                nonRdfSourceDescUri = Optional.of(descriptionUri);
100            }
101        }
102        return nonRdfSourceDescUri;
103    }
104
105    /*
106    * Get the link headers for the resource at the given Uri.
107    */
108    private Header[] getLinkHeaders(final String resourceUri) throws IOException {
109        final HttpHead request = new HttpHead(resourceUri);
110        final HttpResponse response = httpClient.execute(request);
111        LOGGER.debug("Got: " + response.getStatusLine().getStatusCode() + " for HEAD " + resourceUri);
112        return response.getHeaders("Link");
113    }
114
115}