/* * 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 * * 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.streams.s3; import com.amazonaws.services.s3.AmazonS3Client; import com.amazonaws.services.s3.model.ObjectMetadata; import com.amazonaws.services.s3.transfer.TransferManager; import com.amazonaws.services.s3.transfer.Upload; import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Map; /** * This class uses ByteArrayOutputStreams to ensure files are written to S3 properly. The stream is written to the * in memory ByteArrayOutPutStream before it is finally written to Amazon S3. The size the file is allowed to become * is directly controlled by the S3PersistWriter. */ public class S3OutputStreamWrapper extends OutputStream { private static final Logger LOGGER = LoggerFactory.getLogger(S3OutputStreamWrapper.class); private final AmazonS3Client amazonS3Client; private final String bucketName; private final String path; private final String fileName; private ByteArrayOutputStream outputStream; private final Map<String, String> metaData; private boolean isClosed = false; /** * Create an OutputStream Wrapper * @param amazonS3Client * The Amazon S3 Client which will be handling the file * @param bucketName * The Bucket Name you are wishing to write to. * @param path * The path where the object will live * @param fileName * The fileName you ware wishing to write. * @param metaData * Any meta data that is to be written along with the object * @throws IOException * If there is an issue creating the stream, this */ public S3OutputStreamWrapper(AmazonS3Client amazonS3Client, String bucketName, String path, String fileName, Map<String, String> metaData) throws IOException { this.amazonS3Client = amazonS3Client; this.bucketName = bucketName; this.path = path; this.fileName = fileName; this.metaData = metaData; this.outputStream = new ByteArrayOutputStream(); } public void write(int byt) throws IOException { this.outputStream.write(byt); } public void write(byte[] byt) throws IOException { this.outputStream.write(byt); } public void write(byte[] byt, int off, int len) throws IOException { this.outputStream.write(byt, off, len); } public void flush() throws IOException { this.outputStream.flush(); } /** * Whenever the output stream is closed we are going to kick the ByteArrayOutputStream off to Amazon S3. * @throws IOException * Exception thrown from the FileOutputStream */ public void close() throws IOException { if (!isClosed) { try { this.addFile(); this.outputStream.close(); this.outputStream = null; } catch (Exception ex) { ex.printStackTrace(); LOGGER.warn("There was an error adding the temporaryFile to S3"); } finally { // we are done here. this.isClosed = true; } } } private void addFile() throws Exception { InputStream is = new ByteArrayInputStream(this.outputStream.toByteArray()); int contentLength = outputStream.size(); TransferManager transferManager = new TransferManager(amazonS3Client); ObjectMetadata metadata = new ObjectMetadata(); metadata.setExpirationTime(DateTime.now().plusDays(365 * 3).toDate()); metadata.setContentLength(contentLength); metadata.addUserMetadata("writer", "org.apache.streams"); for (String s : metaData.keySet()) { metadata.addUserMetadata(s, metaData.get(s)); } String fileNameToWrite = path + fileName; Upload upload = transferManager.upload(bucketName, fileNameToWrite, is, metadata); try { upload.waitForUploadResult(); is.close(); transferManager.shutdownNow(false); LOGGER.info("S3 File Close[{} kb] - {}", contentLength / 1024, path + fileName); } catch (Exception ignored) { LOGGER.trace("Ignoring", ignored); } } }