Skip to content

Commit dcf3d2f

Browse files
committed
Allow custom S3 endpoint, remove old legacy commented code
1 parent c102a7a commit dcf3d2f

File tree

3 files changed

+45
-56
lines changed

3 files changed

+45
-56
lines changed

dspace-api/src/main/java/org/dspace/storage/bitstore/S3BitStoreService.java

Lines changed: 38 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import java.io.IOException;
1313
import java.io.InputStream;
14+
import java.net.URI;
1415
import java.security.DigestInputStream;
1516
import java.security.MessageDigest;
1617
import java.security.NoSuchAlgorithmException;
@@ -40,6 +41,10 @@
4041
import org.dspace.storage.bitstore.service.BitstreamStorageService;
4142
import org.dspace.util.FunctionalUtils;
4243
import org.springframework.beans.factory.annotation.Autowired;
44+
45+
import jakarta.annotation.Nullable;
46+
import jakarta.validation.constraints.NotBlank;
47+
import jakarta.validation.constraints.NotNull;
4348
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
4449
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
4550
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
@@ -95,6 +100,13 @@ public class S3BitStoreService extends BaseBitStoreService {
95100

96101
private String awsAccessKey;
97102
private String awsSecretKey;
103+
104+
/**
105+
* Custom S3 endpoint URI which will override the Amazon defaults
106+
* if present.
107+
*/
108+
private String endpoint = null;
109+
98110
private String awsRegionName;
99111
private boolean useRelativePath;
100112
private double targetThroughputGbps = 10.0;
@@ -123,6 +135,7 @@ public class S3BitStoreService extends BaseBitStoreService {
123135
/**
124136
* Utility method for generate AmazonS3 builder
125137
*
138+
* @param endpoint optional custom s3 endpoint
126139
* @param regions wanted regions in client
127140
* @param awsCredentials credentials of the client
128141
* @param targetThroughput target throughput in Gbps
@@ -131,8 +144,9 @@ public class S3BitStoreService extends BaseBitStoreService {
131144
* @return builder with the specified parameters
132145
*/
133146
protected static Supplier<S3AsyncClient> amazonClientBuilderBy(
134-
Region region,
135-
AwsCredentialsProvider credentialsProvider,
147+
@Nullable String endpoint,
148+
@NotNull Region region,
149+
@NotNull AwsCredentialsProvider credentialsProvider,
136150
double targetThroughput,
137151
long minPartSize,
138152
Integer maxConcurrency
@@ -152,6 +166,11 @@ protected static Supplier<S3AsyncClient> amazonClientBuilderBy(
152166
crtBuilder.maxConcurrency(maxConcurrency);
153167
}
154168

169+
if (StringUtils.isNotBlank(endpoint)) {
170+
crtBuilder.endpointOverride(URI.create(endpoint));
171+
crtBuilder.forcePathStyle(true);
172+
}
173+
155174
return crtBuilder.targetThroughputInGbps(targetThroughput).minimumPartSizeInBytes(minPartSize).build();
156175
};
157176
}
@@ -181,10 +200,13 @@ public boolean isEnabled() {
181200
*/
182201
@Override
183202
public void init() throws IOException {
203+
184204
if (this.isInitialized() || !this.isEnabled()) {
185205
return;
186206
}
187207

208+
209+
188210
try {
189211
if (StringUtils.isNotBlank(getAwsAccessKey()) && StringUtils.isNotBlank(getAwsSecretKey())) {
190212
log.warn("Use local defined S3 credentials");
@@ -202,6 +224,7 @@ public void init() throws IOException {
202224
s3AsyncClient = FunctionalUtils.getDefaultOrBuild(
203225
this.s3AsyncClient,
204226
amazonClientBuilderBy(
227+
endpoint,
205228
region,
206229
StaticCredentialsProvider.create(AwsBasicCredentials.create(getAwsAccessKey(),
207230
getAwsSecretKey())), targetThroughputGbps, minPartSizeBytes, maxConcurrency)
@@ -211,7 +234,7 @@ public void init() throws IOException {
211234
log.info("Using a IAM role or aws environment credentials");
212235
s3AsyncClient = FunctionalUtils.getDefaultOrBuild(
213236
this.s3AsyncClient,
214-
amazonClientBuilderBy(null, null , targetThroughputGbps, minPartSizeBytes, maxConcurrency));
237+
amazonClientBuilderBy(endpoint, null, null , targetThroughputGbps, minPartSizeBytes, maxConcurrency));
215238
}
216239

217240
// bucket name
@@ -301,6 +324,9 @@ public InputStream get(Bitstream bitstream) throws IOException {
301324
*/
302325
@Override
303326
public void put(Bitstream bitstream, InputStream in) throws IOException {
327+
log.error(getEndpoint());
328+
log.error(getAwsAccessKey());
329+
log.error(getAwsSecretKey());
304330
String key = getFullKey(bitstream.getInternalId());
305331

306332
try (DigestInputStream dis = new DigestInputStream(in, MessageDigest.getInstance(CSA))) {
@@ -478,6 +504,15 @@ public void setAwsSecretKey(String awsSecretKey) {
478504
this.awsSecretKey = awsSecretKey;
479505
}
480506

507+
public String getEndpoint() {
508+
return endpoint;
509+
}
510+
511+
@Autowired
512+
public void setEndpoint(String endpoint) {
513+
this.endpoint = endpoint;
514+
}
515+
481516
public String getAwsRegionName() {
482517
return awsRegionName;
483518
}
@@ -596,58 +631,6 @@ public static void main(String[] args) throws Exception {
596631
store.bucketName = DEFAULT_BUCKET_PREFIX + hostname + ".s3test";
597632
store.s3AsyncClient.createBucket(r -> r.bucket(store.bucketName)).join();
598633

599-
/* Broken in DSpace 6 TODO Refactor
600-
// time everything, todo, switch to caliper
601-
long start = Instant.now().toEpochMilli();
602-
// Case 1: store a file
603-
String id = store.generateId();
604-
System.out.print("put() file " + assetFile + " under ID " + id + ": ");
605-
FileInputStream fis = new FileInputStream(assetFile);
606-
//TODO create bitstream for assetfile...
607-
Map attrs = store.put(fis, id);
608-
long now = Instant.now().toEpochMilli();
609-
System.out.println((now - start) + " msecs");
610-
start = now;
611-
// examine the metadata returned
612-
Iterator iter = attrs.keySet().iterator();
613-
System.out.println("Metadata after put():");
614-
while (iter.hasNext())
615-
{
616-
String key = (String)iter.next();
617-
System.out.println( key + ": " + (String)attrs.get(key) );
618-
}
619-
// Case 2: get metadata and compare
620-
System.out.print("about() file with ID " + id + ": ");
621-
Map attrs2 = store.about(id, attrs);
622-
now = Instant.now().toEpochMilli();
623-
System.out.println((now - start) + " msecs");
624-
start = now;
625-
iter = attrs2.keySet().iterator();
626-
System.out.println("Metadata after about():");
627-
while (iter.hasNext())
628-
{
629-
String key = (String)iter.next();
630-
System.out.println( key + ": " + (String)attrs.get(key) );
631-
}
632-
// Case 3: retrieve asset and compare bits
633-
System.out.print("get() file with ID " + id + ": ");
634-
java.io.FileOutputStream fos = new java.io.FileOutputStream(assetFile+".echo");
635-
InputStream in = store.get(id);
636-
Utils.bufferedCopy(in, fos);
637-
fos.close();
638-
in.close();
639-
now = Instant.now().toEpochMilli();
640-
System.out.println((now - start) + " msecs");
641-
start = now;
642-
// Case 4: remove asset
643-
System.out.print("remove() file with ID: " + id + ": ");
644-
store.remove(id);
645-
now = Instant.now().toEpochMilli();
646-
System.out.println((now - start) + " msecs");
647-
System.out.flush();
648-
// should get nothing back now - will throw exception
649-
store.get(id);
650-
*/
651634
}
652635

653636
/**

dspace/config/modules/assetstore.cfg

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ assetstore.s3.subfolder =
5555
assetstore.s3.awsAccessKey =
5656
assetstore.s3.awsSecretKey =
5757

58+
# Optional custom S3 endpoint URI. Leave this blank / commented to use the Amazon default
59+
#assetstore.s3.endpoint =
60+
5861
# If the credentials are left empty,
5962
# then this setting is ignored and the default AWS region will be used.
6063
assetstore.s3.awsRegionName =
@@ -118,4 +121,4 @@ assetstore.s3.s3ChecksumAlgorithm = CRC32
118121

119122
# The maximum counter value for S3 operations.
120123
# Default: -1 (unlimited) connection is never manualy closed in BitstoreService
121-
# assetstore.jcloud.maxCounter = -1
124+
# assetstore.jcloud.maxCounter = -1

dspace/config/spring/api/bitstore.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
<!-- S3 bucket name to store assets in. example: longsight-dspace-auk -->
2929
<property name="bucketName" value="${assetstore.s3.bucketName}"/>
3030

31+
<!-- S3 endpoint URI if not using Amazon defaults, example: minio.mysite.org -->
32+
<property name="endpoint" value="${assetstore.s3.endpoint:}"/>
33+
3134
<!-- AWS S3 Region to use: {us-east-1, us-west-1, eu-west-1, eu-central-1, ap-southeast-1, ... } -->
3235
<!-- Optional, sdk default is us-east-1 -->
3336
<property name="awsRegionName" value="${assetstore.s3.awsRegionName}"/>

0 commit comments

Comments
 (0)