2828import com .google .cloud .storage .StorageException ;
2929import com .google .cloud .storage .StorageOptions ;
3030import com .google .common .annotations .VisibleForTesting ;
31+ import io .cdap .cdap .api .exception .ErrorCategory ;
32+ import io .cdap .cdap .api .exception .ErrorType ;
33+ import io .cdap .cdap .api .exception .ErrorUtils ;
3134import io .cdap .plugin .gcp .common .GCPConnectorConfig ;
35+ import io .cdap .plugin .gcp .common .GCPErrorDetailsProviderUtil ;
3236import io .cdap .plugin .gcp .common .GCPUtils ;
3337import org .slf4j .Logger ;
3438import org .slf4j .LoggerFactory ;
@@ -68,7 +72,14 @@ public Blob pickABlob(String path) {
6872 return null ;
6973 }
7074 GCSPath gcsPath = GCSPath .from (path );
71- Page <Blob > blobPage = storage .list (gcsPath .getBucket (), Storage .BlobListOption .prefix (gcsPath .getName ()));
75+ Page <Blob > blobPage ;
76+ try {
77+ blobPage = storage .list (gcsPath .getBucket (), Storage .BlobListOption .prefix (gcsPath .getName ()));
78+ } catch (Exception e ) {
79+ String errorReason = String .format ("Unable to list objects in bucket %s." , gcsPath .getBucket ());
80+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
81+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
82+ }
7283 Iterator <Blob > iterator = blobPage .getValues ().iterator ();
7384 while (iterator .hasNext ()) {
7485 Blob blob = iterator .next ();
@@ -89,7 +100,13 @@ public void setMetaData(Blob blob, Map<String, String> metaData) {
89100 if (blob == null || metaData == null || metaData .isEmpty ()) {
90101 return ;
91102 }
92- storage .update (BlobInfo .newBuilder (blob .getBlobId ()).setMetadata (metaData ).build ());
103+ try {
104+ storage .update (BlobInfo .newBuilder (blob .getBlobId ()).setMetadata (metaData ).build ());
105+ } catch (Exception e ) {
106+ String errorReason = String .format ("Unable to update metadata for blob %s." , blob .getName ());
107+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
108+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
109+ }
93110 }
94111
95112 /**
@@ -102,7 +119,14 @@ public void mapMetaDataForAllBlobs(String path, Consumer<Map<String, String>> fu
102119 return ;
103120 }
104121 GCSPath gcsPath = GCSPath .from (path );
105- Page <Blob > blobPage = storage .list (gcsPath .getBucket (), Storage .BlobListOption .prefix (gcsPath .getName ()));
122+ Page <Blob > blobPage ;
123+ try {
124+ blobPage = storage .list (gcsPath .getBucket (), Storage .BlobListOption .prefix (gcsPath .getName ()));
125+ } catch (Exception e ) {
126+ String errorReason = String .format ("Unable to list objects in bucket %s." , gcsPath .getBucket ());
127+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
128+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
129+ }
106130 Iterator <Blob > blobIterator = blobPage .iterateAll ().iterator ();
107131 while (blobIterator .hasNext ()) {
108132 Blob blob = blobIterator .next ();
@@ -132,9 +156,11 @@ public void createBucketIfNotExists(GCSPath path, @Nullable String location, @Nu
132156 LOG .warn ("Getting 409 Conflict: {} Bucket at destination path {} may already exist." ,
133157 e .getMessage (), path .getUri ());
134158 } else {
135- throw new RuntimeException (
159+ String errorReason =
136160 String .format ("Unable to create bucket %s. Ensure you entered the correct bucket path and " +
137- "have permissions for it." , path .getBucket ()), e );
161+ "have permissions for it." , path .getBucket ());
162+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
163+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
138164 }
139165 }
140166 }
@@ -173,9 +199,16 @@ public void move(GCSPath sourcePath, GCSPath destPath, boolean recursive, boolea
173199 * Get all the matching wildcard paths given the regex input.
174200 */
175201 public List <GCSPath > getMatchedPaths (GCSPath sourcePath , boolean recursive , Pattern wildcardRegex ) {
176- Page <Blob > blobPage = storage .list (sourcePath .getBucket (), Storage .BlobListOption .prefix (
202+ Page <Blob > blobPage ;
203+ try {
204+ blobPage = storage .list (sourcePath .getBucket (), Storage .BlobListOption .prefix (
177205 getWildcardPathPrefix (sourcePath , wildcardRegex )
178- ));
206+ ));
207+ } catch (Exception e ) {
208+ String errorReason = String .format ("Unable to list objects in bucket %s." , sourcePath .getBucket ());
209+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
210+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
211+ }
179212 List <String > blobPageNames = new ArrayList <>();
180213 blobPage .getValues ().forEach (blob -> blobPageNames .add (blob .getName ()));
181214 return getFilterMatchedPaths (sourcePath , blobPageNames , recursive );
@@ -212,58 +245,84 @@ static List<GCSPath> getFilterMatchedPaths(GCSPath sourcePath, List<String> blob
212245 private void pairTraverse (GCSPath sourcePath , GCSPath destPath , boolean recursive , boolean overwrite ,
213246 Consumer <BlobPair > consumer ) {
214247
215- Bucket sourceBucket = null ;
248+ Bucket sourceBucket ;
216249 try {
217250 sourceBucket = storage .get (sourcePath .getBucket ());
218- } catch (StorageException e ) {
251+ } catch (Exception e ) {
219252 // Add more descriptive error message
220- throw new RuntimeException (
221- String . format ( "Unable to access source bucket %s. " , sourcePath . getBucket ())
222- + "Ensure you entered the correct bucket path." , e );
253+ String errorReason = String . format ( "Unable to access GCS bucket '%s'" , sourcePath . getBucket ());
254+ throw GCPErrorDetailsProviderUtil . getHttpResponseExceptionDetailsFromChain ( e , errorReason , ErrorType . UNKNOWN ,
255+ true , GCPUtils . GCS_SUPPORTED_DOC_URL );
223256 }
224257 if (sourceBucket == null ) {
225- throw new IllegalArgumentException (
226- String .format ("Source bucket '%s' does not exist." , sourcePath .getBucket ()));
258+ String errorReason = String .format ("Source bucket '%s' does not exist." , sourcePath .getBucket ());
259+ throw ErrorUtils .getProgramFailureException (new ErrorCategory (ErrorCategory .ErrorCategoryEnum .PLUGIN ),
260+ errorReason , errorReason , ErrorType .USER , true , null );
227261 }
228- Bucket destBucket = null ;
262+ Bucket destBucket ;
229263 try {
230264 destBucket = storage .get (destPath .getBucket ());
231- } catch (StorageException e ) {
265+ } catch (Exception e ) {
232266 // Add more descriptive error message
233- throw new RuntimeException (
234- String . format ( "Unable to access destination bucket %s. " , destPath . getBucket ())
235- + "Ensure you entered the correct bucket path." , e );
267+ String errorReason = String . format ( "Unable to access GCS bucket '%s'" , destPath . getBucket ());
268+ throw GCPErrorDetailsProviderUtil . getHttpResponseExceptionDetailsFromChain ( e , errorReason , ErrorType . UNKNOWN ,
269+ true , GCPUtils . GCS_SUPPORTED_DOC_URL );
236270 }
237271 if (destBucket == null ) {
238- throw new IllegalArgumentException (
239- String .format ("Destination bucket '%s' does not exist. Please create it first." , destPath .getBucket ()));
272+ String errorReason =
273+ String .format ("Destination bucket '%s' does not exist. Please create it first." , destPath .getBucket ());
274+ throw ErrorUtils .getProgramFailureException (new ErrorCategory (ErrorCategory .ErrorCategoryEnum .PLUGIN ),
275+ errorReason , errorReason , ErrorType .USER , true , null );
240276 }
241277
242278 boolean destinationBaseExists ;
243279 String baseDestName = destPath .getName ();
244- if (destPath .isBucket () || storage .get (BlobId .of (destPath .getBucket (), baseDestName )) != null ) {
280+ boolean destinationBlobExists ;
281+ try {
282+ destinationBlobExists = destPath .isBucket () || storage .get (BlobId .of (destPath .getBucket (), baseDestName )) != null ;
283+ } catch (Exception e ) {
284+ String errorReason = String .format ("Unable to access GCS bucket '%s'" , destPath .getBucket ());
285+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
286+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
287+ }
288+ if (destinationBlobExists ) {
245289 destinationBaseExists = true ;
246290 } else {
247291 // if gs://bucket2/subdir doesn't exist, check if gs://bucket2/subdir/ exists
248292 // similarly, if gs://bucket2/subdir/ doesn't exist, check if gs://bucket2/subdir exists
249293 // this is because "cp dir0 subdir" and "cp dir0 subdir/" are equivalent if the 'subdir' directory exists
250294 String modifiedName = baseDestName .endsWith ("/" ) ?
251295 baseDestName .substring (0 , baseDestName .length () - 1 ) : baseDestName + "/" ;
252- destinationBaseExists = storage .get (BlobId .of (destPath .getBucket (), modifiedName )) != null ;
296+ try {
297+ destinationBaseExists = storage .get (BlobId .of (destPath .getBucket (), modifiedName )) != null ;
298+ } catch (Exception e ) {
299+ String errorReason = String .format ("Unable to access GCS bucket '%s'" , destPath .getBucket ());
300+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
301+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
302+ }
253303 }
254304
255305 List <BlobPair > copyList = new ArrayList <>();
256306 traverse (BlobId .of (sourcePath .getBucket (), sourcePath .getName ()), recursive , sourceBlob -> {
257307 BlobId destBlobID = resolve (sourcePath .getName (), sourceBlob .getBlobId ().getName (),
258308 destPath , destinationBaseExists );
259309 if (!overwrite ) {
260- Blob destBlob = storage .get (destBlobID );
310+ Blob destBlob ;
311+ try {
312+ destBlob = storage .get (destBlobID );
313+ } catch (Exception e ) {
314+ String errorReason = String .format ("Unable to access GCS bucket '%s'" , destPath .getBucket ());
315+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
316+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
317+ }
261318 // we can't just use Blob's isDirectory() because the cloud console will create a 'directory' by creating
262319 // a 0 size placeholder blob that ends with '/'. This placeholder blob's isDirectory() method returns false,
263320 // but we don't want the overwrite check to fail on it. So we explicitly ignore the check for these 0 size
264321 // placeholder blobs.
265322 if (destBlob != null && !destBlob .getName ().endsWith ("/" ) && destBlob .getSize () != 0 ) {
266- throw new IllegalArgumentException (String .format ("%s already exists." , toPath (destBlobID )));
323+ String errorReason = String .format ("%s already exists." , toPath (destBlobID ));
324+ throw ErrorUtils .getProgramFailureException (new ErrorCategory (ErrorCategory .ErrorCategoryEnum .PLUGIN ),
325+ errorReason , errorReason , ErrorType .USER , true , null );
267326 }
268327 }
269328 copyList .add (new BlobPair (sourceBlob , destBlobID ));
@@ -347,8 +406,15 @@ static String append(String base, String part) {
347406 * @param consumer the blob consumer
348407 */
349408 private void traverse (BlobId blobId , boolean recursive , Consumer <Blob > consumer ) {
350- Page <Blob > blobList = storage .list (blobId .getBucket (), Storage .BlobListOption .currentDirectory (),
351- Storage .BlobListOption .prefix (blobId .getName ()));
409+ Page <Blob > blobList ;
410+ try {
411+ blobList = storage .list (blobId .getBucket (), Storage .BlobListOption .currentDirectory (),
412+ Storage .BlobListOption .prefix (blobId .getName ()));
413+ } catch (Exception e ) {
414+ String errorReason = String .format ("" );
415+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
416+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
417+ }
352418 for (Blob blob : blobList .iterateAll ()) {
353419 if (!blob .isDirectory ()) {
354420 consumer .accept (blob );
@@ -363,11 +429,17 @@ private static String toPath(BlobId blobId) {
363429 }
364430
365431 public static StorageClient create (String project , @ Nullable String serviceAccount ,
366- Boolean isServiceAccountFilePath , @ Nullable Integer readTimeout )
367- throws IOException {
432+ Boolean isServiceAccountFilePath , @ Nullable Integer readTimeout ) {
368433 StorageOptions .Builder builder = StorageOptions .newBuilder ().setProjectId (project );
369434 if (serviceAccount != null ) {
370- builder .setCredentials (GCPUtils .loadServiceAccountCredentials (serviceAccount , isServiceAccountFilePath ));
435+ try {
436+ builder .setCredentials (GCPUtils .loadServiceAccountCredentials (serviceAccount , isServiceAccountFilePath ));
437+ } catch (IOException e ) {
438+ String errorReason = "Unable to load service account credentials." ;
439+ throw ErrorUtils .getProgramFailureException (new ErrorCategory (ErrorCategory .ErrorCategoryEnum .PLUGIN ),
440+ errorReason , String .format ("%s %s: %s" , errorReason , e .getClass ().getName (), e .getMessage ()),
441+ ErrorType .UNKNOWN , false , null );
442+ }
371443 }
372444 if (readTimeout != null ) {
373445 builder .setTransportOptions (HttpTransportOptions .newBuilder ().setReadTimeout (readTimeout * 1000 ).build ());
@@ -376,7 +448,7 @@ public static StorageClient create(String project, @Nullable String serviceAccou
376448 return new StorageClient (storage );
377449 }
378450
379- public static StorageClient create (GCPConnectorConfig config ) throws IOException {
451+ public static StorageClient create (GCPConnectorConfig config ) {
380452 return create (config .getProject (), config .getServiceAccount (), config .isServiceAccountFilePath (), null );
381453 }
382454
0 commit comments