001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: https://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: https://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.db.storage.s3;
029
030import org.opencms.util.CmsStringUtil;
031
032import software.amazon.awssdk.regions.Region;
033
034/**
035 * Configuration for the S3 client used by the storage backend.<p>
036 */
037public class CmsS3ClientConfiguration {
038
039    /** Default complete API call timeout in milliseconds. */
040    public static final int DEFAULT_API_CALL_TIMEOUT = 60000;
041
042    /** Default single API call attempt timeout in milliseconds. */
043    public static final int DEFAULT_API_CALL_ATTEMPT_TIMEOUT = 30000;
044
045    /** Default connection timeout in milliseconds. */
046    public static final int DEFAULT_CONNECTION_TIMEOUT = 5000;
047
048    /** Default timeout for acquiring a pooled connection in milliseconds. */
049    public static final int DEFAULT_CONNECTION_ACQUISITION_TIMEOUT = 10000;
050
051    /** Default maximum number of pooled connections. */
052    public static final int DEFAULT_MAX_CONNECTIONS = 50;
053
054    /** Default maximum number of retries. */
055    public static final int DEFAULT_MAX_RETRIES = 2;
056
057    /** Default AWS region. */
058    public static final String DEFAULT_REGION = Region.AWS_GLOBAL.id();
059
060    /** Default socket timeout in milliseconds. */
061    public static final int DEFAULT_SOCKET_TIMEOUT = 30000;
062
063    /** The S3 access key. */
064    private final String m_accessKey;
065
066    /** The complete API call timeout in milliseconds. */
067    private final int m_apiCallTimeout;
068
069    /** The single API call attempt timeout in milliseconds. */
070    private final int m_apiCallAttemptTimeout;
071
072    /** The bucket name. */
073    private final String m_bucketName;
074
075    /** The connection timeout in milliseconds. */
076    private final int m_connectionTimeout;
077
078    /** The timeout for acquiring a pooled connection in milliseconds. */
079    private final int m_connectionAcquisitionTimeout;
080
081    /** The endpoint. */
082    private final String m_endpoint;
083
084    /** The maximum number of retries. */
085    private final int m_maxRetries;
086
087    /** The maximum number of pooled connections. */
088    private final int m_maxConnections;
089
090    /** Whether path-style access should be used. */
091    private final boolean m_pathStyle;
092
093    /** The AWS region. */
094    private final String m_region;
095
096    /** The S3 secret key. */
097    private final String m_secretKey;
098
099    /** The socket timeout in milliseconds. */
100    private final int m_socketTimeout;
101
102    /**
103     * Creates a new S3 client configuration.<p>
104     *
105     * @param endpoint the S3 endpoint
106     * @param bucketName the bucket name
107     * @param accessKey the access key
108     * @param secretKey the secret key
109     * @param pathStyle whether path-style access should be used
110     * @param region the AWS region
111     * @param connectionTimeout the connection timeout in milliseconds
112     * @param socketTimeout the socket timeout in milliseconds
113     * @param apiCallAttemptTimeout the timeout for a single API call attempt in milliseconds
114     * @param apiCallTimeout the timeout for the complete API call in milliseconds
115     * @param maxRetries the maximum number of retries
116     */
117    public CmsS3ClientConfiguration(
118        String endpoint,
119        String bucketName,
120        String accessKey,
121        String secretKey,
122        boolean pathStyle,
123        String region,
124        int connectionTimeout,
125        int socketTimeout,
126        int apiCallAttemptTimeout,
127        int apiCallTimeout,
128        int maxRetries) {
129
130        this(
131            endpoint,
132            bucketName,
133            accessKey,
134            secretKey,
135            pathStyle,
136            region,
137            connectionTimeout,
138            socketTimeout,
139            apiCallAttemptTimeout,
140            apiCallTimeout,
141            maxRetries,
142            DEFAULT_MAX_CONNECTIONS,
143            DEFAULT_CONNECTION_ACQUISITION_TIMEOUT);
144    }
145
146    /**
147     * Creates a new S3 client configuration including connection pool settings.<p>
148     *
149     * @param endpoint the S3 endpoint
150     * @param bucketName the bucket name
151     * @param accessKey the S3 access key
152     * @param secretKey the S3 secret key
153     * @param pathStyle whether path-style access should be used
154     * @param region the AWS region
155     * @param connectionTimeout the connection timeout in milliseconds
156     * @param socketTimeout the socket timeout in milliseconds
157     * @param apiCallAttemptTimeout the timeout for a single API call attempt in milliseconds
158     * @param apiCallTimeout the timeout for the complete API call in milliseconds
159     * @param maxRetries the maximum number of retries
160     * @param maxConnections the maximum number of pooled connections
161     * @param connectionAcquisitionTimeout the timeout for acquiring a pooled connection in milliseconds
162     */
163    public CmsS3ClientConfiguration(
164        String endpoint,
165        String bucketName,
166        String accessKey,
167        String secretKey,
168        boolean pathStyle,
169        String region,
170        int connectionTimeout,
171        int socketTimeout,
172        int apiCallAttemptTimeout,
173        int apiCallTimeout,
174        int maxRetries,
175        int maxConnections,
176        int connectionAcquisitionTimeout) {
177
178        validateRequired("endpoint", endpoint);
179        validateRequired("bucketName", bucketName);
180        validateRequired("accessKey", accessKey);
181        validateRequired("secretKey", secretKey);
182        validateRequired("region", region);
183        validatePositive("connectionTimeout", connectionTimeout);
184        validatePositive("socketTimeout", socketTimeout);
185        validatePositive("apiCallAttemptTimeout", apiCallAttemptTimeout);
186        validatePositive("apiCallTimeout", apiCallTimeout);
187        validateNonNegative("maxRetries", maxRetries);
188        validatePositive("maxConnections", maxConnections);
189        validatePositive("connectionAcquisitionTimeout", connectionAcquisitionTimeout);
190        m_endpoint = endpoint.trim();
191        m_bucketName = bucketName.trim();
192        m_accessKey = accessKey;
193        m_secretKey = secretKey;
194        m_pathStyle = pathStyle;
195        m_region = region.trim();
196        m_connectionTimeout = connectionTimeout;
197        m_connectionAcquisitionTimeout = connectionAcquisitionTimeout;
198        m_socketTimeout = socketTimeout;
199        m_apiCallAttemptTimeout = apiCallAttemptTimeout;
200        m_apiCallTimeout = apiCallTimeout;
201        m_maxRetries = maxRetries;
202        m_maxConnections = maxConnections;
203    }
204
205    /**
206     * Creates a new S3 client configuration using default client settings.<p>
207     *
208     * @param endpoint the S3 endpoint
209     * @param bucketName the bucket name
210     * @param accessKey the access key
211     * @param secretKey the secret key
212     * @param pathStyle whether path-style access should be used
213     *
214     * @return the configuration
215     */
216    public static CmsS3ClientConfiguration createDefault(
217        String endpoint,
218        String bucketName,
219        String accessKey,
220        String secretKey,
221        boolean pathStyle) {
222
223        return new CmsS3ClientConfiguration(
224            endpoint,
225            bucketName,
226            accessKey,
227            secretKey,
228            pathStyle,
229            DEFAULT_REGION,
230            DEFAULT_CONNECTION_TIMEOUT,
231            DEFAULT_SOCKET_TIMEOUT,
232            DEFAULT_API_CALL_ATTEMPT_TIMEOUT,
233            DEFAULT_API_CALL_TIMEOUT,
234            DEFAULT_MAX_RETRIES);
235    }
236
237    /**
238     * Validates that a configuration value is not negative.<p>
239     *
240     * @param name the configuration name
241     * @param value the configuration value
242     */
243    private static void validateNonNegative(String name, int value) {
244
245        if (value < 0) {
246            throw new IllegalArgumentException(name + " must not be negative.");
247        }
248    }
249
250    /**
251     * Validates that a configuration value is positive.<p>
252     *
253     * @param name the configuration name
254     * @param value the configuration value
255     */
256    private static void validatePositive(String name, int value) {
257
258        if (value <= 0) {
259            throw new IllegalArgumentException(name + " must be positive.");
260        }
261    }
262
263    /**
264     * Validates that a configuration value is not empty.<p>
265     *
266     * @param name the configuration name
267     * @param value the configuration value
268     */
269    private static void validateRequired(String name, String value) {
270
271        if (CmsStringUtil.isEmptyOrWhitespaceOnly(value)) {
272            throw new IllegalArgumentException(name + " must not be empty.");
273        }
274    }
275
276    /**
277     * Returns the access key.<p>
278     *
279     * @return the access key
280     */
281    public String getAccessKey() {
282
283        return m_accessKey;
284    }
285
286    /**
287     * Returns the single API call attempt timeout.<p>
288     *
289     * @return the timeout in milliseconds
290     */
291    public int getApiCallAttemptTimeout() {
292
293        return m_apiCallAttemptTimeout;
294    }
295
296    /**
297     * Returns the complete API call timeout.<p>
298     *
299     * @return the timeout in milliseconds
300     */
301    public int getApiCallTimeout() {
302
303        return m_apiCallTimeout;
304    }
305
306    /**
307     * Returns the bucket name.<p>
308     *
309     * @return the bucket name
310     */
311    public String getBucketName() {
312
313        return m_bucketName;
314    }
315
316    /**
317     * Returns the timeout for acquiring a pooled connection.<p>
318     *
319     * @return the timeout in milliseconds
320     */
321    public int getConnectionAcquisitionTimeout() {
322
323        return m_connectionAcquisitionTimeout;
324    }
325
326    /**
327     * Returns the connection timeout.<p>
328     *
329     * @return the timeout in milliseconds
330     */
331    public int getConnectionTimeout() {
332
333        return m_connectionTimeout;
334    }
335
336    /**
337     * Returns the endpoint.<p>
338     *
339     * @return the endpoint
340     */
341    public String getEndpoint() {
342
343        return m_endpoint;
344    }
345
346    /**
347     * Returns the maximum number of pooled connections.<p>
348     *
349     * @return the maximum number of pooled connections
350     */
351    public int getMaxConnections() {
352
353        return m_maxConnections;
354    }
355
356    /**
357     * Returns the maximum number of retries.<p>
358     *
359     * @return the maximum number of retries
360     */
361    public int getMaxRetries() {
362
363        return m_maxRetries;
364    }
365
366    /**
367     * Returns the configured AWS region.<p>
368     *
369     * @return the AWS region
370     */
371    public String getRegion() {
372
373        return m_region;
374    }
375
376    /**
377     * Returns the secret key.<p>
378     *
379     * @return the secret key
380     */
381    public String getSecretKey() {
382
383        return m_secretKey;
384    }
385
386    /**
387     * Returns the socket timeout.<p>
388     *
389     * @return the timeout in milliseconds
390     */
391    public int getSocketTimeout() {
392
393        return m_socketTimeout;
394    }
395
396    /**
397     * Returns whether path-style access is configured.<p>
398     *
399     * @return true if path-style access is configured
400     */
401    public boolean isPathStyle() {
402
403        return m_pathStyle;
404    }
405}