/******************************************************************************* * Copyright (c) 2014 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.orion.internal.server.servlets.file; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URI; import org.eclipse.core.filesystem.IFileInfo; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.filesystem.IFileSystem; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.orion.internal.server.servlets.ChangeEvent; import org.eclipse.orion.internal.server.servlets.IFileStoreModificationListener.ChangeType; /** * Wraps an ordinary {@link IFileStore} to provide notifications after write operations have * occurred. Supports {@link #equals(Object)} and {@link #hashCode()}. */ public class FileStoreNotificationWrapper implements IFileStore { private void notifyOfWrite(ChangeEvent event) { FilesystemModificationListenerManager.getInstance().notifyOfChange(event); } /** * Wrap the given store. When the wrapper is used to perform writes, change events * will be generated. */ public static FileStoreNotificationWrapper wrap(Object source, IFileStore store) { if (store == null) { return null; } return new FileStoreNotificationWrapper(source, store); } /** The source value for ChangeEvent notifications. */ private final Object source; private final IFileStore wrapped; private FileStoreNotificationWrapper(Object source, IFileStore store) { this.source = source; this.wrapped = store; } @SuppressWarnings("rawtypes") public Object getAdapter(Class adapter) { return wrapped.getAdapter(adapter); } public IFileInfo[] childInfos(int options, IProgressMonitor monitor) throws CoreException { return wrapped.childInfos(options, monitor); } public String[] childNames(int options, IProgressMonitor monitor) throws CoreException { return wrapped.childNames(options, monitor); } public IFileStore[] childStores(int options, IProgressMonitor monitor) throws CoreException { IFileStore[] toWrap = wrapped.childStores(options, monitor); for (int i = 0; i < toWrap.length; i++) { toWrap[i] = wrap(source, toWrap[i]); } return toWrap; } public void copy(IFileStore destination, int options, IProgressMonitor monitor) throws CoreException { destination = unwrap(destination); wrapped.copy(destination, options, monitor); // Tested by CoreFilesTest.testListenerCopyFile() notifyOfWrite(new ChangeEvent(source, ChangeType.COPY_INTO, destination, wrapped)); } public void delete(int options, IProgressMonitor monitor) throws CoreException { wrapped.delete(options, monitor); // Tested by CoreFilesTest.testListenerDeleteNonEmptyDirectory() // Tested by CoreFilesTest.testListenerDeleteEmptyDir() // Tested by CoreFilesTest.testListenerDeleteFile() notifyOfWrite(new ChangeEvent(source, ChangeType.DELETE, wrapped)); } public IFileInfo fetchInfo() { return wrapped.fetchInfo(); } public IFileInfo fetchInfo(int options, IProgressMonitor monitor) throws CoreException { return wrapped.fetchInfo(options, monitor); } @SuppressWarnings("deprecation") public IFileStore getChild(IPath path) { return wrap(source, wrapped.getChild(path)); } public IFileStore getFileStore(IPath path) { return wrap(source, wrapped.getFileStore(path)); } public IFileStore getChild(String name) { return wrap(source, wrapped.getChild(name)); } public IFileSystem getFileSystem() { return wrapped.getFileSystem(); } public String getName() { return wrapped.getName(); } public IFileStore getParent() { return wrap(source, wrapped.getParent()); } public boolean isParentOf(IFileStore other) { other = unwrap(other); return wrapped.isParentOf(other); } public static IFileStore unwrap(IFileStore other) { if (other instanceof FileStoreNotificationWrapper) { other = ((FileStoreNotificationWrapper) other).wrapped; } return other; } public IFileStore mkdir(int options, IProgressMonitor monitor) throws CoreException { IFileStore mkdir = wrapped.mkdir(options, monitor); notifyOfWrite(new ChangeEvent(source, ChangeType.MKDIR, mkdir)); // Tested by CoreFilesTest.testListenerCreateDirectory() return wrap(source, mkdir); } public void move(IFileStore destination, int options, IProgressMonitor monitor) throws CoreException { destination = unwrap(destination); wrapped.move(destination, options, monitor); // Tested by CoreFilesTest.testListenerMoveFileNoOverwrite() notifyOfWrite(new ChangeEvent(source, ChangeType.MOVE, destination, wrapped)); } public InputStream openInputStream(int options, IProgressMonitor monitor) throws CoreException { return wrapped.openInputStream(options, monitor); } public OutputStream openOutputStream(int options, IProgressMonitor monitor) throws CoreException { final OutputStream out = wrapped.openOutputStream(options, monitor); return new OutputStream() { @Override public void write(int b) throws IOException { out.write(b); } @Override public void write(byte[] b) throws IOException { out.write(b); } @Override public void write(byte[] b, int off, int len) throws IOException { out.write(b, off, len); } @Override public void flush() throws IOException { out.flush(); } @Override public void close() throws IOException { try { out.close(); } finally { // Tested by CoreFilesTest.testListenerWriteFile() notifyOfWrite(new ChangeEvent(source, ChangeType.WRITE, wrapped)); } } }; } public void putInfo(IFileInfo info, int options, IProgressMonitor monitor) throws CoreException { wrapped.putInfo(info, options, monitor); // Tested by Ad notifyOfWrite(new ChangeEvent(source, ChangeType.PUTINFO, wrapped)); } public File toLocalFile(int options, IProgressMonitor monitor) throws CoreException { // ;_; so much for wrapping return wrapped.toLocalFile(options, monitor); } public URI toURI() { return wrapped.toURI(); } @Override public boolean equals(Object o) { if (o instanceof FileStoreNotificationWrapper) { if (wrapped.equals(unwrap((FileStoreNotificationWrapper) o))) { return true; } } return false; } @Override public int hashCode() { return wrapped.hashCode(); } }