| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.jackrabbit.aws.ext; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.Properties; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import com.amazonaws.AmazonClientException; |
| import com.amazonaws.ClientConfiguration; |
| import com.amazonaws.Protocol; |
| import com.amazonaws.auth.AWSCredentials; |
| import com.amazonaws.auth.BasicAWSCredentials; |
| import com.amazonaws.regions.Regions; |
| import com.amazonaws.services.s3.AmazonS3; |
| import com.amazonaws.services.s3.AmazonS3Client; |
| import com.amazonaws.services.s3.S3ClientOptions; |
| import com.amazonaws.services.s3.model.ObjectListing; |
| import com.amazonaws.services.s3.model.Region; |
| import com.amazonaws.services.s3.model.S3ObjectSummary; |
| import com.amazonaws.util.StringUtils; |
| |
| /** |
| * Amazon S3 utilities. |
| */ |
| public final class Utils { |
| |
| private static final Logger LOG = LoggerFactory.getLogger(Utils.class); |
| |
| public static final String DEFAULT_CONFIG_FILE = "aws.properties"; |
| |
| private static final String DELETE_CONFIG_SUFFIX = ";burn"; |
| |
| /** |
| * The default value AWS bucket region. |
| */ |
| public static final String DEFAULT_AWS_BUCKET_REGION = "us-standard"; |
| |
| /** |
| * constants to define endpoint to various AWS region |
| */ |
| public static final String AWSDOTCOM = "amazonaws.com"; |
| |
| public static final String S3 = "s3"; |
| |
| public static final String DOT = "."; |
| |
| public static final String DASH = "-"; |
| |
| /** |
| * private constructor so that class cannot initialized from outside. |
| */ |
| private Utils() { |
| |
| } |
| |
| /** |
| * Create AmazonS3Client from properties. |
| * |
| * @param prop properties to configure @link {@link AmazonS3Client} |
| * @return {@link AmazonS3Client} |
| */ |
| public static AmazonS3Client openService(final Properties prop) { |
| String accessKey = prop.getProperty(S3Constants.ACCESS_KEY); |
| String secretKey = prop.getProperty(S3Constants.SECRET_KEY); |
| AmazonS3Client s3service = null; |
| if (StringUtils.isNullOrEmpty(accessKey) |
| || StringUtils.isNullOrEmpty(secretKey)) { |
| LOG.info("Configuring Amazon Client from environment"); |
| s3service = new AmazonS3Client(getClientConfiguration(prop)); |
| } else { |
| LOG.info("Configuring Amazon Client from property file."); |
| AWSCredentials credentials = new BasicAWSCredentials(accessKey, |
| secretKey); |
| s3service = new AmazonS3Client(credentials, |
| getClientConfiguration(prop)); |
| } |
| String region = prop.getProperty(S3Constants.S3_REGION); |
| String endpoint = null; |
| String propEndPoint = prop.getProperty(S3Constants.S3_END_POINT); |
| if ((propEndPoint != null) && !"".equals(propEndPoint)) { |
| endpoint = propEndPoint; |
| } else { |
| if (StringUtils.isNullOrEmpty(region)) { |
| com.amazonaws.regions.Region s3Region = Regions.getCurrentRegion(); |
| if (s3Region != null) { |
| region = s3Region.getName(); |
| } else { |
| throw new AmazonClientException( |
| "parameter [" |
| + S3Constants.S3_REGION |
| + "] not configured and cannot be derived from environment"); |
| } |
| } |
| if (DEFAULT_AWS_BUCKET_REGION.equals(region)) { |
| endpoint = S3 + DOT + AWSDOTCOM; |
| } else if (Region.EU_Ireland.toString().equals(region)) { |
| endpoint = "s3-eu-west-1" + DOT + AWSDOTCOM; |
| } else { |
| endpoint = S3 + DASH + region + DOT + AWSDOTCOM; |
| } |
| } |
| /* |
| * setting endpoint to remove latency of redirection. If endpoint is |
| * not set, invocation first goes us standard region, which |
| * redirects it to correct location. |
| */ |
| s3service.setEndpoint(endpoint); |
| LOG.info("S3 service endpoint [{}] ", endpoint); |
| s3service.setS3ClientOptions(getS3ClientOptions(prop)); |
| return s3service; |
| } |
| |
| /** |
| * Delete S3 bucket. This method first deletes all objects from bucket and |
| * then delete empty bucket. |
| * |
| * @param bucketName the bucket name. |
| */ |
| public static void deleteBucket(final String bucketName) throws IOException { |
| Properties prop = readConfig(DEFAULT_CONFIG_FILE); |
| AmazonS3 s3service = openService(prop); |
| ObjectListing prevObjectListing = s3service.listObjects(bucketName); |
| while (true) { |
| for (S3ObjectSummary s3ObjSumm : prevObjectListing.getObjectSummaries()) { |
| s3service.deleteObject(bucketName, s3ObjSumm.getKey()); |
| } |
| if (!prevObjectListing.isTruncated()) { |
| break; |
| } |
| prevObjectListing = s3service.listNextBatchOfObjects(prevObjectListing); |
| } |
| s3service.deleteBucket(bucketName); |
| } |
| |
| /** |
| * Read a configuration properties file. If the file name ends with ";burn", |
| * the file is deleted after reading. |
| * |
| * @param fileName the properties file name |
| * @return the properties |
| * @throws IOException if the file doesn't exist |
| */ |
| public static Properties readConfig(String fileName) throws IOException { |
| boolean delete = false; |
| if (fileName.endsWith(DELETE_CONFIG_SUFFIX)) { |
| delete = true; |
| fileName = fileName.substring(0, fileName.length() |
| - DELETE_CONFIG_SUFFIX.length()); |
| } |
| if (!new File(fileName).exists()) { |
| throw new IOException("Config file not found: " + fileName); |
| } |
| Properties prop = new Properties(); |
| InputStream in = null; |
| try { |
| in = new FileInputStream(fileName); |
| prop.load(in); |
| } finally { |
| if (in != null) { |
| in.close(); |
| } |
| if (delete) { |
| deleteIfPossible(new File(fileName)); |
| } |
| } |
| return prop; |
| } |
| |
| private static void deleteIfPossible(final File file) { |
| boolean deleted = file.delete(); |
| if (!deleted) { |
| LOG.warn("Could not delete " + file.getAbsolutePath()); |
| } |
| } |
| |
| private static ClientConfiguration getClientConfiguration(Properties prop) { |
| int connectionTimeOut = Integer.parseInt(prop.getProperty(S3Constants.S3_CONN_TIMEOUT)); |
| int socketTimeOut = Integer.parseInt(prop.getProperty(S3Constants.S3_SOCK_TIMEOUT)); |
| int maxConnections = Integer.parseInt(prop.getProperty(S3Constants.S3_MAX_CONNS)); |
| int maxErrorRetry = Integer.parseInt(prop.getProperty(S3Constants.S3_MAX_ERR_RETRY)); |
| |
| String protocol = prop.getProperty(S3Constants.S3_CONN_PROTOCOL); |
| String proxyHost = prop.getProperty(S3Constants.PROXY_HOST); |
| String proxyPort = prop.getProperty(S3Constants.PROXY_PORT); |
| |
| ClientConfiguration cc = new ClientConfiguration(); |
| |
| if (protocol != null && protocol.equalsIgnoreCase("http")) { |
| cc.setProtocol(Protocol.HTTP); |
| } |
| |
| if (proxyHost != null && !proxyHost.isEmpty()) { |
| cc.setProxyHost(proxyHost); |
| } |
| |
| if (proxyPort != null && !proxyPort.isEmpty()) { |
| cc.setProxyPort(Integer.parseInt(proxyPort)); |
| } |
| |
| cc.setConnectionTimeout(connectionTimeOut); |
| cc.setSocketTimeout(socketTimeOut); |
| cc.setMaxConnections(maxConnections); |
| cc.setMaxErrorRetry(maxErrorRetry); |
| |
| return cc; |
| } |
| |
| private static S3ClientOptions getS3ClientOptions(Properties prop) { |
| boolean pathStyleAccess = Boolean.parseBoolean(prop.getProperty(S3Constants.S3_PATH_STYLE_ACCESS)); |
| return S3ClientOptions.builder().setPathStyleAccess(pathStyleAccess).build(); |
| } |
| } |