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 /**
@@ -132,9 +149,11 @@ public void createBucketIfNotExists(GCSPath path, @Nullable String location, @Nu
132149 LOG .warn ("Getting 409 Conflict: {} Bucket at destination path {} may already exist." ,
133150 e .getMessage (), path .getUri ());
134151 } else {
135- throw new RuntimeException (
152+ String errorReason =
136153 String .format ("Unable to create bucket %s. Ensure you entered the correct bucket path and " +
137- "have permissions for it." , path .getBucket ()), e );
154+ "have permissions for it." , path .getBucket ());
155+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
156+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
138157 }
139158 }
140159 }
@@ -173,9 +192,16 @@ public void move(GCSPath sourcePath, GCSPath destPath, boolean recursive, boolea
173192 * Get all the matching wildcard paths given the regex input.
174193 */
175194 public List <GCSPath > getMatchedPaths (GCSPath sourcePath , boolean recursive , Pattern wildcardRegex ) {
176- Page <Blob > blobPage = storage .list (sourcePath .getBucket (), Storage .BlobListOption .prefix (
195+ Page <Blob > blobPage ;
196+ try {
197+ blobPage = storage .list (sourcePath .getBucket (), Storage .BlobListOption .prefix (
177198 getWildcardPathPrefix (sourcePath , wildcardRegex )
178- ));
199+ ));
200+ } catch (Exception e ) {
201+ String errorReason = String .format ("Unable to list objects in bucket %s." , sourcePath .getBucket ());
202+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
203+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
204+ }
179205 List <String > blobPageNames = new ArrayList <>();
180206 blobPage .getValues ().forEach (blob -> blobPageNames .add (blob .getName ()));
181207 return getFilterMatchedPaths (sourcePath , blobPageNames , recursive );
@@ -212,58 +238,84 @@ static List<GCSPath> getFilterMatchedPaths(GCSPath sourcePath, List<String> blob
212238 private void pairTraverse (GCSPath sourcePath , GCSPath destPath , boolean recursive , boolean overwrite ,
213239 Consumer <BlobPair > consumer ) {
214240
215- Bucket sourceBucket = null ;
241+ Bucket sourceBucket ;
216242 try {
217243 sourceBucket = storage .get (sourcePath .getBucket ());
218- } catch (StorageException e ) {
244+ } catch (Exception e ) {
219245 // 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 );
246+ String errorReason = String . format ( "Unable to access GCS bucket '%s'" , sourcePath . getBucket ());
247+ throw GCPErrorDetailsProviderUtil . getHttpResponseExceptionDetailsFromChain ( e , errorReason , ErrorType . UNKNOWN ,
248+ true , GCPUtils . GCS_SUPPORTED_DOC_URL );
223249 }
224250 if (sourceBucket == null ) {
225- throw new IllegalArgumentException (
226- String .format ("Source bucket '%s' does not exist." , sourcePath .getBucket ()));
251+ String errorReason = String .format ("Source bucket '%s' does not exist." , sourcePath .getBucket ());
252+ throw ErrorUtils .getProgramFailureException (new ErrorCategory (ErrorCategory .ErrorCategoryEnum .PLUGIN ),
253+ errorReason , errorReason , ErrorType .USER , true , null );
227254 }
228- Bucket destBucket = null ;
255+ Bucket destBucket ;
229256 try {
230257 destBucket = storage .get (destPath .getBucket ());
231- } catch (StorageException e ) {
258+ } catch (Exception e ) {
232259 // 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 );
260+ String errorReason = String . format ( "Unable to access GCS bucket '%s'" , destPath . getBucket ());
261+ throw GCPErrorDetailsProviderUtil . getHttpResponseExceptionDetailsFromChain ( e , errorReason , ErrorType . UNKNOWN ,
262+ true , GCPUtils . GCS_SUPPORTED_DOC_URL );
236263 }
237264 if (destBucket == null ) {
238- throw new IllegalArgumentException (
239- String .format ("Destination bucket '%s' does not exist. Please create it first." , destPath .getBucket ()));
265+ String errorReason =
266+ String .format ("Destination bucket '%s' does not exist. Please create it first." , destPath .getBucket ());
267+ throw ErrorUtils .getProgramFailureException (new ErrorCategory (ErrorCategory .ErrorCategoryEnum .PLUGIN ),
268+ errorReason , errorReason , ErrorType .USER , true , null );
240269 }
241270
242271 boolean destinationBaseExists ;
243272 String baseDestName = destPath .getName ();
244- if (destPath .isBucket () || storage .get (BlobId .of (destPath .getBucket (), baseDestName )) != null ) {
273+ boolean destinationBlobExists ;
274+ try {
275+ destinationBlobExists = destPath .isBucket () || storage .get (BlobId .of (destPath .getBucket (), baseDestName )) != null ;
276+ } catch (Exception e ) {
277+ String errorReason = String .format ("Unable to access GCS bucket '%s'" , destPath .getBucket ());
278+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
279+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
280+ }
281+ if (destinationBlobExists ) {
245282 destinationBaseExists = true ;
246283 } else {
247284 // if gs://bucket2/subdir doesn't exist, check if gs://bucket2/subdir/ exists
248285 // similarly, if gs://bucket2/subdir/ doesn't exist, check if gs://bucket2/subdir exists
249286 // this is because "cp dir0 subdir" and "cp dir0 subdir/" are equivalent if the 'subdir' directory exists
250287 String modifiedName = baseDestName .endsWith ("/" ) ?
251288 baseDestName .substring (0 , baseDestName .length () - 1 ) : baseDestName + "/" ;
252- destinationBaseExists = storage .get (BlobId .of (destPath .getBucket (), modifiedName )) != null ;
289+ try {
290+ destinationBaseExists = storage .get (BlobId .of (destPath .getBucket (), modifiedName )) != null ;
291+ } catch (Exception e ) {
292+ String errorReason = String .format ("Unable to access GCS bucket '%s'" , destPath .getBucket ());
293+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
294+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
295+ }
253296 }
254297
255298 List <BlobPair > copyList = new ArrayList <>();
256299 traverse (BlobId .of (sourcePath .getBucket (), sourcePath .getName ()), recursive , sourceBlob -> {
257300 BlobId destBlobID = resolve (sourcePath .getName (), sourceBlob .getBlobId ().getName (),
258301 destPath , destinationBaseExists );
259302 if (!overwrite ) {
260- Blob destBlob = storage .get (destBlobID );
303+ Blob destBlob ;
304+ try {
305+ destBlob = storage .get (destBlobID );
306+ } catch (Exception e ) {
307+ String errorReason = String .format ("Unable to access GCS bucket '%s'" , destPath .getBucket ());
308+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
309+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
310+ }
261311 // we can't just use Blob's isDirectory() because the cloud console will create a 'directory' by creating
262312 // a 0 size placeholder blob that ends with '/'. This placeholder blob's isDirectory() method returns false,
263313 // but we don't want the overwrite check to fail on it. So we explicitly ignore the check for these 0 size
264314 // placeholder blobs.
265315 if (destBlob != null && !destBlob .getName ().endsWith ("/" ) && destBlob .getSize () != 0 ) {
266- throw new IllegalArgumentException (String .format ("%s already exists." , toPath (destBlobID )));
316+ String errorReason = String .format ("%s already exists." , toPath (destBlobID ));
317+ throw ErrorUtils .getProgramFailureException (new ErrorCategory (ErrorCategory .ErrorCategoryEnum .PLUGIN ),
318+ errorReason , errorReason , ErrorType .USER , true , null );
267319 }
268320 }
269321 copyList .add (new BlobPair (sourceBlob , destBlobID ));
@@ -347,8 +399,15 @@ static String append(String base, String part) {
347399 * @param consumer the blob consumer
348400 */
349401 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 ()));
402+ Page <Blob > blobList ;
403+ try {
404+ blobList = storage .list (blobId .getBucket (), Storage .BlobListOption .currentDirectory (),
405+ Storage .BlobListOption .prefix (blobId .getName ()));
406+ } catch (Exception e ) {
407+ String errorReason = String .format ("" );
408+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
409+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
410+ }
352411 for (Blob blob : blobList .iterateAll ()) {
353412 if (!blob .isDirectory ()) {
354413 consumer .accept (blob );
@@ -363,11 +422,17 @@ private static String toPath(BlobId blobId) {
363422 }
364423
365424 public static StorageClient create (String project , @ Nullable String serviceAccount ,
366- Boolean isServiceAccountFilePath , @ Nullable Integer readTimeout )
367- throws IOException {
425+ Boolean isServiceAccountFilePath , @ Nullable Integer readTimeout ) {
368426 StorageOptions .Builder builder = StorageOptions .newBuilder ().setProjectId (project );
369427 if (serviceAccount != null ) {
370- builder .setCredentials (GCPUtils .loadServiceAccountCredentials (serviceAccount , isServiceAccountFilePath ));
428+ try {
429+ builder .setCredentials (GCPUtils .loadServiceAccountCredentials (serviceAccount , isServiceAccountFilePath ));
430+ } catch (IOException e ) {
431+ String errorReason = "Unable to load service account credentials." ;
432+ throw ErrorUtils .getProgramFailureException (new ErrorCategory (ErrorCategory .ErrorCategoryEnum .PLUGIN ),
433+ errorReason , String .format ("%s %s: %s" , errorReason , e .getClass ().getName (), e .getMessage ()),
434+ ErrorType .UNKNOWN , false , null );
435+ }
371436 }
372437 if (readTimeout != null ) {
373438 builder .setTransportOptions (HttpTransportOptions .newBuilder ().setReadTimeout (readTimeout * 1000 ).build ());
@@ -376,7 +441,7 @@ public static StorageClient create(String project, @Nullable String serviceAccou
376441 return new StorageClient (storage );
377442 }
378443
379- public static StorageClient create (GCPConnectorConfig config ) throws IOException {
444+ public static StorageClient create (GCPConnectorConfig config ) {
380445 return create (config .getProject (), config .getServiceAccount (), config .isServiceAccountFilePath (), null );
381446 }
382447
0 commit comments