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