//------------------------------------------------------------------------------
// Copyright (c) 2005, 2006 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 implementation
//------------------------------------------------------------------------------
package org.eclipse.epf.persistence;
import java.io.File;
import java.security.AccessController;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.core.internal.resources.ResourceException;
import org.eclipse.core.internal.resources.ResourceStatus;
import org.eclipse.core.internal.utils.Messages;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceStatus;
import org.eclipse.core.resources.IWorkspace;
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.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.CommonPlugin;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
import org.eclipse.epf.common.utils.FileUtil;
import org.eclipse.epf.persistence.util.PersistenceResources;
import org.eclipse.epf.services.IFileManager;
import org.eclipse.epf.services.Services;
import org.eclipse.epf.uma.MethodElement;
import org.eclipse.epf.uma.util.UmaUtil;
import org.eclipse.osgi.util.NLS;
import sun.security.action.GetPropertyAction;
/**
* Implementation class for IFileManager.
*
* @author Phong Nguyen Le
* @since 1.0
*/
public class FileManager implements IFileManager {
public static final String PLUGIN_ID = FileManager.class.getPackage()
.getName();
private static FileManager instance = null;
private static String tmpdir;
public static String getTempDir() {
if (tmpdir == null) {
GetPropertyAction a = new GetPropertyAction("java.io.tmpdir"); //$NON-NLS-1$
tmpdir = ((String) AccessController.doPrivileged(a));
}
return tmpdir;
}
private boolean validateEditInitialized = false;
public static final FileManager getInstance() {
if (instance == null) {
synchronized (FileManager.class) {
if (instance == null) {
instance = new FileManager();
}
}
}
return instance;
}
protected FileManager() {
}
public static IResource getResourceForLocation(String location) {
File file = new File(location);
if (!file.exists()) {
return null;
}
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
IPath path = new Path(location);
IResource resource;
if (file.isFile()) {
resource = workspaceRoot.getFileForLocation(path);
if (resource == null) {
IResource parentResource = getResourceForLocation(file
.getParent());
if (parentResource != null) {
try {
parentResource.refreshLocal(IResource.DEPTH_ONE, null);
} catch (CoreException e) {
// CommonPlugin.INSTANCE.log(e);
}
resource = workspaceRoot.getFileForLocation(path);
}
}
} else {
resource = workspaceRoot.getContainerForLocation(path);
}
return resource;
}
public static boolean refresh(IResource resource) throws CoreException {
if (!resource.exists()) {
ArrayList foldersToRefresh = new ArrayList();
IContainer container;
for (container = resource.getParent(); !container.exists(); container = container
.getParent()) {
foldersToRefresh.add(0, container);
}
if (container.exists()) {
container.refreshLocal(IResource.DEPTH_ONE, null);
}
if (!foldersToRefresh.isEmpty()) {
for (Iterator iter = foldersToRefresh.iterator(); iter
.hasNext();) {
IFolder folder = (IFolder) iter.next();
if (folder.exists()) {
folder.refreshLocal(IResource.DEPTH_ONE, null);
} else {
return false;
}
}
}
}
resource.refreshLocal(IResource.DEPTH_ONE, null);
return true;
}
/**
* Refreshes file or directory with given local file system
* <code>path</code>
*
* @param path
* local file system path
* @return
* @throws CoreException
*/
private static boolean refresh(String path) throws CoreException {
IResource resource = getResourceForLocation(path);
if (resource != null) {
return refresh(resource);
}
return false;
}
public boolean refresh(Resource resource) {
try {
return refresh(toFileString(resource.getURI()));
} catch (CoreException e) {
// CommonPlugin.INSTANCE.log(e);
return false;
}
}
public boolean move(String oldPath, String newPath) {
return move(oldPath, newPath, false);
}
public boolean move(String oldPath, String newPath,
boolean forceRemoveSource) {
try {
refresh(oldPath);
IResource resource = null;
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace()
.getRoot();
// create the folders of the destination if they did not exist
IPath destPath = new Path(newPath);
if (new File(oldPath).isFile()) {
resource = workspaceRoot.getFileForLocation(destPath);
if(resource == null) {
resource = workspaceRoot.getContainerForLocation(destPath);
}
} else {
resource = workspaceRoot.getContainerForLocation(destPath);
if(resource == null) {
resource = workspaceRoot.getFileForLocation(destPath);
}
}
if(resource != null) {
if (resource.exists()) {
resource.refreshLocal(IResource.DEPTH_ZERO, null);
if(resource.exists()) {
throw new MultiFileIOException(NLS.bind(
PersistenceResources.moveError_msg, oldPath, newPath));
}
}
ArrayList foldersToCreate = new ArrayList();
IContainer container;
for (container = resource.getParent(); !container.exists(); container = container
.getParent()) {
foldersToCreate.add(0, container);
}
if (!foldersToCreate.isEmpty()) {
container.refreshLocal(IResource.DEPTH_ONE, null);
for (Iterator iter = foldersToCreate.iterator(); iter.hasNext();) {
IFolder folder = (IFolder) iter.next();
if (!folder.exists()) {
folder.create(true, true, null);
} else {
folder.refreshLocal(IResource.DEPTH_ONE, null);
}
}
}
destPath = resource.getFullPath();
}
else if(Platform.getLocation().isPrefixOf(destPath)) {
destPath = new Path(destPath.toOSString().substring(Platform.getLocation().toOSString().length()));
}
IPath path = new Path(oldPath);
IFile file = workspaceRoot.getFileForLocation(path);
if (file != null && file.exists()) {
resource = file;
} else {
resource = workspaceRoot.getContainerForLocation(path);
}
if (resource != null) {
try {
resource.move(destPath, true, null);
} catch (ResourceException e) {
PersistencePlugin.getDefault().getLog().log(e.getStatus());
if (forceRemoveSource) {
throw e;
}
boolean failed = false;
// handle situation when Eclipse moves file/directory by
// copying it to destination then deleting the source
// but deletion failed
IStatus[] statuses = e.getStatus().getChildren();
for (int i = 0; i < statuses.length; i++) {
IStatus status = statuses[i];
if (status.getCode() == IResourceStatus.FAILED_DELETE_LOCAL
&& status.getMessage() == Messages.localstore_deleteProblem) {
String msg = MessageFormat
.format(
"Warning while moving ''{0}'' to ''{1}'': {2}", new Object[] { oldPath, newPath, status.getMessage() }); //$NON-NLS-1$
PersistencePlugin.getDefault().getLogger().logWarning(msg);
} else {
failed = true;
}
}
if (failed || !new File(newPath).exists()) {
return false;
}
}
return true;
}
} catch (CoreException e) {
PersistencePlugin.getDefault().getLogger().logError(e);
if (MultiFileSaveUtil.DEBUG) {
e.printStackTrace();
}
}
return false;
}
public boolean rename(File oldFile, File newFile) {
return move(oldFile.getAbsolutePath(), newFile.getAbsolutePath());
}
public void deleteResource(String path, IProgressMonitor monitor)
throws CoreException {
// no need to refresh the whole tree from specified path
// getResourceForLocation() refreshes resource in a more efficient way
//
// IWorkspaceRoot workspaceRoot =
// ResourcesPlugin.getWorkspace().getRoot();
// try {
// workspaceRoot.refreshLocal(IResource.DEPTH_INFINITE, monitor);
// } catch (CoreException e1) {
// e1.printStackTrace();
// }
IResource resource = getResourceForLocation(path);
if (resource != null) {
resource.delete(true, monitor);
}
}
public boolean delete(String path) {
try {
deleteResource(path, null);
return true;
} catch (CoreException e) {
CommonPlugin.INSTANCE.log(e);
if (MultiFileSaveUtil.DEBUG) {
e.printStackTrace();
}
}
return false;
}
private static boolean fromCC(IStatus status) {
String pluginId = status.getPlugin();
return pluginId != null
&& pluginId.toLowerCase().indexOf("clearcase") != -1; //$NON-NLS-1$
}
public IStatus checkModify(String[] paths, Object context) {
IStatus status = null;
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IFile[] files = new IFile[paths.length];
ArrayList<String> notFoundFiles = new ArrayList<String>();
for (int i = 0; i < paths.length; i++) {
String path = paths[i];
try {
path = new File(path).getCanonicalPath();
refresh(path);
} catch (Exception e) {
PersistencePlugin.getDefault().getLogger().logError(e);
}
IFile file = workspace.getRoot().getFileForLocation(new Path(path));
if (file == null) {
notFoundFiles.add(path);
} else {
files[i] = file;
}
}
if (!notFoundFiles.isEmpty()) {
return new Status(IStatus.WARNING, PLUGIN_ID, IStatus.WARNING, NLS
.bind(PersistenceResources.fileNotFoundError_msg,
notFoundFiles), null);
}
if (!validateEditInitialized) {
// status = workspace.validateEdit(files, context);
status = FileUtil.validateEdit(workspace, files, context);
validateEditInitialized = true;
if (status.isOK()) {
// double-check after initialization
//
// status = workspace.validateEdit(files, context);
status = FileUtil.validateEdit(workspace, files, context);
}
} else {
// status = workspace.validateEdit(files, context);
status = FileUtil.validateEdit(workspace, files, context);
}
if (status.isOK()) {
MultiStatus multiStatus = new MultiStatus(PLUGIN_ID,
IStatus.OK, PersistenceResources.modifyFilesError_msg,
null);
// some version control provider still returns OK status even though
// user cancelled the check out
// double-check here again to make sure the file is not read-only
//
for (int i = 0; i < files.length; i++) {
IFile file = files[i];
try {
file.refreshLocal(IResource.DEPTH_ZERO, null);
} catch (CoreException e) {
CommonPlugin.INSTANCE.log(e);
}
if (file.isReadOnly()) {
String localPath = file.getLocation().toOSString();
String msg = MessageFormat.format(
PersistenceResources.FileManager_fileReadOnly,
new Object[] { localPath });
multiStatus.add(new ResourceStatus(IStatus.ERROR, 0, file
.getFullPath(), msg, null));
}
}
if(!multiStatus.isOK()) {
return multiStatus;
}
} else {
// hack for clearcase
if (fromCC(status)) {
String msg = PersistenceResources.modifyFilesError_msg;
MultiStatus multiStatus = new MultiStatus(PLUGIN_ID, status
.getCode(), msg, null);
multiStatus.add(status);
return multiStatus;
}
}
// convert workspace path to local file system path
if (status instanceof MultiStatus) {
MultiStatus ms = (MultiStatus) status;
for (int i = 0; i < ms.getChildren().length; i++) {
IStatus childStatus = ms.getChildren()[i];
ms.getChildren()[i] = toStatusWithLocalPath(childStatus);
}
}
else {
status = toStatusWithLocalPath(status);
}
return status;
}
private static IStatus toStatusWithLocalPath(IStatus status) {
if (status instanceof IResourceStatus
&& status.getCode() == IResourceStatus.READ_ONLY_LOCAL) {
IResourceStatus resourceStatus = ((IResourceStatus) status);
IPath path = resourceStatus.getPath();
IFile file = ResourcesPlugin.getWorkspace().getRoot()
.getFile(path);
String localPath = file.getLocation().toOSString();
String msg = MessageFormat.format(
PersistenceResources.FileManager_fileReadOnly,
new Object[] { localPath });
return new ResourceStatus(status
.getSeverity(), status.getCode(),
resourceStatus.getPath(), msg, status
.getException());
}
return status;
}
/**
* @see org.eclipse.epf.services.IFileManager#checkModify(java.lang.String,
* java.lang.Object)
*/
public IStatus checkModify(String path, Object context) {
return checkModify(new String[] { path }, context);
}
/**
* Checks if the given path is team-private file or folder
*
* @param path
* @return
*/
public boolean isTeamPrivate(String path) {
IResource resource = getResourceForLocation(path);
return resource != null && resource.isTeamPrivateMember();
}
/**
* Finds the file corresponding to the specified URI, using a URI converter
* if necessary (and provided) to normalize it.
*
* @param uri a URI
* @param converter an optional URI converter (may be <code>null</code>)
*
* @return the file, if available in the workspace
*/
public static IFile getFile(URI uri, URIConverter converter) {
IFile result = null;
if ("platform".equals(uri.scheme()) && (uri.segmentCount() > 2)) { //$NON-NLS-1$
if ("resource".equals(uri.segment(0))) { //$NON-NLS-1$
IPath path = new Path(URI.decode(uri.path())).removeFirstSegments(1);
result = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
}
} else if (uri.isFile() && !uri.isRelative()) {
result = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(
new Path(uri.toFileString()));
} else {
// normalize, to see whether may we can resolve it this time
if (converter != null) {
URI normalized = converter.normalize(uri);
if (!uri.equals(normalized)) {
// recurse on the new URI
result = getFile(normalized, converter);
}
}
}
return result;
}
public static String toFileString(URI uri, URIConverter converter) {
if(uri.isFile()) {
return uri.toFileString();
}
IFile file = getFile(uri, converter);
return file != null ? file.getLocation().toOSString() : null;
}
public static String toFileString(URI uri) {
return toFileString(uri, null);
}
public static class FileInfo implements IFileInfo {
private IFile file;
private FileInfo(IFile file) {
this.file = file;
}
public long getModificationStamp() {
return file.getModificationStamp();
}
public boolean isSynchronized() {
return file.isSynchronized(IResource.DEPTH_ZERO);
}
public File getFile() {
IPath loc = file.getLocation();
return loc != null ? file.getLocation().toFile() : null;
}
}
public IFileInfo getFileInfo(Resource resource) {
IFile file = WorkspaceSynchronizer.getFile(resource);
return file != null ? new FileInfo(file) : null;
}
public static boolean copyFile(File srcFile, File tgtFile) {
boolean b = FileUtil.copyFile(srcFile, tgtFile) ;
if (b) {
IResource wsResource = tgtFile == null ? null : FileManager.getResourceForLocation(tgtFile.getAbsolutePath());
if(wsResource != null) {
try {
FileManager.refresh(wsResource);
}
catch(Exception e) {
}
}
}
return b;
}
public static IStatus checkModifyPathList(List<String> modifiedFiles, Object context) {
if (modifiedFiles == null || modifiedFiles.isEmpty()) {
return Status.OK_STATUS;
}
String[] paths = new String[modifiedFiles.size()];
modifiedFiles.toArray(paths);
IFileManager fileMgr = Services.getFileManager();
IStatus status = fileMgr.checkModify(paths, context);
return status;
}
public static IStatus checkModifyResources(Set<Resource> resources, Object context) {
List<String> modifiedFiles = UmaUtil.getResourceFilePaths(resources);
IStatus status = checkModifyPathList(modifiedFiles, context);
return status;
}
public static IStatus checkModifyElements(Set<MethodElement> elements, Object context) {
Set<Resource> resources = UmaUtil.getElementResources(elements);
return checkModifyResources(resources, context);
}
}