Skip to content

Commit 3744c86

Browse files
Add error details provider for Amazon S3 plugin
1 parent bbd7daf commit 3744c86

File tree

4 files changed

+80
-2
lines changed

4 files changed

+80
-2
lines changed

pom.xml

+6-2
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,9 @@
310310
<extensions>true</extensions>
311311
<configuration>
312312
<instructions>
313-
<_exportcontents>io.cdap.plugin.aws.s3.*</_exportcontents>
313+
<_exportcontents>
314+
io.cdap.plugin.aws.s3.*;
315+
</_exportcontents>
314316
<Embed-Dependency>*;inline=false;scope=compile</Embed-Dependency>
315317
<Embed-Transitive>true</Embed-Transitive>
316318
<Embed-Directory>lib</Embed-Directory>
@@ -492,7 +494,9 @@
492494
<extensions>true</extensions>
493495
<configuration>
494496
<instructions>
495-
<_exportcontents>io.cdap.plugin.aws.s3.*</_exportcontents>
497+
<_exportcontents>
498+
io.cdap.plugin.aws.s3.*;
499+
</_exportcontents>
496500
<Embed-Dependency>*;inline=false;scope=compile</Embed-Dependency>
497501
<Embed-Transitive>true</Embed-Transitive>
498502
<Embed-Directory>lib</Embed-Directory>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright © 2025 Cask Data, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
17+
package io.cdap.plugin.aws.s3.common;
18+
19+
import com.amazonaws.AmazonServiceException;
20+
import com.amazonaws.services.s3.model.AmazonS3Exception;
21+
import com.google.common.base.Throwables;
22+
import io.cdap.cdap.api.exception.ErrorCategory;
23+
import io.cdap.cdap.api.exception.ErrorCodeType;
24+
import io.cdap.cdap.api.exception.ErrorType;
25+
import io.cdap.cdap.api.exception.ErrorUtils;
26+
import io.cdap.cdap.api.exception.ErrorUtils.ActionErrorPair;
27+
import io.cdap.cdap.api.exception.ProgramFailureException;
28+
import io.cdap.cdap.etl.api.exception.ErrorContext;
29+
import io.cdap.cdap.etl.api.exception.ErrorDetailsProvider;
30+
import java.util.List;
31+
32+
/**
33+
* Error details provided for the Amazon S3
34+
**/
35+
public final class AmazonErrorDetailsProvider implements ErrorDetailsProvider {
36+
37+
static final String S3_EXTERNAL_DOC =
38+
"https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html";
39+
40+
@Override
41+
public ProgramFailureException getExceptionDetails(Exception e, ErrorContext errorContext) {
42+
List<Throwable> causalChain = Throwables.getCausalChain(e);
43+
for (Throwable t : causalChain) {
44+
if (t instanceof ProgramFailureException) {
45+
// if causal chain already has program failure exception, return null to avoid double wrap.
46+
return null;
47+
}
48+
if (t instanceof AmazonS3Exception) {
49+
AmazonS3Exception amazonServiceException = (AmazonS3Exception) t;
50+
int statusCode = amazonServiceException.getStatusCode();
51+
ActionErrorPair pair = ErrorUtils.getActionErrorByStatusCode(statusCode);
52+
String errorReason = String.format("%s %s. %s. For more details, see %s", statusCode,
53+
amazonServiceException.getErrorMessage(), pair.getCorrectiveAction(), S3_EXTERNAL_DOC);
54+
return ErrorUtils.getProgramFailureException(new ErrorCategory(
55+
ErrorCategory.ErrorCategoryEnum.PLUGIN, amazonServiceException.getErrorCode()),
56+
errorReason, amazonServiceException.getMessage(), ErrorType.USER, true,
57+
ErrorCodeType.HTTP, String.valueOf(statusCode), S3_EXTERNAL_DOC, t);
58+
}
59+
}
60+
return null;
61+
}
62+
}

src/main/java/io/cdap/plugin/aws/s3/sink/S3BatchSink.java

+6
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import io.cdap.cdap.etl.api.batch.BatchSink;
3232
import io.cdap.cdap.etl.api.batch.BatchSinkContext;
3333
import io.cdap.cdap.etl.api.connector.Connector;
34+
import io.cdap.plugin.aws.s3.common.AmazonErrorDetailsProvider;
3435
import io.cdap.plugin.aws.s3.common.S3ConnectorConfig;
3536
import io.cdap.plugin.aws.s3.common.S3Constants;
3637
import io.cdap.plugin.aws.s3.common.S3Path;
@@ -87,6 +88,11 @@ protected LineageRecorder getLineageRecorder(BatchSinkContext context) {
8788
return new LineageRecorder(context, asset);
8889
}
8990

91+
@Override
92+
protected String getErrorDetailsProviderClassName() {
93+
return AmazonErrorDetailsProvider.class.getName();
94+
}
95+
9096
@Override
9197
protected Map<String, String> getFileSystemProperties(BatchSinkContext context) {
9298
// when context is null, it is configure time, by that time, it will always use s3n

src/main/java/io/cdap/plugin/aws/s3/source/S3BatchSource.java

+6
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import io.cdap.cdap.etl.api.batch.BatchSource;
3131
import io.cdap.cdap.etl.api.batch.BatchSourceContext;
3232
import io.cdap.cdap.etl.api.connector.Connector;
33+
import io.cdap.plugin.aws.s3.common.AmazonErrorDetailsProvider;
3334
import io.cdap.plugin.aws.s3.common.S3ConnectorConfig;
3435
import io.cdap.plugin.aws.s3.common.S3Constants;
3536
import io.cdap.plugin.aws.s3.common.S3EmptyInputFormat;
@@ -89,6 +90,11 @@ public void prepareRun(BatchSourceContext context) throws Exception {
8990
super.prepareRun(context);
9091
}
9192

93+
@Override
94+
protected String getErrorDetailsProviderClassName() {
95+
return AmazonErrorDetailsProvider.class.getName();
96+
}
97+
9298
@Override
9399
protected LineageRecorder getLineageRecorder(BatchSourceContext context) {
94100
return new LineageRecorder(context, asset);

0 commit comments

Comments
 (0)