/**
* This file Copyright (c) 2005-2010 Aptana, Inc. This program is
* dual-licensed under both the Aptana Public License and the GNU General
* Public license. You may elect to use one or the other of these licenses.
*
* This program is distributed in the hope that it will be useful, but
* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
* NONINFRINGEMENT. Redistribution, except as permitted by whichever of
* the GPL or APL you select, is prohibited.
*
* 1. For the GPL license (GPL), you can redistribute and/or modify this
* program under the terms of the GNU General Public License,
* Version 3, as published by the Free Software Foundation. You should
* have received a copy of the GNU General Public License, Version 3 along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Aptana provides a special exception to allow redistribution of this file
* with certain other free and open source software ("FOSS") code and certain additional terms
* pursuant to Section 7 of the GPL. You may view the exception and these
* terms on the web at http://www.aptana.com/legal/gpl/.
*
* 2. For the Aptana Public License (APL), this program and the
* accompanying materials are made available under the terms of the APL
* v1.0 which accompanies this distribution, and is available at
* http://www.aptana.com/legal/apl/.
*
* You may view the GPL, Aptana's exception and additional terms, and the
* APL in the file titled license.html at the root of the corresponding
* plugin containing this source file.
*
* Any modifications to this file must keep this entire header intact.
*/
package com.aptana.ide.core.io.efs;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileInfo;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.filesystem.IFileSystem;
import org.eclipse.core.filesystem.provider.FileInfo;
import org.eclipse.core.filesystem.provider.FileStore;
import org.eclipse.core.internal.filesystem.Messages;
import org.eclipse.core.internal.filesystem.Policy;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceProxy;
import org.eclipse.core.resources.IResourceProxyVisitor;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.osgi.util.NLS;
import com.aptana.ide.core.IdeLog;
import com.aptana.ide.core.io.CoreIOPlugin;
import com.aptana.ide.core.io.preferences.CloakingUtils;
/**
* @author Max Stepanov
*
*/
@SuppressWarnings("restriction")
/* package */ class WorkspaceFile extends FileStore {
private static final IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
private IResource resource;
private final IPath path;
private IFileStore localFileStore;
private static boolean refreshed = false;
/**
*
*/
public WorkspaceFile(IResource resource) {
this(resource, resource.getFullPath());
}
/**
*
*/
public WorkspaceFile(IPath path) {
this(null, path);
}
/**
*
*/
private WorkspaceFile(IResource resource, IPath path) {
this.resource = resource;
this.path = path;
}
/* (non-Javadoc)
* @see org.eclipse.core.runtime.PlatformObject#getAdapter(java.lang.Class)
*/
@SuppressWarnings("unchecked")
@Override
public Object getAdapter(Class adapter) {
if (IResource.class == adapter) {
try {
ensureResource();
} catch (CoreException e) {
}
return resource;
}
return super.getAdapter(adapter);
}
/* (non-Javadoc)
* @see org.eclipse.core.filesystem.provider.FileStore#childNames(int, org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
public String[] childNames(int options, IProgressMonitor monitor) throws CoreException {
ensureResource();
if (resource instanceof IContainer) {
IContainer container = (IContainer) resource;
if (!container.isSynchronized(IResource.DEPTH_ONE)) {
container.refreshLocal(IResource.DEPTH_ONE, new NullProgressMonitor());
}
final List<String> childNames = new ArrayList<String>();
final boolean[] skipSelf = new boolean[] { true };
container.accept(new IResourceProxyVisitor() {
public boolean visit(IResourceProxy proxy) throws CoreException {
if (skipSelf[0]) {
skipSelf[0] = false;
return true;
}
childNames.add(proxy.getName());
return false;
}
}, IContainer.INCLUDE_HIDDEN);
return childNames.toArray(new String[childNames.size()]);
}
return EMPTY_STRING_ARRAY;
}
/* (non-Javadoc)
* @see org.eclipse.core.filesystem.provider.FileStore#fetchInfo(int, org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
public IFileInfo fetchInfo(int options, IProgressMonitor monitor) throws CoreException {
ensureLocalFileStore();
if (localFileStore != null) {
return localFileStore.fetchInfo(options, monitor);
}
FileInfo info = new FileInfo(path.lastSegment());
info.setExists(false);
return info;
}
/* (non-Javadoc)
* @see org.eclipse.core.filesystem.provider.FileStore#getChild(java.lang.String)
*/
@Override
public IFileStore getChild(String name) {
return new WorkspaceFile(path.append(name));
}
/* (non-Javadoc)
* @see org.eclipse.core.filesystem.provider.FileStore#getName()
*/
@Override
public String getName() {
return path.lastSegment();
}
/* (non-Javadoc)
* @see org.eclipse.core.filesystem.provider.FileStore#getParent()
*/
@Override
public IFileStore getParent() {
if (path.equals(Path.ROOT)) {
return null;
}
return new WorkspaceFile(path.removeLastSegments(1));
}
/* (non-Javadoc)
* @see org.eclipse.core.filesystem.provider.FileStore#openInputStream(int, org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
public InputStream openInputStream(int options, IProgressMonitor monitor) throws CoreException {
ensureLocalFileStore();
if (localFileStore != null) {
return localFileStore.openInputStream(options, monitor);
}
Policy.error(EFS.ERROR_READ, NLS.bind(Messages.fileNotFound, path));
return null;
}
/* (non-Javadoc)
* @see org.eclipse.core.filesystem.provider.FileStore#toURI()
*/
@Override
public URI toURI() {
try {
return new URI(WorkspaceFileSystem.SCHEME_WORKSPACE, path.toPortableString(), null);
} catch (URISyntaxException e) {
IdeLog.logError(CoreIOPlugin.getDefault(), e.getLocalizedMessage(), e);
}
return null;
}
/* (non-Javadoc)
* @see org.eclipse.core.filesystem.provider.FileStore#copy(org.eclipse.core.filesystem.IFileStore, int, org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
public void copy(IFileStore destination, int options, IProgressMonitor monitor) throws CoreException {
if (CloakingUtils.isFileCloaked(this)) {
// this file is cloaked from transferring
return;
}
ensureLocalFileStore();
if (localFileStore != null) {
localFileStore.copy(destination, options, monitor);
} else {
super.copy(destination, options, monitor);
}
}
/* (non-Javadoc)
* @see org.eclipse.core.filesystem.provider.FileStore#delete(int, org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
public void delete(int options, IProgressMonitor monitor) throws CoreException {
ensureLocalFileStore();
if (localFileStore != null) {
localFileStore.delete(options, monitor);
}
}
/* (non-Javadoc)
* @see org.eclipse.core.filesystem.provider.FileStore#getFileStore(org.eclipse.core.runtime.IPath)
*/
@Override
public IFileStore getFileStore(IPath path) {
return new WorkspaceFile(this.path.append(path));
}
/* (non-Javadoc)
* @see org.eclipse.core.filesystem.provider.FileStore#getFileSystem()
*/
@Override
public IFileSystem getFileSystem() {
return WorkspaceFileSystem.getInstance();
}
/* (non-Javadoc)
* @see org.eclipse.core.filesystem.provider.FileStore#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (!(obj instanceof WorkspaceFile)) {
return false;
}
return path.equals(((WorkspaceFile) obj).path);
}
/* (non-Javadoc)
* @see org.eclipse.core.filesystem.provider.FileStore#hashCode()
*/
@Override
public int hashCode() {
return path.hashCode();
}
/* (non-Javadoc)
* @see org.eclipse.core.filesystem.provider.FileStore#mkdir(int, org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
public IFileStore mkdir(int options, IProgressMonitor monitor) throws CoreException {
ensureLocalFileStore(true);
if (localFileStore != null) {
try {
localFileStore.mkdir(options, monitor);
} finally {
localFileStore = null;
}
}
return this;
}
/* (non-Javadoc)
* @see org.eclipse.core.filesystem.provider.FileStore#move(org.eclipse.core.filesystem.IFileStore, int, org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
public void move(IFileStore destination, int options, IProgressMonitor monitor) throws CoreException {
if (!(destination instanceof WorkspaceFile)) {
ensureLocalFileStore();
if (localFileStore != null) {
localFileStore.move(destination, options, monitor);
return;
}
Policy.error(EFS.ERROR_NOT_EXISTS, NLS.bind(Messages.fileNotFound, path));
}
monitor = Policy.monitorFor(monitor);
monitor.beginTask(NLS.bind(Messages.moving, destination.toString()), 100);
WorkspaceFile destinationFile = (WorkspaceFile) destination;
try {
ensureResource();
if (resource == null) {
Policy.error(EFS.ERROR_NOT_EXISTS, NLS.bind(Messages.fileNotFound, path));
}
IResource destinationResource = (IResource) destinationFile.getAdapter(IResource.class);
if (destinationResource == null) {
if (resource instanceof IContainer) {
destinationResource = workspaceRoot.getFolder(destinationFile.path);
} else {
destinationResource = workspaceRoot.getFile(destinationFile.path);
}
}
boolean sourceEqualsDest = resource.equals(destinationResource);
boolean overwrite = (options & EFS.OVERWRITE) != 0;
if (!sourceEqualsDest && !overwrite && destinationResource.exists()) {
Policy.error(EFS.ERROR_EXISTS, NLS.bind(Messages.fileExists, destinationResource.getFullPath()));
}
try {
resource.move(destinationResource.getFullPath(), true, Policy.subMonitorFor(monitor, 100));
} catch (CoreException e) {
Policy.error(EFS.ERROR_WRITE, NLS.bind(Messages.failedMove, toString(), destination.toString()), e);
}
} finally {
monitor.done();
}
}
/* (non-Javadoc)
* @see org.eclipse.core.filesystem.provider.FileStore#putInfo(org.eclipse.core.filesystem.IFileInfo, int, org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
public void putInfo(IFileInfo info, int options, IProgressMonitor monitor) throws CoreException {
// passing "true" because the file store doesn't need to be physically exist when doing putInfo()
ensureLocalFileStore(true);
if (localFileStore != null) {
localFileStore.putInfo(info, options, monitor);
} else {
Policy.error(EFS.ERROR_NOT_EXISTS, NLS.bind(Messages.fileNotFound, path));
}
}
/* (non-Javadoc)
* @see org.eclipse.core.filesystem.provider.FileStore#toLocalFile(int, org.eclipse.core.runtime.IProgressMonitor)
*/
public File toLocalFile(int options, IProgressMonitor monitor) throws CoreException {
ensureLocalFileStore();
if (localFileStore != null) {
return localFileStore.toLocalFile(options, monitor);
}
return null;
}
/* (non-Javadoc)
* @see org.eclipse.core.filesystem.provider.FileStore#openOutputStream(int, org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
public OutputStream openOutputStream(int options, IProgressMonitor monitor) throws CoreException {
ensureLocalFileStore(true);
if (localFileStore != null) {
return localFileStore.openOutputStream(options, monitor);
}
return null;
}
/* (non-Javadoc)
* @see org.eclipse.core.filesystem.provider.FileStore#toString()
*/
@Override
public String toString() {
return path.toString();
}
private void ensureResource() throws CoreException {
if(!refreshed) {
workspaceRoot.refreshLocal(IResource.DEPTH_INFINITE, null);
refreshed = true;
}
if (resource != null && (
!resource.isSynchronized(IResource.DEPTH_ZERO)
|| !resource.exists())) {
resource = null;
localFileStore = null;
}
if (resource == null) {
IResource res = workspaceRoot;
for (String name : path.segments()) {
if (res instanceof IContainer) {
IContainer container = (IContainer) res;
// [IM] commented out as it proves too expensive to compute on the fly. Needs revisiting.
// if (!container.isSynchronized(IResource.DEPTH_ONE)) {
// container.refreshLocal(IResource.DEPTH_ONE, new NullProgressMonitor());
// }
res = container.findMember(name);
} else {
res = null;
break;
}
}
resource = res;
}
}
private void ensureLocalFileStore() throws CoreException {
ensureLocalFileStore(false);
}
private void ensureLocalFileStore(boolean force) throws CoreException {
ensureResource();
if (localFileStore == null) {
if (resource != null && resource.exists()) {
localFileStore = new LocalFile(resource.getLocation().toFile());
} else if (force) {
IResource parent = workspaceRoot;
IPath relativePath = null;
for (int i = 0; i < path.segmentCount(); ++i) {
if (parent instanceof IContainer) {
IResource member = ((IContainer) parent).findMember(path.segment(i));
if (member != null) {
parent = member;
} else {
relativePath = path.removeFirstSegments(i);
break;
}
} else {
parent = null;
break;
}
}
if (parent != null & relativePath != null) {
localFileStore = new LocalFile(parent.getLocation().toFile()).getFileStore(relativePath);
}
}
}
}
public static IFileStore fromLocalFile(File file) {
IResource resource = null;
if (file.isDirectory()) {
resource = workspaceRoot.getContainerForLocation(Path.fromOSString(file.getAbsolutePath()));
} else if (file.isFile()) {
resource = workspaceRoot.getFileForLocation(Path.fromOSString(file.getAbsolutePath()));
}
if (resource != null) {
return new WorkspaceFile(resource);
}
return null;
}
}