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.CONTENT_TYPE; 021import static org.fcrepo.client.FedoraHeaderConstants.DIGEST; 022import static org.fcrepo.client.FedoraHeaderConstants.IF_MATCH; 023import static org.fcrepo.client.FedoraHeaderConstants.IF_STATE_TOKEN; 024import static org.fcrepo.client.FedoraHeaderConstants.IF_UNMODIFIED_SINCE; 025import static org.fcrepo.client.FedoraHeaderConstants.LINK; 026import static org.fcrepo.client.LinkHeaderConstants.ACL_REL; 027import static org.fcrepo.client.LinkHeaderConstants.TYPE_REL; 028import static org.fcrepo.client.LinkHeaderConstants.EXTERNAL_CONTENT_HANDLING; 029import static org.fcrepo.client.LinkHeaderConstants.EXTERNAL_CONTENT_REL; 030 031import java.io.File; 032import java.io.FileInputStream; 033import java.io.IOException; 034import java.io.InputStream; 035import java.net.URI; 036import java.util.StringJoiner; 037 038import org.apache.commons.lang3.StringUtils; 039import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; 040import org.apache.http.entity.InputStreamEntity; 041import org.fcrepo.client.FcrepoLink.Builder; 042 043/** 044 * Request builder which includes a body component 045 * 046 * @author bbpennel 047 */ 048public abstract class BodyRequestBuilder extends 049 RequestBuilder { 050 051 private StringJoiner digestJoiner; 052 053 /** 054 * Instantiate builder 055 * 056 * @param uri uri request will be issued to 057 * @param client the client 058 */ 059 protected BodyRequestBuilder(final URI uri, final FcrepoClient client) { 060 super(uri, client); 061 } 062 063 /** 064 * Add a body to this request from a stream, with application/octet-stream as its content type 065 * 066 * @param stream InputStream of the content to be sent to the server 067 * @return this builder 068 */ 069 protected BodyRequestBuilder body(final InputStream stream) { 070 return body(stream, null); 071 } 072 073 /** 074 * Add a body to this request as a stream with the given content type 075 * 076 * @param stream InputStream of the content to be sent to the server 077 * @param contentType the Content-Type of the body 078 * @return this builder 079 */ 080 protected BodyRequestBuilder body(final InputStream stream, final String contentType) { 081 if (stream != null) { 082 String type = contentType; 083 if (type == null) { 084 type = "application/octet-stream"; 085 } 086 087 ((HttpEntityEnclosingRequestBase) request).setEntity(new InputStreamEntity(stream)); 088 request.addHeader(CONTENT_TYPE, type); 089 } 090 091 return this; 092 } 093 094 /** 095 * Add the given file as the body for this request with the provided content type 096 * 097 * @param file File containing the content to be sent to the server 098 * @param contentType the Content-Type of the body 099 * @return this builder 100 * @throws IOException when unable to stream the body file 101 */ 102 protected BodyRequestBuilder body(final File file, final String contentType) throws IOException { 103 return body(new FileInputStream(file), contentType); 104 } 105 106 /** 107 * Add the given URI to the request as the location a Non-RDF Source binary should use for external content. The 108 * handling parameter must be supplied, and informs the server of how to process the request. 109 * 110 * @param contentURI URI of the external content. 111 * @param contentType Mimetype to supply for the external content. 112 * @param handling Name of the handling method, used by the server to determine how to process the external 113 * content URI. Standard values can be found in {@link ExternalContentHandling}. 114 * @return this builder 115 */ 116 protected BodyRequestBuilder externalContent(final URI contentURI, final String contentType, 117 final String handling) { 118 final Builder linkBuilder = FcrepoLink.fromUri(contentURI) 119 .rel(EXTERNAL_CONTENT_REL) 120 .param(EXTERNAL_CONTENT_HANDLING, handling); 121 122 if (StringUtils.isNotBlank(contentType)) { 123 linkBuilder.type(contentType); 124 } 125 126 request.addHeader(LINK, linkBuilder.build().toString()); 127 return this; 128 } 129 130 /** 131 * Provide a SHA-1 checksum for the body of this request. 132 * 133 * @deprecated Use {@link #digestSha1(java.lang.String)}. 134 * @param digest sha-1 checksum to provide as the digest for the request body 135 * @return this builder 136 */ 137 @Deprecated 138 protected BodyRequestBuilder digest(final String digest) { 139 return digestSha1(digest); 140 } 141 142 /** 143 * Provide a checksum for the body of this request 144 * 145 * @param digest checksum to provide as the digest for the request body 146 * @param alg abbreviated algorithm identifier for the type of checksum being 147 * added (for example, sha, md5, etc) 148 * @return this builder 149 */ 150 protected BodyRequestBuilder digest(final String digest, final String alg) { 151 if (digest != null) { 152 if (digestJoiner == null) { 153 digestJoiner = new StringJoiner(", "); 154 } 155 digestJoiner.add(alg + "=" + digest); 156 request.setHeader(DIGEST, digestJoiner.toString()); 157 } 158 return this; 159 } 160 161 /** 162 * Provide a SHA-1 checksum for the body of this request. 163 * 164 * @param digest sha-1 checksum to provide as the digest for the request body 165 * @return this builder 166 */ 167 protected BodyRequestBuilder digestSha1(final String digest) { 168 return digest(digest, "sha"); 169 } 170 171 /** 172 * Provide a MD5 checksum for the body of this request 173 * 174 * @param digest MD5 checksum to provide as the digest for the request body 175 * @return this builder 176 */ 177 protected BodyRequestBuilder digestMd5(final String digest) { 178 return digest(digest, "md5"); 179 } 180 181 /** 182 * Provide a SHA-256 checksum for the body of this request 183 * 184 * @param digest sha-256 checksum to provide as the digest for the request body 185 * @return this builder 186 */ 187 protected BodyRequestBuilder digestSha256(final String digest) { 188 return digest(digest, "sha256"); 189 } 190 191 /** 192 * Add an interaction model to the request 193 * 194 * @param interactionModelUri URI of the interaction model 195 * @return this builder 196 */ 197 protected BodyRequestBuilder addInteractionModel(final String interactionModelUri) { 198 if (interactionModelUri != null) { 199 final FcrepoLink link = FcrepoLink.fromUri(interactionModelUri) 200 .rel(TYPE_REL) 201 .build(); 202 request.addHeader(LINK, link.toString()); 203 } 204 return this; 205 } 206 207 /** 208 * Provide a if-unmodified-since header for this request 209 * 210 * @param modified date to provide as the if-unmodified-since header 211 * @return this builder 212 */ 213 public BodyRequestBuilder ifUnmodifiedSince(final String modified) { 214 if (modified != null) { 215 request.setHeader(IF_UNMODIFIED_SINCE, modified); 216 } 217 return this; 218 } 219 220 /** 221 * Provide an etag for the if-match header for this request 222 * 223 * @param etag etag to provide as the if-match header 224 * @return this builder 225 */ 226 protected BodyRequestBuilder ifMatch(final String etag) { 227 if (etag != null) { 228 request.setHeader(IF_MATCH, etag); 229 } 230 return this; 231 } 232 233 /** 234 * Provide the URI to an ACL for this request 235 * 236 * @param aclUri URI to the ACL 237 * @return this builder 238 */ 239 protected BodyRequestBuilder linkAcl(final String aclUri) { 240 if (aclUri != null) { 241 final FcrepoLink link = FcrepoLink.fromUri(aclUri) 242 .rel(ACL_REL) 243 .build(); 244 request.addHeader(LINK, link.toString()); 245 } 246 return this; 247 } 248 249 /** 250 * Provide a value for the if-state-token header for this request. 251 * 252 * @param token state token value 253 * @return this builder 254 */ 255 protected BodyRequestBuilder ifStateToken(final String token) { 256 if (token != null) { 257 request.setHeader(IF_STATE_TOKEN, token); 258 } 259 return this; 260 } 261}