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