/******************************************************************************* * Copyright (c) 2012-2015 Codenvy, S.A. * 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: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.core.internal.resources; import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.ForbiddenException; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.project.server.FileEntry; import org.eclipse.che.api.project.server.FolderEntry; import org.eclipse.che.api.project.server.ProjectManager; import org.eclipse.che.api.project.server.VirtualFileEntry; import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl; import org.eclipse.che.core.internal.utils.Policy; import org.eclipse.core.commands.operations.IUndoContext; import org.eclipse.core.commands.operations.UndoContext; import org.eclipse.core.internal.resources.ICoreConstants; import org.eclipse.core.internal.resources.OS; import org.eclipse.core.internal.resources.ResourceException; import org.eclipse.core.internal.resources.WorkspaceDescription; import org.eclipse.core.internal.utils.Messages; import org.eclipse.core.resources.IBuildConfiguration; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFilterMatcherDescriptor; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IPathVariableManager; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IProjectNatureDescriptor; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IResourceRuleFactory; import org.eclipse.core.resources.IResourceStatus; import org.eclipse.core.resources.ISaveParticipant; import org.eclipse.core.resources.ISavedState; import org.eclipse.core.resources.ISynchronizer; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceDescription; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.resources.team.TeamHook; import org.eclipse.core.runtime.Assert; 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.OperationCanceledException; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Plugin; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.osgi.util.NLS; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.InputStream; import java.net.URI; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.eclipse.che.api.project.server.Constants.CODENVY_DIR; /** * @author Evgen Vidolob */ public class Workspace implements IWorkspace { public static final boolean caseSensitive = new java.io.File("a").compareTo(new java.io.File("A")) != 0; //$NON-NLS-1$ //$NON-NLS-2$ private static final Logger LOG = LoggerFactory.getLogger(Workspace.class); protected final IWorkspaceRoot defaultRoot = new WorkspaceRoot(Path.ROOT, this); private final FolderEntry projectsRoot; /** * Work manager should never be accessed directly because accessor * asserts that workspace is still open. */ protected WorkManager _workManager; /** * The currently installed team hook. */ protected TeamHook teamHook = null; private String wsPath; private ProjectManager projectManager; private String wsId; /** * Scheduling rule factory. This field is null if the factory has not been used * yet. The accessor method should be used rather than accessing this field * directly. */ private IResourceRuleFactory ruleFactory; private IUndoContext undoContext = new UndoContext(); public Workspace(String path, ProjectManager projectManager, String wsId) { this.wsPath = path; this.projectManager = projectManager; try { projectsRoot = projectManager.getProjectsRoot(wsId); } catch (ServerException | NotFoundException e) { throw new IllegalStateException(e); } this.wsId = wsId; _workManager = new WorkManager(this); _workManager.startup(null); _workManager.postWorkspaceStartup(); } public static WorkspaceDescription defaultWorkspaceDescription() { return new WorkspaceDescription("Workspace"); //$NON-NLS-1$ } private static boolean deleteDirectory(java.io.File directory) { if (directory.exists()) { java.io.File[] files = directory.listFiles(); if (null != files) { for (int i = 0; i < files.length; i++) { if (files[i].isDirectory()) { deleteDirectory(files[i]); } else { files[i].delete(); } } } } return (directory.delete()); } public String getAbsoluteWorkspacePath() { return wsPath; } public Resource newResource(IPath path, int type) { String message; switch (type) { case IResource.FOLDER: if (path.segmentCount() < ICoreConstants.MINIMUM_FOLDER_SEGMENT_LENGTH) { message = "Path must include project and resource name: " + path.toString(); //$NON-NLS-1$ Assert.isLegal(false, message); } return new Folder(path.makeAbsolute(), this); case IResource.FILE: if (path.segmentCount() < ICoreConstants.MINIMUM_FILE_SEGMENT_LENGTH) { message = "Path must include project and resource name: " + path.toString(); //$NON-NLS-1$ Assert.isLegal(false, message); } return new File(path.makeAbsolute(), this); case IResource.PROJECT: return (Resource)getRoot().getProject(path.toOSString()); case IResource.ROOT: return (Resource)getRoot(); } Assert.isLegal(false); // will never get here because of assertion. return null; } @Override public void addResourceChangeListener(IResourceChangeListener listener) { //TODO // throw new UnsupportedOperationException(); } @Override public void addResourceChangeListener(IResourceChangeListener listener, int eventMask) { // throw new UnsupportedOperationException(); //TODO } @Override public ISavedState addSaveParticipant(Plugin plugin, ISaveParticipant iSaveParticipant) throws CoreException { throw new UnsupportedOperationException(); } @Override public ISavedState addSaveParticipant(String s, ISaveParticipant iSaveParticipant) throws CoreException { throw new UnsupportedOperationException(); } @Override public void build(int i, IProgressMonitor iProgressMonitor) throws CoreException { throw new UnsupportedOperationException(); } @Override public void build(IBuildConfiguration[] iBuildConfigurations, int i, boolean b, IProgressMonitor iProgressMonitor) throws CoreException { throw new UnsupportedOperationException(); } @Override public void checkpoint(boolean b) { // throw new UnsupportedOperationException(); } @Override public IProject[][] computePrerequisiteOrder(IProject[] iProjects) { throw new UnsupportedOperationException(); } @Override public ProjectOrder computeProjectOrder(IProject[] iProjects) { throw new UnsupportedOperationException(); } @Override public IStatus copy(IResource[] iResources, IPath iPath, boolean b, IProgressMonitor iProgressMonitor) throws CoreException { throw new UnsupportedOperationException(); } @Override public IStatus copy(IResource[] iResources, IPath iPath, int i, IProgressMonitor iProgressMonitor) throws CoreException { throw new UnsupportedOperationException(); } @Override public IStatus delete(IResource[] resources, boolean force, IProgressMonitor monitor) throws CoreException { int updateFlags = force ? IResource.FORCE : IResource.NONE; updateFlags |= IResource.KEEP_HISTORY; return delete(resources, updateFlags, monitor); } @Override public IStatus delete(IResource[] resources, int updateFlags, IProgressMonitor monitor) throws CoreException { monitor = Policy.monitorFor(monitor); try { int opWork = Math.max(resources.length, 1); int totalWork = Policy.totalWork * opWork / Policy.opWork; String message = Messages.resources_deleting_0; monitor.beginTask(message, totalWork); message = Messages.resources_deleteProblem; MultiStatus result = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.INTERNAL_ERROR, message, null); if (resources.length == 0) return result; resources = resources.clone(); // to avoid concurrent changes to this array try { prepareOperation(getRoot(), monitor); beginOperation(true); for (int i = 0; i < resources.length; i++) { Policy.checkCanceled(monitor); Resource resource = (Resource)resources[i]; if (resource == null) { monitor.worked(1); continue; } try { resource.delete(updateFlags, Policy.subMonitorFor(monitor, 1)); } catch (CoreException e) { // Don't really care about the exception unless the resource is still around. ResourceInfo info = resource.getResourceInfo(false, false); if (resource.exists(resource.getFlags(info), false)) { message = NLS.bind(Messages.resources_couldnotDelete, resource.getFullPath()); result.merge(new org.eclipse.core.internal.resources.ResourceStatus(IResourceStatus.FAILED_DELETE_LOCAL, resource.getFullPath(), message)); result.merge(e.getStatus()); } } } if (result.matches(IStatus.ERROR)) throw new ResourceException(result); return result; } catch (OperationCanceledException e) { getWorkManager().operationCanceled(); throw e; } finally { endOperation(getRoot(), true, Policy.subMonitorFor(monitor, totalWork - opWork)); } } finally { monitor.done(); } } @Override public void deleteMarkers(IMarker[] iMarkers) throws CoreException { throw new UnsupportedOperationException(); } @Override public void forgetSavedTree(String s) { throw new UnsupportedOperationException(); } @Override public IFilterMatcherDescriptor[] getFilterMatcherDescriptors() { throw new UnsupportedOperationException(); } @Override public IFilterMatcherDescriptor getFilterMatcherDescriptor(String s) { throw new UnsupportedOperationException(); } @Override public IProjectNatureDescriptor[] getNatureDescriptors() { throw new UnsupportedOperationException(); } @Override public IProjectNatureDescriptor getNatureDescriptor(String s) { throw new UnsupportedOperationException(); } @Override public Map<IProject, IProject[]> getDanglingReferences() { throw new UnsupportedOperationException(); } @Override public IWorkspaceDescription getDescription() { WorkspaceDescription workingCopy = defaultWorkspaceDescription(); // description.copyTo(workingCopy); return workingCopy; } @Override public void setDescription(IWorkspaceDescription iWorkspaceDescription) throws CoreException { throw new UnsupportedOperationException(); } @Override public IWorkspaceRoot getRoot() { return defaultRoot; } @Override public IResourceRuleFactory getRuleFactory() { //note that the rule factory is created lazily because it //requires loading the teamHook extension if (ruleFactory == null) ruleFactory = new Rules(this); return ruleFactory; } @Override public ISynchronizer getSynchronizer() { throw new UnsupportedOperationException(); } @Override public boolean isAutoBuilding() { throw new UnsupportedOperationException(); } @Override public boolean isTreeLocked() { //todo return false; } @Override public IProjectDescription loadProjectDescription(IPath iPath) throws CoreException { throw new UnsupportedOperationException(); } @Override public IProjectDescription loadProjectDescription(InputStream inputStream) throws CoreException { throw new UnsupportedOperationException(); } @Override public IStatus move(IResource[] iResources, IPath iPath, boolean b, IProgressMonitor iProgressMonitor) throws CoreException { throw new UnsupportedOperationException(); } @Override public IStatus move(IResource[] iResources, IPath iPath, int i, IProgressMonitor iProgressMonitor) throws CoreException { throw new UnsupportedOperationException(); } @Override public IBuildConfiguration newBuildConfig(String s, String s1) { throw new UnsupportedOperationException(); } @Override public IProjectDescription newProjectDescription(String s) { throw new UnsupportedOperationException(); } @Override public void removeResourceChangeListener(IResourceChangeListener listener) { // throw new UnsupportedOperationException(); //TODO } @Override public void removeSaveParticipant(Plugin plugin) { throw new UnsupportedOperationException(); } @Override public void removeSaveParticipant(String s) { throw new UnsupportedOperationException(); } /** * Called before checking the pre-conditions of an operation. Optionally supply * a scheduling rule to determine when the operation is safe to run. If a scheduling * rule is supplied, this method will block until it is safe to run. * * @param rule the scheduling rule that describes what this operation intends to modify. */ public void prepareOperation(ISchedulingRule rule, IProgressMonitor monitor) throws CoreException { try { //make sure autobuild is not running if it conflicts with this operation ISchedulingRule buildRule = getRuleFactory().buildRule(); // if (rule != null && buildRule != null && (rule.isConflicting(buildRule) || buildRule.isConflicting(rule))) // buildManager.interrupt(); } finally { getWorkManager().checkIn(rule, monitor); } // if (!isOpen()) { // String message = Messages.resources_workspaceClosed; // throw new ResourceException(IResourceStatus.OPERATION_FAILED, null, message, null); // } } /** * We should not have direct references to this field. All references should go through * this method. */ public WorkManager getWorkManager() throws CoreException { if (_workManager == null) { String message = Messages.resources_shutdown; throw new ResourceException(new ResourceStatus(IResourceStatus.INTERNAL_ERROR, null, message)); } return _workManager; } @Override public void run(IWorkspaceRunnable action, ISchedulingRule rule, int options, IProgressMonitor monitor) throws CoreException { monitor = Policy.monitorFor(monitor); try { monitor.beginTask("", Policy.totalWork); //$NON-NLS-1$ int depth = -1; boolean avoidNotification = (options & IWorkspace.AVOID_UPDATE) != 0; try { prepareOperation(rule, monitor); beginOperation(true); // if (avoidNotification) // avoidNotification = notificationManager.beginAvoidNotify(); depth = getWorkManager().beginUnprotected(); action.run(Policy.subMonitorFor(monitor, Policy.opWork, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK)); } catch (OperationCanceledException e) { getWorkManager().operationCanceled(); throw e; } finally { // if (avoidNotification) // notificationManager.endAvoidNotify(); if (depth >= 0) getWorkManager().endUnprotected(depth); endOperation(rule, false, Policy.subMonitorFor(monitor, Policy.endOpWork)); } } finally { monitor.done(); } } public void beginOperation(boolean createNewTree) throws CoreException { WorkManager workManager = getWorkManager(); workManager.incrementNestedOperations(); if (!workManager.isBalanced()) Assert.isTrue(false, "Operation was not prepared."); //$NON-NLS-1$ // if (workManager.getPreparedOperationDepth() > 1) { // if (createNewTree && tree.isImmutable()) // newWorkingTree(); // return; // } // // stash the current tree as the basis for this operation. // operationTree = tree; // if (createNewTree && tree.isImmutable()) // newWorkingTree(); } /** * End an operation (group of resource changes). * Notify interested parties that resource changes have taken place. All * registered resource change listeners are notified. If autobuilding is * enabled, a build is run. */ public void endOperation(ISchedulingRule rule, boolean build, IProgressMonitor monitor) throws CoreException { WorkManager workManager = getWorkManager(); //don't do any end operation work if we failed to check in if (workManager.checkInFailed(rule)) return; // This is done in a try finally to ensure that we always decrement the operation count // and release the workspace lock. This must be done at the end because snapshot // and "hasChanges" comparison have to happen without interference from other threads. boolean hasTreeChanges = false; boolean depthOne = false; try { workManager.setBuild(build); // if we are not exiting a top level operation then just decrement the count and return depthOne = workManager.getPreparedOperationDepth() == 1; // if (!(notificationManager.shouldNotify() || depthOne)) { // notificationManager.requestNotify(); // return; // } // do the following in a try/finally to ensure that the operation tree is nulled at the end // as we are completing a top level operation. try { // notificationManager.beginNotify(); // check for a programming error on using beginOperation/endOperation Assert.isTrue(workManager.getPreparedOperationDepth() > 0, "Mismatched begin/endOperation"); //$NON-NLS-1$ // At this time we need to re-balance the nested operations. It is necessary because // build() and snapshot() should not fail if they are called. workManager.rebalanceNestedOperations(); //find out if any operation has potentially modified the tree // hasTreeChanges = workManager.shouldBuild(); //double check if the tree has actually changed // if (hasTreeChanges) // hasTreeChanges = operationTree != null && ElementTree.hasChanges(tree, operationTree, ResourceComparator // .getBuildComparator(), true); // broadcastPostChange(); // // Request a snapshot if we are sufficiently out of date. // saveManager.snapshotIfNeeded(hasTreeChanges); } finally { // // make sure the tree is immutable if we are ending a top-level operation. // if (depthOne) { // tree.immutable(); // operationTree = null; // } else // newWorkingTree(); } } finally { workManager.checkOut(rule); } // if (depthOne) // buildManager.endTopLevel(hasTreeChanges); } @Override public void run(IWorkspaceRunnable action, IProgressMonitor monitor) throws CoreException { run(action, defaultRoot, IWorkspace.AVOID_UPDATE, monitor); } @Override public IStatus save(boolean b, IProgressMonitor iProgressMonitor) throws CoreException { throw new UnsupportedOperationException(); } @Override public String[] sortNatureSet(String[] strings) { throw new UnsupportedOperationException(); } @Override public IStatus validateEdit(IFile[] iFiles, Object o) { throw new UnsupportedOperationException(); } @Override public IStatus validateFiltered(IResource iResource) { throw new UnsupportedOperationException(); } @Override public IStatus validateLinkLocation(IResource iResource, IPath iPath) { throw new UnsupportedOperationException(); } @Override public IStatus validateLinkLocationURI(IResource iResource, URI uri) { throw new UnsupportedOperationException(); } @Override public IStatus validateName(String segment, int type) { String message; /* segment must not be null */ if (segment == null) { message = Messages.resources_nameNull; return new org.eclipse.core.internal.resources.ResourceStatus(IResourceStatus.INVALID_VALUE, null, message); } // cannot be an empty string if (segment.length() == 0) { message = Messages.resources_nameEmpty; return new org.eclipse.core.internal.resources.ResourceStatus(IResourceStatus.INVALID_VALUE, null, message); } /* test invalid characters */ char[] chars = OS.INVALID_RESOURCE_CHARACTERS; for (int i = 0; i < chars.length; i++) if (segment.indexOf(chars[i]) != -1) { message = NLS.bind(Messages.resources_invalidCharInName, String.valueOf(chars[i]), segment); return new org.eclipse.core.internal.resources.ResourceStatus(IResourceStatus.INVALID_VALUE, null, message); } /* test invalid OS names */ if (!OS.isNameValid(segment)) { message = NLS.bind(Messages.resources_invalidName, segment); return new org.eclipse.core.internal.resources.ResourceStatus(IResourceStatus.INVALID_VALUE, null, message); } return Status.OK_STATUS; } @Override public IStatus validateNatureSet(String[] strings) { throw new UnsupportedOperationException(); } @Override public IStatus validatePath(String path, int type) { /* path must not be null */ if (path == null) { String message = Messages.resources_pathNull; return new org.eclipse.core.internal.resources.ResourceStatus(IResourceStatus.INVALID_VALUE, null, message); } return validatePath(Path.fromOSString(path), type, false); } /** * Validates that the given workspace path is valid for the given type. If * <code>lastSegmentOnly</code> is true, it is assumed that all segments except * the last one have previously been validated. This is an optimization for validating * a leaf resource when it is known that the parent exists (and thus its parent path * must already be valid). */ public IStatus validatePath(IPath path, int type, boolean lastSegmentOnly) { String message; /* path must not be null */ if (path == null) { message = Messages.resources_pathNull; return new org.eclipse.core.internal.resources.ResourceStatus(IResourceStatus.INVALID_VALUE, null, message); } /* path must not have a device separator */ if (path.getDevice() != null) { message = NLS.bind(Messages.resources_invalidCharInPath, String.valueOf(IPath.DEVICE_SEPARATOR), path); return new org.eclipse.core.internal.resources.ResourceStatus(IResourceStatus.INVALID_VALUE, null, message); } /* path must not be the root path */ if (path.isRoot()) { message = Messages.resources_invalidRoot; return new org.eclipse.core.internal.resources.ResourceStatus(IResourceStatus.INVALID_VALUE, null, message); } /* path must be absolute */ if (!path.isAbsolute()) { message = NLS.bind(Messages.resources_mustBeAbsolute, path); return new org.eclipse.core.internal.resources.ResourceStatus(IResourceStatus.INVALID_VALUE, null, message); } /* validate segments */ int numberOfSegments = path.segmentCount(); if ((type & IResource.PROJECT) != 0) { if (numberOfSegments == ICoreConstants.PROJECT_SEGMENT_LENGTH) { return validateName(path.segment(0), IResource.PROJECT); } else if (type == IResource.PROJECT) { message = NLS.bind(Messages.resources_projectPath, path); return new org.eclipse.core.internal.resources.ResourceStatus(IResourceStatus.INVALID_VALUE, null, message); } } if ((type & (IResource.FILE | IResource.FOLDER)) != 0) { if (numberOfSegments < ICoreConstants.MINIMUM_FILE_SEGMENT_LENGTH) { message = NLS.bind(Messages.resources_resourcePath, path); return new org.eclipse.core.internal.resources.ResourceStatus(IResourceStatus.INVALID_VALUE, null, message); } int fileFolderType = type &= ~IResource.PROJECT; int segmentCount = path.segmentCount(); if (lastSegmentOnly) return validateName(path.segment(segmentCount - 1), fileFolderType); IStatus status = validateName(path.segment(0), IResource.PROJECT); if (!status.isOK()) return status; // ignore first segment (the project) for (int i = 1; i < segmentCount; i++) { status = validateName(path.segment(i), fileFolderType); if (!status.isOK()) return status; } return Status.OK_STATUS; } message = NLS.bind(Messages.resources_invalidPath, path); return new org.eclipse.core.internal.resources.ResourceStatus(IResourceStatus.INVALID_VALUE, null, message); } @Override public IStatus validateProjectLocation(IProject iProject, IPath iPath) { throw new UnsupportedOperationException(); } @Override public IStatus validateProjectLocationURI(IProject iProject, URI uri) { throw new UnsupportedOperationException(); } @Override public IPathVariableManager getPathVariableManager() { throw new UnsupportedOperationException(); } @Override public Object getAdapter(Class aClass) { if (aClass == IUndoContext.class) { return undoContext; } throw new UnsupportedOperationException(); } public java.io.File getFile(IPath path) { return new java.io.File(wsPath, path.toOSString()); } public ResourceInfo getResourceInfo(IPath path) { try { VirtualFileEntry child = projectsRoot.getChild(path.toOSString()); if (child != null) { return newElement(getType(child)); } return null; } catch (ForbiddenException | ServerException e) { LOG.error(e.getMessage(), e); return null; } } private int getType(VirtualFileEntry file) { if (file.isFile()) { return IResource.FILE; } else { try { FolderEntry folder = (FolderEntry)file; if (folder.getChild(CODENVY_DIR) != null /*projectManager.isProjectFolder(folder)*/) { return IResource.PROJECT; } else { return IResource.FOLDER; } } catch (ServerException | ForbiddenException e) { LOG.error(e.getMessage(), e); return IResource.FOLDER; } } } /** * Create and return a new tree element of the given type. */ protected ResourceInfo newElement(int type) { ResourceInfo result = null; switch (type) { case IResource.FILE: case IResource.FOLDER: result = new ResourceInfo(type); break; case IResource.PROJECT: result = new ResourceInfo(type); break; case IResource.ROOT: result = new ResourceInfo(type); break; } return result; } public IResource[] getChildren(IPath path) { try { VirtualFileEntry parent = projectsRoot.getChild(path.toOSString()); if (parent != null && parent.isFolder()) { FolderEntry folder = (FolderEntry)parent; List<VirtualFileEntry> children = folder.getChildren(); if (!children.isEmpty()) { IResource[] resources = new IResource[children.size()]; for (int i = 0; i < children.size(); i++) { VirtualFileEntry child = children.get(i); IPath iPath = new Path(child.getPath()); resources[i] = newResource(iPath, getType(child)); } resources = Arrays.stream(resources).sorted((o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName())).toArray( IResource[]::new); return resources; } } } catch (ForbiddenException | ServerException e) { LOG.error(e.getMessage(), e); } return ICoreConstants.EMPTY_RESOURCE_ARRAY; } public void createResource(IResource resource, int updateFlags) throws CoreException { try { IPath path = resource.getFullPath(); switch (resource.getType()) { case IResource.FILE: String newName = path.lastSegment(); VirtualFileEntry child = projectsRoot.getChild(path.removeLastSegments(1).toOSString()); FolderEntry entry = (FolderEntry)child; entry.createFile(newName, new byte[0]); break; case IResource.FOLDER: projectsRoot.createFolder(path.toOSString()); break; case IResource.PROJECT: projectManager.createProject(wsId, resource.getName(), new ProjectConfigImpl(), new HashMap<>()); break; default: throw new UnsupportedOperationException(); } } catch (ForbiddenException | ConflictException | ServerException | NotFoundException e) { throw new CoreException(new Status(0, ResourcesPlugin.getPluginId(), e.getMessage(), e)); } } public void setFileContent(File file, InputStream content) { try { VirtualFileEntry child = projectsRoot.getChild(file.getFullPath().toOSString()); if (child.isFile()) { FileEntry f = (FileEntry)child; f.updateContent(content); } } catch (ForbiddenException | ServerException e) { ResourcesPlugin.log(e); } } public TeamHook getTeamHook() { // default to use Core's implementation //create anonymous subclass because TeamHook is abstract if (teamHook == null) teamHook = new TeamHook() { // empty }; return teamHook; } public void delete(Resource resource) { try { projectManager.delete(wsId, resource.getFullPath().toOSString()); } catch (ServerException | ForbiddenException | ConflictException | NotFoundException e) { LOG.error(e.getMessage(), e); } } void write(File file, InputStream content, int updateFlags, boolean append, IProgressMonitor monitor) throws CoreException { try { VirtualFileEntry child = projectsRoot.getChild(file.getFullPath().toOSString()); if (child == null) { projectsRoot.createFile(file.getFullPath().toOSString(), content); } else { FileEntry fileEntry = (FileEntry)child; fileEntry.updateContent(content); } } catch (ForbiddenException | ConflictException | ServerException e) { throw new CoreException(new Status(0, "", e.getMessage(), e)); } } public void standardMoveFile(IFile file, IFile destination, int updateFlags, IProgressMonitor monitor) throws CoreException { VirtualFileEntry child = null; try { child = projectsRoot.getChild(file.getFullPath().toOSString()); if (destination.getName().equals(file.getName())) { child.moveTo(destination.getFullPath().removeLastSegments(1).toOSString()); } else { child.moveTo(destination.getFullPath().removeLastSegments(1).toOSString(), destination.getName(), true); } } catch (ForbiddenException | ServerException | NotFoundException | ConflictException e) { throw new CoreException( new Status(IStatus.ERROR, "", "Can't move file: " + file.getFullPath() + " to: " + destination.getFullPath(), e)); } } public void standardMoveFolder(IFolder folder, IFolder destination, int updateFlags, IProgressMonitor monitor) throws CoreException { VirtualFileEntry child = null; try { child = projectsRoot.getChild(folder.getFullPath().toOSString()); if (destination.getName().equals(folder.getName())) { child.moveTo(destination.getFullPath().removeLastSegments(1).toOSString()); } else { child.moveTo(destination.getFullPath().removeLastSegments(1).toOSString(), destination.getName(), true); } } catch (ForbiddenException | NotFoundException | ServerException | ConflictException e) { throw new CoreException( new Status(IStatus.ERROR, "", "Can't move folder: " + folder.getFullPath() + " to: " + destination.getFullPath(), e)); } } public void standardMoveProject(IProject project, IProjectDescription description, int updateFlags, IProgressMonitor monitor) { throw new UnsupportedOperationException("standardMoveProject"); } public void addLifecycleListener(org.eclipse.core.internal.resources.Rules rules) { } /** Returns project manager associated with this workspace */ public ProjectManager getProjectManager() { return projectManager; } /** Returns workspace id of this workspace */ public String getWsId() { return wsId; } }