Skip to content

Commit 3e5fb55

Browse files
authored
feat: S3Client Cleanup and Error Handling Improvements (#1149)
Signed-off-by: Atanas Atanasov <a.v.atanasov98@gmail.com>
1 parent 61ebe73 commit 3e5fb55

File tree

9 files changed

+1013
-355
lines changed

9 files changed

+1013
-355
lines changed

block-node/base/src/main/java/module-info.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
requires transitive org.hiero.block.node.spi;
99
requires com.hedera.pbj.runtime;
10+
requires org.hiero.block.common;
1011
requires com.github.luben.zstd_jni;
1112
requires java.net.http;
1213
requires java.xml;

block-node/base/src/main/java/org/hiero/block/node/base/s3/S3Client.java

Lines changed: 400 additions & 180 deletions
Large diffs are not rendered by default.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
package org.hiero.block.node.base.s3;
3+
4+
/**
5+
* A checked exception to act as a base for all S3 client exceptions.
6+
*/
7+
public class S3ClientException extends Exception {
8+
public S3ClientException() {
9+
super();
10+
}
11+
12+
public S3ClientException(final String message) {
13+
super(message);
14+
}
15+
16+
public S3ClientException(final Throwable cause) {
17+
super(cause);
18+
}
19+
20+
public S3ClientException(final String message, final Throwable cause) {
21+
super(message, cause);
22+
}
23+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
package org.hiero.block.node.base.s3;
3+
4+
public class S3ClientInitializationException extends S3ClientException {
5+
public S3ClientInitializationException() {
6+
super();
7+
}
8+
9+
public S3ClientInitializationException(final String message) {
10+
super(message);
11+
}
12+
13+
public S3ClientInitializationException(final Throwable cause) {
14+
super(cause);
15+
}
16+
17+
public S3ClientInitializationException(final String message, final Throwable cause) {
18+
super(message, cause);
19+
}
20+
}
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
package org.hiero.block.node.base.s3;
3+
4+
import edu.umd.cs.findbugs.annotations.Nullable;
5+
import java.net.http.HttpHeaders;
6+
import java.util.List;
7+
import java.util.Map;
8+
import java.util.Map.Entry;
9+
10+
/**
11+
* A checked exception thrown when an S3 response is not successful.
12+
*/
13+
public final class S3ResponseException extends S3ClientException {
14+
/** The size limit for the toString response body length */
15+
private static final int MAX_RESPONSE_BODY_STRING_LENGTH = 2048;
16+
/** The size limit for the toString headers length */
17+
private static final int MAX_HEADER_STRING_LENGTH = 2048;
18+
/** The four-space indent used for formatting the exception string */
19+
private static final String FOUR_SPACE_INDENT = " ";
20+
/** The response status code */
21+
private final int responseStatusCode;
22+
/** The response body, nullable */
23+
private final byte[] responseBody;
24+
/** The response headers, nullable */
25+
private final HttpHeaders responseHeaders;
26+
27+
public S3ResponseException(
28+
final int responseStatusCode,
29+
@Nullable final byte[] responseBody,
30+
@Nullable final HttpHeaders responseHeaders) {
31+
super();
32+
this.responseStatusCode = responseStatusCode;
33+
this.responseBody = responseBody;
34+
this.responseHeaders = responseHeaders;
35+
}
36+
37+
public S3ResponseException(
38+
final int responseStatusCode,
39+
@Nullable final byte[] responseBody,
40+
@Nullable final HttpHeaders responseHeaders,
41+
final String message) {
42+
super(message);
43+
this.responseStatusCode = responseStatusCode;
44+
this.responseBody = responseBody;
45+
this.responseHeaders = responseHeaders;
46+
}
47+
48+
public S3ResponseException(
49+
final int responseStatusCode,
50+
@Nullable final byte[] responseBody,
51+
@Nullable final HttpHeaders responseHeaders,
52+
final Throwable cause) {
53+
super(cause);
54+
this.responseStatusCode = responseStatusCode;
55+
this.responseBody = responseBody;
56+
this.responseHeaders = responseHeaders;
57+
}
58+
59+
public S3ResponseException(
60+
final int responseStatusCode,
61+
@Nullable final byte[] responseBody,
62+
@Nullable final HttpHeaders responseHeaders,
63+
final String message,
64+
final Throwable cause) {
65+
super(message, cause);
66+
this.responseStatusCode = responseStatusCode;
67+
this.responseBody = responseBody;
68+
this.responseHeaders = responseHeaders;
69+
}
70+
71+
public int getResponseStatusCode() {
72+
return responseStatusCode;
73+
}
74+
75+
public byte[] getResponseBody() {
76+
return responseBody;
77+
}
78+
79+
public HttpHeaders getResponseHeaders() {
80+
return responseHeaders;
81+
}
82+
83+
/**
84+
* @return a {@link String} representation of this exception including the
85+
* response code, headers if available and body if available. Header and
86+
* body strings are limited to a maximum length: header limit - {@value MAX_HEADER_STRING_LENGTH}
87+
* and body limit - {@value MAX_RESPONSE_BODY_STRING_LENGTH}.
88+
*/
89+
@Override
90+
public String toString() {
91+
// start with standard exception string building
92+
final String className = getClass().getName();
93+
final String message = getLocalizedMessage();
94+
final StringBuilder sb = new StringBuilder(className);
95+
if (message != null) {
96+
// if there is a message, append it
97+
sb.append(": ").append(message);
98+
}
99+
sb.append(System.lineSeparator());
100+
appendResponseCode(sb);
101+
appendHeaders(sb);
102+
appendBody(sb);
103+
return sb.toString();
104+
}
105+
106+
/**
107+
* Append the response code to the StringBuilder.
108+
*/
109+
private void appendResponseCode(final StringBuilder sb) {
110+
// append the response status code
111+
sb.append(FOUR_SPACE_INDENT).append("Response status code: ").append(responseStatusCode);
112+
}
113+
114+
/**
115+
* Append the response headers to the StringBuilder.
116+
* If there are no headers, this method does nothing.
117+
* Size limit for the headers string is {@value MAX_HEADER_STRING_LENGTH}.
118+
*/
119+
private void appendHeaders(final StringBuilder sb) {
120+
if (responseHeaders != null) {
121+
final Map<String, List<String>> headersMap = responseHeaders.map();
122+
if (headersMap != null && !headersMap.isEmpty()) {
123+
// for each header, append the header name and value(s)
124+
sb.append(System.lineSeparator());
125+
sb.append(FOUR_SPACE_INDENT).append("Response headers:");
126+
// we limit the size of the printed headers
127+
int headerSizeCount = 0;
128+
for (final Entry<String, List<String>> entry : headersMap.entrySet()) {
129+
// for each header, we get the key and values
130+
final String headerKey = entry.getKey() + ": ";
131+
sb.append(System.lineSeparator());
132+
if (headerSizeCount + headerKey.length() > MAX_HEADER_STRING_LENGTH) {
133+
// if string limit size is exceeded, break
134+
sb.append(FOUR_SPACE_INDENT.repeat(2)).append("...");
135+
break;
136+
} else {
137+
// append the header key
138+
sb.append(FOUR_SPACE_INDENT.repeat(2)).append(headerKey);
139+
headerSizeCount += headerKey.length();
140+
}
141+
// append the header values, usually we expect only one value per header
142+
final List<String> values = entry.getValue();
143+
boolean isFirstValue = true;
144+
for (final String value : values) {
145+
// if string limit size is exceeded, break
146+
if (headerSizeCount + value.length() > MAX_HEADER_STRING_LENGTH) {
147+
// if the value size exceeds the limit, break
148+
sb.append(" ...");
149+
break;
150+
} else {
151+
// append the value, separate with a comma for multi-value headers
152+
if (!isFirstValue) {
153+
sb.append(", ");
154+
headerSizeCount += 2;
155+
} else {
156+
isFirstValue = false;
157+
}
158+
sb.append(value);
159+
headerSizeCount += value.length();
160+
}
161+
}
162+
}
163+
}
164+
}
165+
}
166+
167+
/**
168+
* Append the response body to the StringBuilder.
169+
* If there is no response body, this method does nothing.
170+
* Size limit for the response body string is {@value MAX_RESPONSE_BODY_STRING_LENGTH}.
171+
*/
172+
private void appendBody(final StringBuilder sb) {
173+
if (responseBody != null && responseBody.length > 0) {
174+
// if there is a response body, append it
175+
sb.append(System.lineSeparator());
176+
// we limit the size of the printed response body
177+
sb.append(" Response body: ");
178+
if (responseBody.length > MAX_RESPONSE_BODY_STRING_LENGTH) {
179+
sb.append(new String(responseBody, 0, MAX_RESPONSE_BODY_STRING_LENGTH))
180+
.append(" ...");
181+
} else {
182+
// if the response body is small enough, append it fully
183+
sb.append(new String(responseBody));
184+
}
185+
}
186+
}
187+
}

block-node/base/src/main/java/org/hiero/block/node/base/s3/XmlBodyHandler.java

Lines changed: 0 additions & 61 deletions
This file was deleted.

0 commit comments

Comments
 (0)