/** * This file is part of muCommander, http://www.mucommander.com * Copyright (C) 2002-2016 Maxence Bernard * * muCommander is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * muCommander is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.mucommander.commons.file.protocol.s3; import com.mucommander.commons.file.*; import com.mucommander.commons.io.RandomAccessInputStream; import org.jets3t.service.S3Service; import org.jets3t.service.S3ServiceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * <code>S3Bucket</code> represents an Amazon S3 bucket. * * @author Maxence Bernard */ public class S3Bucket extends S3File { private static final Logger LOGGER = LoggerFactory.getLogger(S3File.class); private String bucketName; private S3BucketFileAttributes atts; // TODO: add support for ACL ? (would cost an extra request per bucket) /** Default permissions for S3 buckets */ private final static FilePermissions DEFAULT_PERMISSIONS = new SimpleFilePermissions(448); // rwx------ protected S3Bucket(FileURL url, S3Service service, String bucketName) throws AuthException { super(url, service); this.bucketName = bucketName; atts = new S3BucketFileAttributes(); } protected S3Bucket(FileURL url, S3Service service, org.jets3t.service.model.S3Bucket bucket) throws AuthException { super(url, service); this.bucketName = bucket.getName(); atts = new S3BucketFileAttributes(bucket); } /////////////////////////// // S3File implementation // /////////////////////////// @Override public FileAttributes getFileAttributes() { return atts; } ///////////////////////////////// // ProtocolFile implementation // ///////////////////////////////// @Override public String getOwner() { return atts.getOwner(); } @Override public boolean canGetOwner() { return true; } @Override public AbstractFile[] ls() throws IOException { return listObjects(bucketName, "", this); } @Override public void delete() throws IOException { try { service.deleteBucket(bucketName); } catch(S3ServiceException e) { throw getIOException(e); } } @Override public void mkdir() throws IOException { try { service.createBucket(bucketName); } catch(S3ServiceException e) { throw getIOException(e); } } // Unsupported operations @Override @UnsupportedFileOperation public void copyRemotelyTo(AbstractFile destFile) throws UnsupportedFileOperationException { throw new UnsupportedFileOperationException(FileOperation.COPY_REMOTELY); } @Override @UnsupportedFileOperation public void renameTo(AbstractFile destFile) throws UnsupportedFileOperationException { throw new UnsupportedFileOperationException(FileOperation.RENAME); } /** * Always throws an {@link UnsupportedFileOperationException}. */ @Override @UnsupportedFileOperation public InputStream getInputStream() throws UnsupportedFileOperationException { throw new UnsupportedFileOperationException(FileOperation.READ_FILE); } /** * Always throws an {@link UnsupportedFileOperationException}. */ @Override @UnsupportedFileOperation public OutputStream getOutputStream() throws UnsupportedFileOperationException { throw new UnsupportedFileOperationException(FileOperation.WRITE_FILE); } /** * Always throws an {@link UnsupportedFileOperationException}. */ @Override @UnsupportedFileOperation public RandomAccessInputStream getRandomAccessInputStream() throws UnsupportedFileOperationException { throw new UnsupportedFileOperationException(FileOperation.RANDOM_READ_FILE); } /////////////////// // Inner classes // /////////////////// /** * S3BucketFileAttributes provides getters and setters for S3 bucket attributes. By extending * <code>SyncedFileAttributes</code>, this class caches attributes for a certain amount of time * after which fresh values are retrieved from the server. * * @author Maxence Bernard */ private class S3BucketFileAttributes extends SyncedFileAttributes { private final static int TTL = 60000; private S3BucketFileAttributes() throws AuthException { super(TTL, false); // no initial update fetchAttributes(); // throws AuthException if no or bad credentials updateExpirationDate(); // declare the attributes as 'fresh' } private S3BucketFileAttributes(org.jets3t.service.model.S3Bucket bucket) throws AuthException { super(TTL, false); // no initial update setAttributes(bucket); setExists(true); updateExpirationDate(); // declare the attributes as 'fresh' } private void setAttributes(org.jets3t.service.model.S3Bucket bucket) { setDirectory(true); setDate(bucket.getCreationDate().getTime()); setPermissions(DEFAULT_PERMISSIONS); setOwner(bucket.getOwner().getDisplayName()); } private void fetchAttributes() throws AuthException { org.jets3t.service.model.S3Bucket bucket; S3ServiceException e = null; try { // Note: unlike getObjectDetails, getBucket returns null when the bucket does not exist // (that is because the corresponding request is a GET on the root resource, not a HEAD on the bucket). bucket = service.getBucket(bucketName); } catch(S3ServiceException ex) { e = ex; bucket = null; } if(bucket!=null) { // Bucket exists setExists(true); setAttributes(bucket); } else { // Bucket doesn't exist on the server, or could not be retrieved setExists(false); setDirectory(false); setDate(0); setPermissions(FilePermissions.EMPTY_FILE_PERMISSIONS); setOwner(null); if(e!=null) handleAuthException(e, fileURL); } } ///////////////////////////////////////// // SyncedFileAttributes implementation // ///////////////////////////////////////// @Override public void updateAttributes() { try { fetchAttributes(); } catch(Exception e) { // AuthException LOGGER.info("Failed to update attributes", e); } } } }