/* license-start
*
* Copyright (C) 2008 - 2013 Crispico, <http://www.crispico.com/>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details, at <http://www.gnu.org/licenses/>.
*
* Contributors:
* Crispico - Initial API and implementation
*
* license-end
*/
package org.flowerplatform.web.projects.remote;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.StringTokenizer;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceDescription;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.flowerplatform.common.CommonPlugin;
import org.flowerplatform.common.file_event.FileEvent;
import org.flowerplatform.common.file_event.IFileEventListener;
import org.flowerplatform.common.util.Pair;
import org.flowerplatform.communication.CommunicationPlugin;
import org.flowerplatform.communication.channel.CommunicationChannel;
import org.flowerplatform.communication.command.DisplaySimpleMessageClientCommand;
import org.flowerplatform.communication.service.ServiceInvocationContext;
import org.flowerplatform.communication.stateful_service.RemoteInvocation;
import org.flowerplatform.communication.tree.remote.GenericTreeStatefulService;
import org.flowerplatform.communication.tree.remote.PathFragment;
import org.flowerplatform.web.WebPlugin;
import org.flowerplatform.web.database.DatabaseManager;
import org.flowerplatform.web.database.DatabaseOperation;
import org.flowerplatform.web.database.DatabaseOperationWrapper;
import org.flowerplatform.web.entity.EntityFactory;
import org.flowerplatform.web.entity.Organization;
import org.flowerplatform.web.entity.WorkingDirectory;
import org.hibernate.Query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This service is registered programmatically in {@link WebPlugin}, to make
* sure that it's instantiated after the {@link DatabaseManager} was created.
*
* @author Cristian Spiescu
*/
public class ProjectsService implements IFileEventListener {
private static Logger logger = LoggerFactory.getLogger(ProjectsService.class);
public static ProjectsService getInstance() {
return (ProjectsService) CommunicationPlugin.getInstance().getServiceRegistry().getService(SERVICE_ID);
}
public static final String SERVICE_ID = "projectsService";
public static final String WORKSPACE_LOCATION_VAR = "WORKSPACE_LOC";
public static final String PROJECT_WRAPPERS = "project-wrappers";
public static final String LINK_TO_PROJECT = "link-to-project";
public static final String PROJECT_WRAPPER_NAME_SEPARATOR = "=+=";
public File getOrganizationDir(String organizationName) {
return new File(CommonPlugin.getInstance().getWorkspaceRoot(), organizationName);
}
public String getOrganizationName(File organizationDir) {
return organizationDir.getName();
}
protected Map<File, List<File>> workingDirectoryToProjectsMap = new HashMap<File, List<File>>();
protected Map<File, Pair<File, IProject>> projectToWorkingDirectoryAndIProjectMap = new HashMap<File, Pair<File, IProject>>();
public Map<File, List<File>> getWorkingDirectoryToProjectsMap() {
return workingDirectoryToProjectsMap;
}
public Map<File, Pair<File, IProject>> getProjectToWorkingDirectoryAndIProjectMap() {
return projectToWorkingDirectoryAndIProjectMap;
}
public ProjectsService() throws CoreException, URISyntaxException {
super();
CommonPlugin.getInstance().getFileEventDispatcher().addFileEventListener(this);
{
// workspace configuration: this should be done only once, because
// these settings are persistent.
// However, I don't see how we could see that "this == first time"
// in a reliable manner. That's
// why we do it every time, and it doesn't hurt as I don't think
// they are expensive methods
// turn off auto build
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceDescription description = workspace.getDescription();
description.setAutoBuilding(false);
workspace.setDescription(description);
// add the workspace location to the variables map. In desktop
// eclipse some default vars seem to be populated
// automatically, but in the web config this doesn't seem to happen
workspace.getPathVariableManager().setURIValue(WORKSPACE_LOCATION_VAR,
CommonPlugin.getInstance().getWorkspaceRoot().toURI());
}
// fill the map with working directories
@SuppressWarnings("unchecked")
List<WorkingDirectory> workingDirectories = (List<WorkingDirectory>) new DatabaseOperationWrapper(
new DatabaseOperation() {
@Override
public void run() {
wrapper.setOperationResult(wrapper.findAll(WorkingDirectory.class));
}
}).getOperationResult();
for (WorkingDirectory workingDirectory : workingDirectories) {
File workingDirFile = new File(getOrganizationDir(workingDirectory.getOrganization().getName()),
workingDirectory.getPathFromOrganization());
workingDirectoryToProjectsMap.put(workingDirFile, new ArrayList<File>());
}
File workingDirectoryFile = null;
for (IProject projectWrapper : ResourcesPlugin.getWorkspace().getRoot().getProjects()) {
// I don't use String.split, because it takes a regex, which means I
// should have another constant,
// because the current separator has regex special chars
StringTokenizer st = new StringTokenizer(projectWrapper.getName(), PROJECT_WRAPPER_NAME_SEPARATOR);
if (st.countTokens() < 3) {
logger.warn(
"Project = {} is invalid. We were expecting at minimum tree tokens (i.e. org/work_dir/proj), but got only = {}",
projectWrapper, st.countTokens());
continue;
}
// we begin directly with something like org/work_dir
// at the end of the iteration, this will be the file of the project
File currentFile = new File(CommonPlugin.getInstance().getWorkspaceRoot(), st.nextToken() + "/"
+ st.nextToken());
do {
if (workingDirectoryToProjectsMap.get(currentFile) != null) {
// found the working directory
workingDirectoryFile = currentFile;
}
currentFile = new File(currentFile, st.nextToken());
} while (st.hasMoreTokens());
if (workingDirectoryFile == null) {
logger.warn("Project = {} is invalid. Couldn't find correspondig WorkingDirectory", projectWrapper);
continue;
}
if (!currentFile.exists() || !currentFile.isDirectory()) {
logger.warn("Project = {} is invalid. The file = {} doesn't point to an existing directory",
projectWrapper, currentFile);
continue;
}
workingDirectoryToProjectsMap.get(workingDirectoryFile).add(currentFile);
projectToWorkingDirectoryAndIProjectMap.put(currentFile, new Pair<File, IProject>(workingDirectoryFile,
projectWrapper));
if (logger.isDebugEnabled()) {
logger.debug(
"Project added succesfully in maps; project wrapper = {}, working directory = {}, project dir = {}",
new Object[] { projectWrapper, workingDirectoryFile, currentFile });
}
}
}
@SuppressWarnings("unchecked")
public List<WorkingDirectory> getWorkingDirectoriesForOrganizationName(final String organizationName) {
return (List<WorkingDirectory>) new DatabaseOperationWrapper(new DatabaseOperation() {
@Override
public void run() {
Query q = wrapper.createQuery(String.format(
"SELECT e from WorkingDirectory e where e.organization.name = '%s'", organizationName));
wrapper.setOperationResult(q.list());
}
}).getOperationResult();
}
public WorkingDirectory getWorkingDirectory(final String organizationName, final String pathFromOrganization) {
return (WorkingDirectory) new DatabaseOperationWrapper(new DatabaseOperation() {
@Override
public void run() {
Query q = wrapper.createQuery(String
.format("SELECT e from WorkingDirectory e where e.organization.name = '%s' and e.pathFromOrganization = '%s' ",
organizationName, pathFromOrganization));
wrapper.setOperationResult(q.uniqueResult());
}
}).getOperationResult();
}
/**
* It's ugly because the method behaves differently/takes other params
* (based on <code>parameterIsWorkingDirectory</code>). But I do this
* because the code is similar, and I don't want to create classes to
* inherit, etc. So it's excused, because the purpose is code reuse.
*
* @param channel
* @param errorTitleMessageKey
* @param workingDirectoryOrProject
* @param parameterIsWorkingDirectory
* @return A pair. The first element is a) the organization (if
* parameterIsWorkingDirectory) or b) working directory (if
* !parameterIsWorkingDirectory). The second element is a boolean
* that indicates whether a message was sent to the client or not.
*/
protected Pair<File, Boolean> getOrganizationDirForWorkingDirectoryOrWorkindDirectoryForProject(
CommunicationChannel channel, String errorTitleMessageKey, File workingDirectoryOrProject,
boolean parameterIsWorkingDirectory) {
File currentFile = workingDirectoryOrProject;
// loop that does validations and find the organization dir
while (currentFile != null && currentFile != CommonPlugin.getInstance().getWorkspaceRoot()) {
if (projectToWorkingDirectoryAndIProjectMap.get(currentFile) != null) {
// a parent is a project; error in both cases
channel.appendCommandToCurrentHttpResponse(new DisplaySimpleMessageClientCommand(WebPlugin
.getInstance().getMessage(errorTitleMessageKey), WebPlugin.getInstance().getMessage(
"explorer.markAsWorkingDirectory.error.isInProj",
CommonPlugin.getInstance().getPathRelativeToWorkspaceRoot(workingDirectoryOrProject),
CommonPlugin.getInstance().getPathRelativeToWorkspaceRoot(currentFile)),
DisplaySimpleMessageClientCommand.ICON_ERROR));
return new Pair<File, Boolean>(null, true);
}
if (workingDirectoryToProjectsMap.get(currentFile) != null) {
// a parent is a working directory
if (!parameterIsWorkingDirectory) {
// I'm looking for the working dir for the project param; so
// we'are happy of finding it
return new Pair<File, Boolean>(currentFile, false);
} else {
// I'm looking for the org dir; we found a working dir,
// which is invalid => error
channel.appendCommandToCurrentHttpResponse(new DisplaySimpleMessageClientCommand(WebPlugin
.getInstance().getMessage(errorTitleMessageKey), WebPlugin.getInstance().getMessage(
"explorer.markAsWorkingDirectory.error.isInWD",
CommonPlugin.getInstance().getPathRelativeToWorkspaceRoot(workingDirectoryOrProject),
CommonPlugin.getInstance().getPathRelativeToWorkspaceRoot(currentFile)),
DisplaySimpleMessageClientCommand.ICON_ERROR));
return new Pair<File, Boolean>(null, true);
}
}
if (parameterIsWorkingDirectory
&& CommonPlugin.getInstance().getWorkspaceRoot().equals(currentFile.getParentFile())) {
// we found the org dir
return new Pair<File, Boolean>(currentFile, false);
}
currentFile = currentFile.getParentFile();
}
return new Pair<File, Boolean>(null, false);
}
public File getFileFromProjectWrapperResource(IResource resource) {
IProject projectWrapper = resource.getProject();
// I don't use String.split, because it takes a regex, which means I
// should have another constant,
// because the current separator has regex special chars
StringTokenizer st = new StringTokenizer(projectWrapper.getName(), PROJECT_WRAPPER_NAME_SEPARATOR);
if (st.countTokens() < 3) {
logger.warn(
"Project = {} is invalid. We were expecting at minimum tree tokens (i.e. org/work_dir/proj), but got only = {}",
projectWrapper, st.countTokens());
return null;
}
// we begin directly with something like org/work_dir
// at the end of the iteration, this will be the file of the project
File currentFile = new File(CommonPlugin.getInstance().getWorkspaceRoot(), st.nextToken() + "/"
+ st.nextToken());
do {
currentFile = new File(currentFile, st.nextToken());
} while (st.hasMoreTokens());
if (resource instanceof IProject) {
return currentFile;
} else {
return new File(currentFile, resource.getFullPath()
.makeRelativeTo(resource.getProject().getFullPath().append(LINK_TO_PROJECT)).toFile().getPath());
}
}
@RemoteInvocation
public void markAsWorkingDirectory(ServiceInvocationContext context, List<PathFragment> pathWithRoot) {
@SuppressWarnings("unchecked")
File file = ((Pair<File, String>) GenericTreeStatefulService.getNodeByPathFor(pathWithRoot, null)).a;
markAsWorkingDirectoryForFile(context, file);
}
public void markAsWorkingDirectoryForFile(ServiceInvocationContext context, final File file) {
final Pair<File, Boolean> organizationDir = getOrganizationDirForWorkingDirectoryOrWorkindDirectoryForProject(
context.getCommunicationChannel(), "explorer.markAsWorkingDirectory.error.title", file, true);
if (organizationDir.a == null) {
if (organizationDir.b) {
// we didn't find it, but it's a validation error; not an
// illegal state; a message was sent to the client
return;
} else {
// it's very wrong if we have this case, i.e. don't find the
// organization
throw new IllegalArgumentException("Couldn't find organization for input = " + file);
}
} else {
if (file.equals(organizationDir.a)) {
// this shouldn't happen, as the action is not visible on
// organization nodes
throw new IllegalArgumentException("The prosed working directory and organization dir are the same: "
+ file);
}
}
new DatabaseOperationWrapper(new DatabaseOperation() {
@Override
public void run() {
String relativePath = CommonPlugin.getInstance().getPathRelativeToFile(file, organizationDir.a);
List<Organization> orgs = (List<Organization>) wrapper.findByField(Organization.class, "name",
getOrganizationName(organizationDir.a));
if (orgs.isEmpty()) {
throw new IllegalArgumentException("Cannot find organization with name = "
+ getOrganizationName(organizationDir.a));
}
WorkingDirectory wd = EntityFactory.eINSTANCE.createWorkingDirectory();
wd.setPathFromOrganization(relativePath);
wd.setOrganization(orgs.get(0));
wrapper.getSession().persist(wd);
}
});
workingDirectoryToProjectsMap.put(file, new ArrayList<File>());
if (logger.isDebugEnabled()) {
logger.debug("In Organization = {}, added a new Working Directory = {}",
getOrganizationName(organizationDir.a), file);
}
}
@RemoteInvocation
public void createOrImportProject(ServiceInvocationContext context, List<PathFragment> pathWithRoot)
throws CoreException, URISyntaxException {
@SuppressWarnings("unchecked")
File file = ((Pair<File, String>) GenericTreeStatefulService.getNodeByPathFor(pathWithRoot, null)).a;
createOrImportProjectFromFile(context, file);
}
public void createOrImportProjectFromFile(ServiceInvocationContext context, final File file)
throws URISyntaxException, CoreException {
final Pair<File, Boolean> workingDirectoryDir = getOrganizationDirForWorkingDirectoryOrWorkindDirectoryForProject(
context.getCommunicationChannel(), "explorer.createOrImportProject.error.title", file, false);
if (workingDirectoryDir.a == null) {
if (workingDirectoryDir.b) {
// we didn't find it, but it's a validation error; not an
// illegal state; a message was sent to the client
} else {
// the file is not in a working dir
context.getCommunicationChannel().appendCommandToCurrentHttpResponse(
new DisplaySimpleMessageClientCommand(WebPlugin.getInstance().getMessage(
"explorer.createOrImportProject.error.title"), WebPlugin.getInstance().getMessage(
"explorer.createOrImportProject.error.cannotFindWD",
CommonPlugin.getInstance().getPathRelativeToWorkspaceRoot(file)),
DisplaySimpleMessageClientCommand.ICON_ERROR));
}
return;
}
// create the project in the workspace
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceRoot wsRoot = workspace.getRoot();
String projectPath = CommonPlugin.getInstance().getPathRelativeToWorkspaceRoot(file);
if (projectPath.indexOf(PROJECT_WRAPPER_NAME_SEPARATOR) >= 0) {
// ooops; the dir contains the separator; not good! I hope this
// won't happen
throw new UnsupportedOperationException(String.format(
"The project to import contains our separator = %s in its name = $s",
PROJECT_WRAPPER_NAME_SEPARATOR, projectPath));
}
String projectWrapperName = projectPath.replace("/", PROJECT_WRAPPER_NAME_SEPARATOR);
String organizationDirName = projectPath.substring(0, projectPath.indexOf('/'));
// e.g.
// WORKSPACE_LOC/myOrg/project-wrappers/myOrg.git_repos.work_dir1.proj1
URI projectWrapperLocationURI = new URI(WORKSPACE_LOCATION_VAR + "/" + organizationDirName + "/"
+ PROJECT_WRAPPERS + "/" + projectWrapperName);
IProject projectWrapper = wsRoot.getProject(projectWrapperName);
if (projectWrapper.exists()) {
logger.warn("The project {} was found in the workspace while trying to import it; deleting it.",
projectWrapper);
projectWrapper.delete(true, null);
}
IStatus status = workspace.validateProjectLocationURI(projectWrapper, projectWrapperLocationURI);
if (!status.isOK()) {
throw new RuntimeException(String.format(
"The project location URI = %s is not valid; we have the following validation error message = %s",
projectWrapperLocationURI, status.getMessage()));
}
IProjectDescription pd = ResourcesPlugin.getWorkspace().newProjectDescription(projectWrapper.getName());
pd.setLocationURI(projectWrapperLocationURI);
projectWrapper.create(pd, null);
projectWrapper.open(null);
// create the linked folder, from the project wrapper -> the project
// itself
IFolder linkToProjectFolder = projectWrapper.getFolder(LINK_TO_PROJECT);
URI linkToProjectURI = new URI(WORKSPACE_LOCATION_VAR + "/" + projectPath);
status = workspace.validateLinkLocationURI(linkToProjectFolder, linkToProjectURI);
if (!status.isOK()) {
throw new RuntimeException(String.format(
"The linkToProjectURI = %s is not valid; we have the following validation error message = %s",
linkToProjectURI, status.getMessage()));
}
linkToProjectFolder.createLink(linkToProjectURI, IResource.NONE, null);
workingDirectoryToProjectsMap.get(workingDirectoryDir.a).add(file);
projectToWorkingDirectoryAndIProjectMap.put(file, new Pair<File, IProject>(workingDirectoryDir.a,
projectWrapper));
if (logger.isDebugEnabled()) {
logger.debug("In Working Directory = {}, added a new Project = {}", workingDirectoryDir.a, file);
}
}
/**
* @author Tache Razvan Mihai
*
* @param file
*/
public void deleteProject(final File file) {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceRoot wsRoot = workspace.getRoot();
String projectPath = CommonPlugin.getInstance().getPathRelativeToWorkspaceRoot(file);
String projectWrapperName = projectPath.replace("/", ProjectsService.PROJECT_WRAPPER_NAME_SEPARATOR);
IProject projectWrapper = wsRoot.getProject(projectWrapperName);
if (projectWrapper.exists()) {
IFolder linkToProjectFolder = projectWrapper.getFolder(ProjectsService.LINK_TO_PROJECT);
try {
// TODO Decide if needed
// IStatus status =
// workspace.validateLinkLocationURI(linkToProjectFolder,
// linkToProjectURI);
// if (!status.isOK()) {
// throw new
// RuntimeException(String.format("The linkToProjectURI = %s is not valid; we have the following validation error message = %s",
// linkToProjectURI, status.getMessage()));
// }
projectWrapper.delete(true, null);
linkToProjectFolder.delete(true, null);
} catch (CoreException e) {
// TODO the component I need to display messages, is waiting to
// be merged within flower/main
// FileManagerService.printSimpleMessageToUser(context,
// "Error",
// e.getMessage() + " Check the console for more informations");
e.printStackTrace();
}
workingDirectoryToProjectsMap.get(projectToWorkingDirectoryAndIProjectMap.get(file).a).remove(file);
projectToWorkingDirectoryAndIProjectMap.remove(file);
} else {
// FileManagerService.printSimpleMessageToUser(context, "error",
// "Project doesn't exist");
}
}
public void renameProject(final File file, final File newFile) {
try {
renameProject(file, newFile, null);
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
public void renameProject(final File file, final File newFile, File newWorkingDirectory) throws URISyntaxException {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceRoot wsRoot = workspace.getRoot();
String projectPath = CommonPlugin.getInstance().getPathRelativeToWorkspaceRoot(file);
String projectWrapperName = projectPath.replace("/", ProjectsService.PROJECT_WRAPPER_NAME_SEPARATOR);
String newProjectPath = CommonPlugin.getInstance().getPathRelativeToWorkspaceRoot(newFile);
String newProjectWrapperName = newProjectPath.replace("/", ProjectsService.PROJECT_WRAPPER_NAME_SEPARATOR);
String organizationDirName = newProjectPath.substring(0, newProjectPath.indexOf('/'));
File projectWrapperFile = new File(workspace.getRoot().getLocationURI().getPath(), organizationDirName + "/"
+ PROJECT_WRAPPERS + "/" + projectWrapperName);
File newProjectWrapperFile = new File(workspace.getRoot().getLocationURI().getPath(), organizationDirName + "/"
+ PROJECT_WRAPPERS + "/" + newProjectWrapperName);
if (newProjectPath.indexOf(PROJECT_WRAPPER_NAME_SEPARATOR) >= 0) {
// ooops; the dir contains the separator; not good! I hope this
// won't happen
throw new UnsupportedOperationException(String.format(
"The project to import contains our separator = %s in its name = $s",
PROJECT_WRAPPER_NAME_SEPARATOR, projectPath));
}
URI newProjectWrapperLocationURI = new URI(WORKSPACE_LOCATION_VAR + "/" + organizationDirName + "/"
+ PROJECT_WRAPPERS + "/" + newProjectWrapperName);
IProject projectWrapper = wsRoot.getProject(projectWrapperName);
IProjectDescription description = null;
IProject newProjectWrapper = null;
try {
description = projectWrapper.getDescription();
description.setLocationURI(newProjectWrapperLocationURI);
IFolder linkToProjectFolder = projectWrapper.getFolder(ProjectsService.LINK_TO_PROJECT);
linkToProjectFolder.delete(true, null);
projectWrapper.delete(false, true, null);
boolean result = projectWrapperFile.renameTo(newProjectWrapperFile);
if (result) {
newProjectWrapper = wsRoot.getProject(newProjectWrapperName);
newProjectWrapper.create(description, null);
if (newProjectWrapper.exists()) {
// set the new name and uri in the description
newProjectWrapper.open(null);
description = newProjectWrapper.getDescription();
description.setName(newProjectWrapperName);
// update the project
newProjectWrapper.move(description, true, null);
// create the linked folder, from the project wrapper -> the
// project itself
linkToProjectFolder = newProjectWrapper.getFolder(LINK_TO_PROJECT);
URI linkToProjectURI = new URI(WORKSPACE_LOCATION_VAR + "/" + newProjectPath);
linkToProjectFolder.createLink(linkToProjectURI, IResource.NONE, null);
// update the maps
File workingDirectory = projectToWorkingDirectoryAndIProjectMap.get(file).a;
if (newWorkingDirectory == null) {
newWorkingDirectory = workingDirectory;
}
int index = workingDirectoryToProjectsMap.get(newWorkingDirectory).indexOf(file);
workingDirectoryToProjectsMap.get(newWorkingDirectory).set(index, newFile);
projectToWorkingDirectoryAndIProjectMap.remove(file);
projectToWorkingDirectoryAndIProjectMap.put(newFile, new Pair<File, IProject>(newWorkingDirectory,
newProjectWrapper));
} else {
// TODO after getting the message method, implement it to
// print an error
}
} else {
// TODO after getting the message method, implement it to print
// an error
}
} catch (CoreException e1) {
e1.printStackTrace();
}
}
public IResource getProjectWrapperResourceFromFile(List<PathFragment> pathWithRoot) {
@SuppressWarnings("unchecked")
File file = ((Pair<File, String>) GenericTreeStatefulService.getNodeByPathFor(pathWithRoot, null)).a;
return getProjectWrapperResourceFromFile(file);
}
public IResource getProjectWrapperResourceFromFile(final File file) {
File currentFile = file;
IProject projectWrapper = null;
while (currentFile != null && currentFile != CommonPlugin.getInstance().getWorkspaceRoot()) {
Pair<File, IProject> pair = projectToWorkingDirectoryAndIProjectMap.get(currentFile);
if (pair != null) {
projectWrapper = pair.b;
break;
}
currentFile = currentFile.getParentFile();
}
// at the end of the loop, current file will be pointing toward the
// project file
if (projectWrapper == null) {
// the path doesn't point on a file within a project
return null;
}
String relativePath = CommonPlugin.getInstance().getPathRelativeToFile(file, currentFile);
if (relativePath.isEmpty()) {
return projectWrapper;
}
String pathInProjectWrapper = LINK_TO_PROJECT + "/" + relativePath;
if (file.isDirectory()) {
return projectWrapper.getFolder(pathInProjectWrapper);
} else {
return projectWrapper.getFile(pathInProjectWrapper);
}
}
public String getOrganizationNameFromFile(File file) {
String relativePathToWorkspace = CommonPlugin.getInstance().getPathRelativeToWorkspaceRoot(file);
String[] folders = relativePathToWorkspace.split("/");
return folders[0];
}
@Override
public void notify(FileEvent event) {
File file = event.getFile();
String org = ProjectsService.getInstance().getOrganizationNameFromFile(event.getFile());
File orgDir = getOrganizationDir(org);
if (event.getEvent() == FileEvent.FILE_RENAMED) {
file = event.getOldFile();
}
if (workingDirectoryToProjectsMap.get(file) != null) {
// it's an working directory
String pathFromOrgForFile = getRelativePathFromOrganization(file);
WorkingDirectory workingDirectory = getWorkingDirectory(org, pathFromOrgForFile);
if (event.getEvent() == FileEvent.FILE_DELETED) {
deleteWorkingDirectory(event.getFile(), workingDirectory);
} else if(event.getEvent() == FileEvent.FILE_RENAMED) {
renameWorkingDirectory(file, event.getFile());
}
} else if (projectToWorkingDirectoryAndIProjectMap.get(file) != null) {
// it's an project
if (event.getEvent() == FileEvent.FILE_DELETED) {
deleteProject(event.getFile());
} else if(event.getEvent() == FileEvent.FILE_RENAMED) {
renameProject(file, event.getFile());
}
} else {
File fileIterator = file.getParentFile();
while (!fileIterator.equals(orgDir)) {
if (workingDirectoryToProjectsMap.get(fileIterator) != null) {
// has found an working directory to the left
List<File> projectFiles = workingDirectoryToProjectsMap.get(fileIterator);
ListIterator<File> iter = projectFiles.listIterator();
while (iter.hasNext()) {
File projectFile = (File) iter.next();
if (projectFile.getPath().contains(file.getPath())) {
if (event.getEvent() == FileEvent.FILE_DELETED) {
iter.remove();
deleteProject(projectFile);
} else if(event.getEvent() == FileEvent.FILE_RENAMED) {
String projectPath = projectFile.getPath();
String newProjectPath = projectPath.replace(event.getOldFile().getPath(), event
.getFile().getPath());
renameProject(projectFile, new File(newProjectPath));
}
}
}
break;
}
fileIterator = fileIterator.getParentFile();
}
if (fileIterator.equals(orgDir)) {
List<WorkingDirectory> workingDirectories = ProjectsService.getInstance()
.getWorkingDirectoriesForOrganizationName(org);
ListIterator<WorkingDirectory> iter = workingDirectories.listIterator();
while (iter.hasNext()) {
WorkingDirectory workingDirectory = (WorkingDirectory) iter.next();
if (workingDirectory.getPathFromOrganization().contains(getRelativePathFromOrganization(file))) {
if (event.getEvent() == FileEvent.FILE_DELETED) {
deleteWorkingDirectory(new File(orgDir, workingDirectory.getPathFromOrganization()),
workingDirectory);
} else if(event.getEvent() == FileEvent.FILE_RENAMED) {
File oldWD = new File(orgDir, workingDirectory.getPathFromOrganization());
String oldWDpath = oldWD.getPath();
String newWDpath = oldWDpath.replace(event.getOldFile().getPath(), event.getFile()
.getPath());
renameWorkingDirectory(oldWD, new File(newWDpath));
}
}
}
}
}
}
private void renameWorkingDirectory(final File file, final File newFile) {
final String org = ProjectsService.getInstance().getOrganizationNameFromFile(file);
final File orgDir = getOrganizationDir(org);
final String relativePath = CommonPlugin.getInstance().getPathRelativeToFile(file, orgDir);
final String newOrg = ProjectsService.getInstance().getOrganizationNameFromFile(newFile);
final File newOrgDir = getOrganizationDir(newOrg);
final String newRelativePath = CommonPlugin.getInstance().getPathRelativeToFile(newFile, newOrgDir);
new DatabaseOperationWrapper(new DatabaseOperation() {
@Override
public void run() {
WorkingDirectory wd = getWorkingDirectory(org, relativePath);
List<Organization> orgs = (List<Organization>) wrapper.findByField(Organization.class, "name",
getOrganizationName(newOrgDir));
if (orgs.isEmpty()) {
throw new IllegalArgumentException("Cannot find organization with name = "
+ getOrganizationName(newOrgDir));
}
wd.setPathFromOrganization(newRelativePath);
// wd.setOrganization(orgs.get(0));
wrapper.getSession().merge(wd);
}
});
List<File> backupProjects = workingDirectoryToProjectsMap.remove(file);
workingDirectoryToProjectsMap.put(newFile, backupProjects);
List<File> projectFiles = workingDirectoryToProjectsMap.get(newFile);
ListIterator<File> iter = projectFiles.listIterator();
while (iter.hasNext()) {
File projectFile = (File) iter.next();
String projectPath = projectFile.getPath();
String newProjectPath = projectPath.replace(file.getPath(), newFile.getPath());
try {
renameProject(projectFile, new File(newProjectPath), newFile);
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
}
private void deleteWorkingDirectory(final File file, final WorkingDirectory workingDirectory) {
String org = ProjectsService.getInstance().getOrganizationNameFromFile(file);
final File orgDir = getOrganizationDir(org);
List<File> projectFiles = workingDirectoryToProjectsMap.get(file);
ListIterator<File> iter = projectFiles.listIterator();
while (iter.hasNext()) {
File projectFile = (File) iter.next();
iter.remove();
deleteProject(projectFile);
}
workingDirectoryToProjectsMap.remove(file);
new DatabaseOperationWrapper(new DatabaseOperation() {
@Override
public void run() {
List<Organization> orgs = (List<Organization>) wrapper.findByField(Organization.class, "name",
getOrganizationName(orgDir));
if (orgs.isEmpty()) {
throw new IllegalArgumentException("Cannot find organization with name = "
+ getOrganizationName(orgDir));
}
wrapper.getSession().delete(workingDirectory);
}
});
}
/**
* @author Tache Razvan Mihai
* @param file
* @return the path to the file from organiztion without "\" in the end if it's a simple file or with "\" in the end if it's a parent file : like in file.getParent();
*
*/
public String getRelativePathFromOrganization(File file) {
String org = ProjectsService.getInstance().getOrganizationNameFromFile(file);
File orgDir = getOrganizationDir(org);
String path = file.getPath();
String base = orgDir.getPath();
String pathFromOrgForFile = new File(base).toURI().relativize(new File(path).toURI()).getPath();
return pathFromOrgForFile;
}
}