Java tutorial
/** * Copyright (C) 2013 Red Hat, Inc. (jdcasey@commonjava.org) * * 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 org.commonjava.maven.galley.model; import org.commonjava.maven.galley.event.EventMetadata; import org.commonjava.maven.galley.event.FileAccessEvent; import org.commonjava.maven.galley.event.FileDeletionEvent; import org.commonjava.maven.galley.event.FileErrorEvent; import org.commonjava.maven.galley.event.FileStorageEvent; import org.commonjava.maven.galley.io.OverriddenBooleanValue; import org.commonjava.maven.galley.spi.cache.CacheProvider; import org.commonjava.maven.galley.spi.event.FileEventManager; import org.commonjava.maven.galley.spi.io.TransferDecorator; import org.commonjava.maven.galley.util.TransferInputStream; import org.commonjava.maven.galley.util.TransferOutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import static org.apache.commons.lang.StringUtils.join; public class Transfer { public static final String DELETE_CONTENT_LOG = "org.commonjava.topic.content.delete"; private final Logger logger = LoggerFactory.getLogger(getClass()); private ConcreteResource resource; private final CacheProvider provider; private final TransferDecorator decorator; private final FileEventManager fileEventManager; public Transfer(final Location loc, final CacheProvider provider, final FileEventManager fileEventManager, final TransferDecorator decorator, final String... path) { this.resource = new ConcreteResource(loc, path); this.fileEventManager = fileEventManager; this.decorator = decorator; this.provider = provider; } public Transfer(final ConcreteResource resource, final CacheProvider provider, final FileEventManager fileEventManager, final TransferDecorator decorator) { this.resource = resource; this.fileEventManager = fileEventManager; this.decorator = decorator; this.provider = provider; } public boolean isDirectory() { return provider.isDirectory(resource); } public boolean isFile() { return provider.isFile(resource); } public Location getLocation() { return resource.getLocation(); } public String getPath() { return resource.getPath(); } public ConcreteResource getResource() { return resource; } @Override public String toString() { return String.format("%s:%s (stored at: %s)", resource.getLocation(), resource.getPath(), provider.getFilePath(resource)); } public Transfer getParent() { if (resource.isRoot()) { return this; } return provider.getTransfer(resource.getParent()); } public Transfer getChild(final String file) { return provider.getTransfer(resource.getChild(file)); } public void touch() { touch(new EventMetadata()); } public void touch(final EventMetadata eventMetadata) { if (decorator != null) { decorator.decorateTouch(this, eventMetadata); } fileEventManager.fire(new FileAccessEvent(this, eventMetadata)); } public InputStream openInputStream() throws IOException { return openInputStream(true, new EventMetadata()); } public InputStream openInputStream(final boolean fireEvents) throws IOException { return openInputStream(fireEvents, new EventMetadata()); } public InputStream openInputStream(final boolean fireEvents, final EventMetadata eventMetadata) throws IOException { provider.waitForReadUnlock(resource); try { InputStream stream = provider.openInputStream(resource); if (stream == null) { return null; } if (fireEvents) { stream = new TransferInputStream(stream, new FileAccessEvent(this, eventMetadata), fileEventManager); } stream = decorator == null ? stream : decorator.decorateRead(stream, this, eventMetadata); logger.trace("Returning stream: {} for transfer: {}", stream.getClass().getName(), this); return stream; } catch (final IOException e) { if (fireEvents) { fileEventManager.fire(new FileErrorEvent(this, e, eventMetadata)); } throw e; } } public OutputStream openOutputStream(final TransferOperation accessType) throws IOException { return openOutputStream(accessType, true); } public OutputStream openOutputStream(final TransferOperation accessType, final boolean fireEvents) throws IOException { return openOutputStream(accessType, fireEvents, new EventMetadata()); } public OutputStream openOutputStream(final TransferOperation accessType, final boolean fireEvents, final EventMetadata eventMetadata) throws IOException { return openOutputStream(accessType, fireEvents, eventMetadata, false); } public OutputStream openOutputStream(final TransferOperation accessType, final boolean fireEvents, final EventMetadata eventMetadata, boolean deleteFilesOnPath) throws IOException { provider.waitForWriteUnlock(resource); try { provider.lockWrite(resource); if (deleteFilesOnPath) { deleteFilesOnPath(); } OutputStream stream = provider.openOutputStream(resource); if (stream == null) { return null; } final TransferUnlocker unlocker = new TransferUnlocker(resource, provider); if (fireEvents) { logger.info("Wrapping output stream to: {} using event metadata: {}", this, eventMetadata); stream = new TransferOutputStream(stream, unlocker, new FileStorageEvent(accessType, this, eventMetadata), fileEventManager); } else { logger.info("Wrapping output stream to: {} WITHOUT event metadata", this); stream = new TransferOutputStream(stream, unlocker); } stream = decorator == null ? stream : decorator.decorateWrite(stream, this, accessType, eventMetadata); return stream; } catch (final IOException e) { if (fireEvents) { fileEventManager.fire(new FileErrorEvent(this, e, eventMetadata)); } throw e; } } /** * Goes up through the path to the root of the resource location until it finds an existing element and removes it * in case if it is a file. Starts from the resource path, so also the target file is removed if it pre-exists. * * @throws IOException in case of a deletion problem */ private void deleteFilesOnPath() throws IOException { ConcreteResource currentRes = resource; while (!provider.exists(currentRes) && !currentRes.isRoot()) { currentRes = currentRes.getParent(); } if (provider.exists(currentRes) && provider.isFile(currentRes)) { provider.delete(currentRes); } } public boolean exists(final EventMetadata eventMetadata) { OverriddenBooleanValue overriden = null; if (decorator != null) { overriden = decorator.decorateExists(this, eventMetadata); } if ((overriden != null) && overriden.overrides()) { return overriden.getResult(); } else { return provider.exists(resource); } } public boolean exists() { return exists(new EventMetadata()); } public void copyFrom(final Transfer f) throws IOException { copyFrom(f, new EventMetadata()); } public void copyFrom(final Transfer f, final EventMetadata eventMetadata) throws IOException { provider.waitForWriteUnlock(resource); provider.lockWrite(resource); try { if (decorator != null) { decorator.decorateCopyFrom(f, this, eventMetadata); } provider.copy(f.getResource(), resource); } finally { provider.unlockWrite(resource); } } public String getFullPath() { return provider.getFilePath(resource); } public boolean delete() throws IOException { return delete(true, new EventMetadata()); } public boolean delete(final boolean fireEvents) throws IOException { return delete(fireEvents, new EventMetadata()); } public boolean delete(final boolean fireEvents, final EventMetadata eventMetadata) throws IOException { provider.waitForWriteUnlock(resource); if (!resource.allowsDeletion()) { throw new IOException("Deletion not allowed for: " + resource); } try { if (decorator != null) { decorator.decorateDelete(this, eventMetadata); } Logger contentLogger = LoggerFactory.getLogger(DELETE_CONTENT_LOG); if (contentLogger.isTraceEnabled()) { contentLogger.trace("Starting delete of: {} ({}) from:\n ", resource, eventMetadata, join(Thread.currentThread().getStackTrace(), "\n ")); } else { contentLogger.info("Starting delete of: {} ({})", resource, eventMetadata); } final boolean deleted = provider.delete(resource); if (deleted) { contentLogger.info("Finished delete of: {}", resource); if (fireEvents) { fileEventManager.fire(new FileDeletionEvent(this, eventMetadata)); } } else { contentLogger.info("Failed to delete: {}", resource); } return deleted; } catch (final IOException e) { if (fireEvents) { fileEventManager.fire(new FileErrorEvent(this, e, eventMetadata)); } throw e; } } public String[] list() throws IOException { String[] listing = provider.list(resource); if (decorator != null) { listing = decorator.decorateListing(this, listing, new EventMetadata()); } return listing; } public File getDetachedFile() { provider.waitForWriteUnlock(resource); provider.lockWrite(resource); try { return provider.asAdminView().getDetachedFile(resource); } finally { provider.unlockWrite(resource); } } public void mkdirs() throws IOException { if (decorator != null) { decorator.decorateMkdirs(this, new EventMetadata()); } provider.mkdirs(resource); } public void createFile() throws IOException { provider.waitForWriteUnlock(resource); if (decorator != null) { decorator.decorateCreateFile(this, new EventMetadata()); } provider.createFile(resource); } public long length() { return provider.length(resource); } public long lastModified() { return provider.lastModified(resource); } public Transfer getSibling(final String named) { if (resource.isRoot()) { return null; } return getParent().getChild(named); } public Transfer getSiblingMeta(final String extension) { if (resource.isRoot()) { return null; } final String named = resource.getPath() + extension; final Transfer tx = this; logger.debug("Creating meta-transfer sibling for: {}", new Object() { @Override public String toString() { return tx + " with name: " + named + " (parent: " + tx.getParent() + ")"; } }); return provider.getTransfer(new ConcreteResource(getLocation(), named)); } public static final class TransferUnlocker { private final CacheProvider provider; private final ConcreteResource resource; private TransferUnlocker(final ConcreteResource resource, final CacheProvider provider) { this.resource = resource; this.provider = provider; } public void unlock() { provider.unlockWrite(resource); } } public void lockWrite() { provider.lockWrite(resource); } public void unlock() { provider.unlockWrite(resource); } public boolean isWriteLocked() { return provider.isWriteLocked(resource); } public TransferDecorator getDecorator() { return decorator; } public void setResource(ConcreteResource resource) { this.resource = resource; } @Override public boolean equals(final Object o) { if (this == o) { return true; } if (!(o instanceof Transfer)) { return false; } final Transfer transfer = (Transfer) o; return resource.equals(transfer.resource); } @Override public int hashCode() { return resource.hashCode(); } }