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.client;
019
020import static org.fcrepo.client.FedoraHeaderConstants.ACCEPT;
021import static org.fcrepo.client.FedoraHeaderConstants.IF_MODIFIED_SINCE;
022import static org.fcrepo.client.FedoraHeaderConstants.IF_NONE_MATCH;
023import static org.fcrepo.client.FedoraHeaderConstants.PREFER;
024import static org.fcrepo.client.FedoraHeaderConstants.RANGE;
025import static org.fcrepo.client.PreferHeaderConstants.RETURN_REPRESENTATION;
026import static org.fcrepo.client.PreferHeaderConstants.RETURN_MINIMAL;
027import java.net.URI;
028import java.time.Instant;
029import java.util.List;
030import java.util.StringJoiner;
031import java.util.stream.Collectors;
032
033import org.apache.http.client.methods.HttpRequestBase;
034
035/**
036 * Builds a GET request to retrieve the content of a resource from the Fedora HTTP API
037 *
038 * @author bbpennel
039 */
040public class GetBuilder extends RetrieveRequestBuilder {
041
042    /**
043     * Construct a GetBuilder
044     *
045     * @param uri the target
046     * @param client the client for this request
047     */
048    public GetBuilder(final URI uri, final FcrepoClient client) {
049        super(uri, client);
050    }
051
052    @Override
053    protected HttpRequestBase createRequest() {
054        return HttpMethods.GET.createRequest(targetUri);
055    }
056
057    /**
058     * Add the accept header to this request to negotiate the response format.
059     *
060     * @param mediaType media type to set as the accept header. It should be a value from one of the allowed RDF
061     *        source formats supported by Fedora.
062     * @return this builder
063     */
064    public GetBuilder accept(final String mediaType) {
065        if (mediaType != null) {
066            request.setHeader(ACCEPT, mediaType);
067        }
068        return this;
069    }
070
071    /**
072     * Set the byte range of content to retrieve
073     *
074     * @param rangeStart beginning byte index
075     * @param rangeEnd ending byte index
076     * @return this builder
077     */
078    public GetBuilder range(final Long rangeStart, final Long rangeEnd) {
079        if (rangeStart != null || rangeEnd != null) {
080            String range = "bytes=";
081            if (rangeStart != null && rangeStart.longValue() > -1L) {
082                range += rangeStart.toString();
083            }
084            range += "-";
085            if (rangeEnd != null && rangeEnd.longValue() > -1L) {
086                range += rangeEnd.toString();
087            }
088            request.setHeader(RANGE, range);
089        }
090        return this;
091    }
092
093    /**
094     * Set the prefer header for this request to minimal, to indicate that only triples directly related to a resource
095     * should be returned.
096     *
097     * @return this builder
098     */
099    public GetBuilder preferMinimal() {
100        request.setHeader(PREFER, RETURN_MINIMAL);
101        return this;
102    }
103
104    /**
105     * Set the prefer header for this request to representation, to indicate that links to other resources and their
106     * properties should also be included.
107     *
108     * @return this builder
109     */
110    public GetBuilder preferRepresentation() {
111        request.setHeader(PREFER, RETURN_REPRESENTATION);
112        return this;
113    }
114
115    /**
116     * Set the prefer header for this request to representation, to indicate that links to other resources and their
117     * properties should also be included. The set of properties returned can be further specified by providing lists
118     * of LDP defined preferences to omit or include.
119     *
120     * @param includeUris URIs of LDP defined preferences to include
121     * @param omitUris URIs of LDP defined preferences to omit
122     * @return this builder
123     */
124    public GetBuilder preferRepresentation(final List<URI> includeUris, final List<URI> omitUris) {
125        request.setHeader(PREFER, buildPrefer(includeUris, omitUris));
126        return this;
127    }
128
129    private String buildPrefer(final List<URI> includeUris, final List<URI> omitUris) {
130        final StringJoiner preferJoin = new StringJoiner("; ");
131        preferJoin.add(RETURN_REPRESENTATION);
132
133        if (includeUris != null) {
134            final String include = includeUris.stream().map(URI::toString).collect(Collectors.joining(" "));
135            if (include.length() > 0) {
136                preferJoin.add("include=\"" + include + "\"");
137            }
138        }
139
140        if (omitUris != null) {
141            final String omit = omitUris.stream().map(URI::toString).collect(Collectors.joining(" "));
142            if (omit.length() > 0) {
143                preferJoin.add("omit=\"" + omit + "\"");
144            }
145        }
146
147        return preferJoin.toString();
148    }
149
150    /**
151     * Provide an etag for the if-none-match header for this request
152     *
153     * @param etag etag to provide as the if-none-match header
154     * @return this builder
155     */
156    public GetBuilder ifNoneMatch(final String etag) {
157        if (etag != null) {
158            request.setHeader(IF_NONE_MATCH, etag);
159        }
160        return this;
161    }
162
163    /**
164     * Provide a if-last-modified header for this request
165     *
166     * @param lastModified date to provided as the if-modified-since header
167     * @return this builder
168     */
169    public GetBuilder ifModifiedSince(final String lastModified) {
170        if (lastModified != null) {
171            request.setHeader(IF_MODIFIED_SINCE, lastModified);
172        }
173        return this;
174    }
175
176    @Override
177    public GetBuilder disableRedirects() {
178        return (GetBuilder) super.disableRedirects();
179    }
180
181    @Override
182    public GetBuilder wantDigest(final String value) {
183        return (GetBuilder) super.wantDigest(value);
184    }
185
186    @Override
187    public GetBuilder noCache() {
188        return (GetBuilder) super.noCache();
189    }
190
191    @Override
192    public GetBuilder acceptDatetime(final Instant acceptInstant) {
193        return (GetBuilder) super.acceptDatetime(acceptInstant);
194    }
195
196    @Override
197    public GetBuilder acceptDatetime(final String acceptDatetime) {
198        return (GetBuilder) super.acceptDatetime(acceptDatetime);
199    }
200
201    @Override
202    public GetBuilder addHeader(final String name, final String value) {
203        return (GetBuilder) super.addHeader(name, value);
204    }
205
206    @Override
207    public GetBuilder addLinkHeader(final FcrepoLink linkHeader) {
208        return (GetBuilder) super.addLinkHeader(linkHeader);
209    }
210}