Java tutorial
/* * Copyright 2012 Last.fm * * Licensed 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 fm.last.moji.impl; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.util.Collections; import java.util.List; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import fm.last.moji.MojiFile; import fm.last.moji.MojiFileAttributes; import fm.last.moji.tracker.TrackerFactory; class MojiFileImpl implements MojiFile { private static final Logger log = LoggerFactory.getLogger(MojiFileImpl.class); private final String domain; private final TrackerFactory trackerFactory; private final HttpConnectionFactory httpFactory; private final ReadWriteLock lock; private Executor executor; private String storageClass; private String key; MojiFileImpl(String key, String domain, String storageClass, TrackerFactory trackerFactory, HttpConnectionFactory httpFactory) { this.key = key; this.domain = domain; this.storageClass = storageClass; this.trackerFactory = trackerFactory; this.httpFactory = httpFactory; executor = new Executor(trackerFactory); lock = new ReentrantReadWriteLock(); } @Override public boolean exists() throws IOException { log.debug("exists() : {}", this); boolean exists = false; try { lock.readLock().lock(); ExistsCommand command = new ExistsCommand(key, domain); executor.executeCommand(command); exists = command.getExists(); log.debug("exists() -> {}", exists); } finally { lock.readLock().unlock(); } return exists; } @Override public void delete() throws IOException { log.debug("delete() : {}", this); try { lock.writeLock().lock(); DeleteCommand command = new DeleteCommand(key, domain); executor.executeCommand(command); } finally { lock.writeLock().unlock(); } } @Override public long length() throws IOException { log.debug("length() : {}", this); long length = -1L; try { lock.readLock().lock(); FileLengthCommand command = new FileLengthCommand(httpFactory, key, domain); executor.executeCommand(command); length = command.getLength(); log.debug("length() -> {}", length); } finally { lock.readLock().unlock(); } return length; } @Override public InputStream getInputStream() throws IOException { log.debug("getInputStream() : {}", this); InputStream inputStream = null; try { Lock readLock = lock.readLock(); readLock.lock(); GetInputStreamCommand command = new GetInputStreamCommand(key, domain, httpFactory, readLock); executor.executeCommand(command); inputStream = command.getInputStream(); log.debug("getInputStream() -> {}", inputStream); } catch (Throwable e) { unlockQuietly(lock.readLock()); IOUtils.closeQuietly(inputStream); if (e instanceof IOException) { throw (IOException) e; } else { throw new RuntimeException(e); } } // calling close will release the lock return inputStream; } @Override public OutputStream getOutputStream() throws IOException { log.debug("getOutputStream() : {}", this); OutputStream outputStream = null; try { Lock writeLock = lock.writeLock(); writeLock.lock(); GetOutputStreamCommand command = new GetOutputStreamCommand(trackerFactory, httpFactory, key, domain, storageClass, writeLock); executor.executeCommand(command); outputStream = command.getOutputStream(); log.debug("getOutputStream() -> {}", outputStream); } catch (Throwable e) { unlockQuietly(lock.writeLock()); IOUtils.closeQuietly(outputStream); if (e instanceof IOException) { throw (IOException) e; } else { throw new RuntimeException(e); } } // calling close will release the lock return outputStream; } @Override public void rename(String newKey) throws IOException { log.debug("rename() : {}", this); try { lock.writeLock().lock(); RenameCommand command = new RenameCommand(key, domain, newKey); executor.executeCommand(command); key = newKey; } finally { lock.writeLock().unlock(); } } @Override public void modifyStorageClass(String newStorageClass) throws IOException { log.debug("setStorageClass() : {}", this); if (storageClass == null) { throw new IllegalArgumentException("storageClass == null"); } try { lock.writeLock().lock(); UpdateStorageClassCommand command = new UpdateStorageClassCommand(key, domain, newStorageClass); executor.executeCommand(command); storageClass = newStorageClass; } finally { lock.writeLock().unlock(); } } @Override public List<URL> getPaths() throws IOException { log.debug("getPaths() : {}", this); List<URL> paths = Collections.emptyList(); try { lock.readLock().lock(); GetPathsCommand command = new GetPathsCommand(key, domain); executor.executeCommand(command); paths = command.getPaths(); log.debug("getPaths() -> {}", paths); } finally { lock.readLock().unlock(); } return paths; } @Override public MojiFileAttributes getAttributes() throws IOException { log.debug("getAttributes() : {}", this); MojiFileAttributes attributes = null; try { lock.readLock().lock(); GetAttributesCommand command = new GetAttributesCommand(key, domain); executor.executeCommand(command); attributes = command.getAttributes(); log.debug("getAttributes() -> {}", attributes); } finally { lock.readLock().unlock(); } return attributes; } @Override public String getKey() { return key; } @Override public String getDomain() { return domain; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("MogileFileImpl [domain="); builder.append(domain); builder.append(", key="); builder.append(key); builder.append("]"); return builder.toString(); } @Override public void copyToFile(File destination) throws IOException { InputStream inputStream = null; inputStream = getInputStream(); // buffers internally and closes FileUtils.copyInputStreamToFile(inputStream, destination); } void setExecutor(Executor executor) { this.executor = executor; } private void unlockQuietly(Lock lock) { try { lock.unlock(); } catch (IllegalMonitorStateException e) { } } }