1919import static com .google .cloud .storage .MultipartUploadUtility .readStream ;
2020import static com .google .cloud .storage .MultipartUploadUtility .signRequest ;
2121
22- import com .google .cloud .storage .multipartupload .model .CompleteMultipartRequest ;
23- import com .google .cloud .storage .multipartupload .model .CompleteMultipartResponse ;
22+ import com .google .api .client .http .AbstractHttpContent ;
23+ import com .google .api .client .http .HttpRequestFactory ;
24+ import com .google .api .client .util .ObjectParser ;
25+ import com .google .api .gax .grpc .GrpcStatusCode ;
26+ import com .google .api .gax .rpc .UnimplementedException ;
27+ import com .google .cloud .storage .Retrying .Retrier ;
28+ import com .google .cloud .storage .multipartupload .model .AbortMultipartUploadRequest ;
29+ import com .google .cloud .storage .multipartupload .model .AbortMultipartUploadResponse ;
30+ import com .google .cloud .storage .multipartupload .model .CompleteMultipartUploadRequest ;
31+ import com .google .cloud .storage .multipartupload .model .CompleteMultipartUploadResponse ;
2432import com .google .cloud .storage .multipartupload .model .CompletedPart ;
2533import com .google .cloud .storage .multipartupload .model .CreateMultipartUploadRequest ;
2634import com .google .cloud .storage .multipartupload .model .CreateMultipartUploadResponse ;
2735import com .google .cloud .storage .multipartupload .model .UploadPartRequest ;
2836import com .google .cloud .storage .multipartupload .model .UploadPartResponse ;
37+ import io .grpc .Status ;
2938import java .io .IOException ;
39+ import java .io .InputStream ;
3040import java .io .OutputStream ;
41+ import java .io .Reader ;
42+ import java .lang .reflect .Type ;
3143import java .net .HttpURLConnection ;
44+ import java .net .URI ;
3245import java .net .URL ;
46+ import java .nio .charset .Charset ;
3347import java .nio .charset .StandardCharsets ;
3448import java .security .MessageDigest ;
3549import java .security .NoSuchAlgorithmException ;
3650import java .util .Base64 ;
3751
38- public class MultipartUploadImpl implements MultipartUpload {
39-
40- private static final String BUCKET_NAME = "shreyassinha" ;
41- private static final String OBJECT_NAME = "5mb" ; // The name for the object in GCS
42- private static final String FILE_PATH = "5mb-examplefile-com.txt" ; // The local file to upload
52+ public class MultipartUploadClientImpl extends MultipartUploadClient {
4353
4454 // Add HMAC keys from GCS Settings > Interoperability
4555
4656 // --- End Configuration ---
4757 private static final String GCS_ENDPOINT = "https://storage.googleapis.com" ;
4858
59+ public MultipartUploadClientImpl (URI uri , HttpRequestFactory requestFactory , Retrier retrier ) {
60+ }
61+
4962 public CreateMultipartUploadResponse createMultipartUpload (CreateMultipartUploadRequest request )
5063 throws IOException {
51- String resourcePath = "/" + request .getBucket () + "/" + request .getKey ();
64+ String resourcePath = "/" + request .bucket () + "/" + request .key ();
5265 String uri = GCS_ENDPOINT + resourcePath + "?uploads" ;
5366 String date = getRfc1123Date ();
5467 String contentType = "application/x-www-form-urlencoded" ;
@@ -74,13 +87,13 @@ public CreateMultipartUploadResponse createMultipartUpload(CreateMultipartUpload
7487 int start = responseBody .indexOf (uploadIdTag ) + uploadIdTag .length ();
7588 int end = responseBody .indexOf ("</UploadId>" );
7689 String uploadId = responseBody .substring (start , end );
77- return CreateMultipartUploadResponse .newBuilder ().setUploadId (uploadId ).build ();
90+ return CreateMultipartUploadResponse .builder ().uploadId (uploadId ).build ();
7891 }
7992
8093 public UploadPartResponse uploadPart (UploadPartRequest request , RequestBody requestBody )
8194 throws IOException {
82- String resourcePath = "/" + request .getBucket () + "/" + request .getKey ();
83- String queryString = "?partNumber=" + request .getPartNumber () + "&uploadId=" + request .getUploadId ();
95+ String resourcePath = "/" + request .bucket () + "/" + request .key ();
96+ String queryString = "?partNumber=" + request .partNumber () + "&uploadId=" + request .uploadId ();
8497 String uri = GCS_ENDPOINT + resourcePath + queryString ;
8598 String date = getRfc1123Date ();
8699 String contentType = "application/octet-stream" ;
@@ -94,32 +107,32 @@ public UploadPartResponse uploadPart(UploadPartRequest request, RequestBody requ
94107 connection .setRequestProperty ("Date" , date );
95108 connection .setRequestProperty ("Authorization" , authHeader );
96109 connection .setRequestProperty ("Content-Type" , contentType );
97- connection .setFixedLengthStreamingMode (requestBody .getPartDate ().length );
110+ connection .setFixedLengthStreamingMode (requestBody .getPartData ().length );
98111 connection .setDoOutput (true );
99112
100113 try (OutputStream os = connection .getOutputStream ()) {
101- os .write (requestBody .getPartDate ());
114+ os .write (requestBody .getPartData ());
102115 }
103116
104117 if (connection .getResponseCode () != 200 ) {
105118 String error = readStream (connection .getErrorStream ());
106- throw new RuntimeException ("Failed to upload part " + request .getPartNumber () + ": " + connection .getResponseCode () + " " + error );
119+ throw new RuntimeException ("Failed to upload part " + request .partNumber () + ": " + connection .getResponseCode () + " " + error );
107120 }
108121 String eTag = connection .getHeaderField ("ETag" );
109- return UploadPartResponse .newBuilder ().setEtag (eTag ).build ();
122+ return UploadPartResponse .builder ().etag (eTag ).build ();
110123 }
111124
112- public CompleteMultipartResponse completeMultipartUpload (CompleteMultipartRequest request )
125+ public CompleteMultipartUploadResponse completeMultipartUpload (CompleteMultipartUploadRequest request )
113126 throws NoSuchAlgorithmException , IOException {
114- String resourcePath = "/" + request .getBucket () + "/" + request .getKey ();
115- String queryString = "?uploadId=" + request .getUploadId ();
127+ String resourcePath = "/" + request .bucket () + "/" + request .key ();
128+ String queryString = "?uploadId=" + request .uploadId ();
116129 String uri = GCS_ENDPOINT + resourcePath + queryString ;
117130
118131 StringBuilder xmlBodyBuilder = new StringBuilder ("<CompleteMultipartUpload>\n " );
119- for (CompletedPart part : request .getCompletedMultipartUpload ().getCompletedPartList ()) {
132+ for (CompletedPart part : request .completedMultipartUpload ().completedPartList ()) {
120133 xmlBodyBuilder .append (" <Part>\n " );
121- xmlBodyBuilder .append (" <PartNumber>" ).append (part .getPartNumber ()).append ("</PartNumber>\n " );
122- xmlBodyBuilder .append (" <ETag>" ).append (part .getEtag ()).append ("</ETag>\n " );
134+ xmlBodyBuilder .append (" <PartNumber>" ).append (part .partNumber ()).append ("</PartNumber>\n " );
135+ xmlBodyBuilder .append (" <ETag>" ).append (part .etag ()).append ("</ETag>\n " );
123136 xmlBodyBuilder .append (" </Part>\n " );
124137 }
125138 xmlBodyBuilder .append ("</CompleteMultipartUpload>" );
@@ -153,4 +166,89 @@ public CompleteMultipartResponse completeMultipartUpload(CompleteMultipartReques
153166 }
154167 return null ;
155168 }
169+
170+ @ Override
171+ public AbortMultipartUploadResponse abortMultipartUpload (AbortMultipartUploadRequest request ) throws IOException {
172+ String resourcePath = "/" + request .bucket () + "/" + request .key ();
173+ String queryString = "?uploadId=" + request .uploadId ();
174+ String uri = GCS_ENDPOINT + resourcePath + queryString ;
175+ String date = getRfc1123Date ();
176+
177+ // GCS Signature Rule #4: The query string IS NOT included for the DELETE abort request.
178+ String signature = signRequest ("DELETE" , "" , "" , date , resourcePath , GOOGLE_SECRET_KEY );
179+
180+ String authHeader = "GOOG1 " + GOOGLE_ACCESS_KEY + ":" + signature ;
181+
182+ HttpURLConnection connection = (HttpURLConnection ) new URL (uri ).openConnection ();
183+ connection .setRequestMethod ("DELETE" );
184+ connection .setRequestProperty ("Date" , date );
185+ connection .setRequestProperty ("Authorization" , authHeader );
186+
187+ if (connection .getResponseCode () != 204 ) {
188+ String error = readStream (connection .getErrorStream ());
189+ throw new RuntimeException ("Failed to abort upload: " + connection .getResponseCode () + " " + error );
190+ }
191+ return new AbortMultipartUploadResponse ();
192+ }
193+
194+ private static final class Utf8StringRequestContent extends AbstractHttpContent {
195+
196+ private final byte [] xml ;
197+
198+ private Utf8StringRequestContent (byte [] xml ) {
199+ // https://www.ietf.org/rfc/rfc2376.txt#:~:text=6.1%20text/xml%20with%20UTF%2D8%20Charset
200+ super ("text/xml;charset=utf-8" );
201+ this .xml = xml ;
202+ }
203+
204+ @ Override
205+ public long getLength () throws IOException {
206+ return super .getLength ();
207+ }
208+
209+ @ Override
210+ public void writeTo (OutputStream out ) throws IOException {
211+ out .write (xml );
212+ }
213+
214+ public static Utf8StringRequestContent of (String xml ) {
215+ return new Utf8StringRequestContent (xml .getBytes (StandardCharsets .UTF_8 ));
216+ }
217+ }
218+
219+ private static class XmlObjectParser implements ObjectParser {
220+
221+ @ Override
222+ public <T > T parseAndClose (InputStream in , Charset charset , Class <T > dataClass )
223+ throws IOException {
224+ try (InputStream is = in ) {
225+ return todo ();
226+ }
227+ }
228+
229+ @ Override
230+ public Object parseAndClose (InputStream in , Charset charset , Type dataType ) throws IOException {
231+ try (InputStream is = in ) {
232+ return todo ();
233+ }
234+ }
235+
236+ @ Override
237+ public <T > T parseAndClose (Reader reader , Class <T > dataClass ) throws IOException {
238+ try (Reader r = reader ) {
239+ return todo ();
240+ }
241+ }
242+
243+ @ Override
244+ public Object parseAndClose (Reader reader , Type dataType ) throws IOException {
245+ try (Reader r = reader ) {
246+ return todo ();
247+ }
248+ }
249+
250+ private static <T > T todo () {
251+ throw new UnimplementedException ("todo" , null , GrpcStatusCode .of (Status .Code .UNIMPLEMENTED ), false );
252+ }
253+ }
156254}
0 commit comments