Skip to content

Commit e7206b1

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

File tree

4 files changed

+90
-2
lines changed

4 files changed

+90
-2
lines changed

pom.xml

+20-2
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,11 @@
142142
</exclusion>
143143
</exclusions>
144144
</dependency>
145+
<dependency>
146+
<groupId>org.apache.hadoop</groupId>
147+
<artifactId>hadoop-aws</artifactId>
148+
<version>${hadoop.version}</version>
149+
</dependency>
145150
<dependency>
146151
<groupId>io.cdap.cdap</groupId>
147152
<artifactId>cdap-data-pipeline3_2.12</artifactId>
@@ -283,6 +288,11 @@
283288
<artifactId>aws-java-sdk-s3</artifactId>
284289
<version>${aws.sdk.version}</version>
285290
</dependency>
291+
<dependency>
292+
<groupId>org.apache.commons</groupId>
293+
<artifactId>commons-lang3</artifactId>
294+
<version>3.12.0</version>
295+
</dependency>
286296
<dependency>
287297
<groupId>com.amazonaws</groupId>
288298
<artifactId>aws-java-sdk-sts</artifactId>
@@ -310,7 +320,11 @@
310320
<extensions>true</extensions>
311321
<configuration>
312322
<instructions>
313-
<_exportcontents>io.cdap.plugin.aws.s3.*</_exportcontents>
323+
<_exportcontents>
324+
io.cdap.plugin.aws.s3.*;
325+
org.apache.hadoop.fs.s3a.*;
326+
org.apache.hadoop.fs.s3native.*;
327+
</_exportcontents>
314328
<Embed-Dependency>*;inline=false;scope=compile</Embed-Dependency>
315329
<Embed-Transitive>true</Embed-Transitive>
316330
<Embed-Directory>lib</Embed-Directory>
@@ -492,7 +506,11 @@
492506
<extensions>true</extensions>
493507
<configuration>
494508
<instructions>
495-
<_exportcontents>io.cdap.plugin.aws.s3.*</_exportcontents>
509+
<_exportcontents>
510+
io.cdap.plugin.aws.s3.*;
511+
org.apache.hadoop.fs.s3a.*;
512+
org.apache.hadoop.fs.s3native.*;
513+
</_exportcontents>
496514
<Embed-Dependency>*;inline=false;scope=compile</Embed-Dependency>
497515
<Embed-Transitive>true</Embed-Transitive>
498516
<Embed-Directory>lib</Embed-Directory>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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.google.common.base.Throwables;
21+
import io.cdap.cdap.api.exception.ErrorCategory;
22+
import io.cdap.cdap.api.exception.ErrorCodeType;
23+
import io.cdap.cdap.api.exception.ErrorType;
24+
import io.cdap.cdap.api.exception.ErrorUtils;
25+
import io.cdap.cdap.api.exception.ProgramFailureException;
26+
import io.cdap.cdap.etl.api.exception.ErrorContext;
27+
import io.cdap.cdap.etl.api.exception.ErrorDetailsProvider;
28+
import java.util.List;
29+
30+
/**
31+
* Error details provided for the Amazon S3
32+
**/
33+
public final class AmazonErrorDetailsProvider implements ErrorDetailsProvider {
34+
35+
static final String S3_EXTERNAL_DOC =
36+
"https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html";
37+
38+
@Override
39+
public ProgramFailureException getExceptionDetails(Exception e, ErrorContext errorContext) {
40+
List<Throwable> causalChain = Throwables.getCausalChain(e);
41+
for (Throwable t : causalChain) {
42+
if (t instanceof ProgramFailureException) {
43+
// if causal chain already has program failure exception, return null to avoid double wrap.
44+
return null;
45+
}
46+
if (t instanceof AmazonServiceException) {
47+
AmazonServiceException s3Exception = (AmazonServiceException) t;
48+
String errorMessage = s3Exception.getErrorMessage();
49+
String errorMessageWithDetails = s3Exception.getMessage();
50+
return ErrorUtils.getProgramFailureException(
51+
new ErrorCategory(ErrorCategory.ErrorCategoryEnum.PLUGIN, s3Exception.getErrorCode()),
52+
errorMessage, errorMessageWithDetails, ErrorType.USER, true, ErrorCodeType.HTTP,
53+
String.valueOf(s3Exception.getStatusCode()), S3_EXTERNAL_DOC, t);
54+
}
55+
}
56+
return null;
57+
}
58+
}

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)