/*******************************************************************************
* Copyright (c) 2011, 2016 Ericsson
*
* 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:
* Francois Chouinard - Initial API and implementation
* Bernd Hufmann - Added project creation utility
* Patrick Tasse - Refactor resource change listener
*******************************************************************************/
package org.eclipse.tracecompass.tmf.ui.project.model;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
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.IProgressMonitor;
import org.eclipse.swt.widgets.Display;
import org.eclipse.tracecompass.internal.tmf.ui.Activator;
import org.eclipse.tracecompass.tmf.core.TmfCommonConstants;
import org.eclipse.tracecompass.tmf.core.TmfProjectNature;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
/**
* Factory class storing TMF tracing projects and creating TMF project model elements.
* <p>
* @version 1.0
* @author Francois Chouinard
*/
public class TmfProjectRegistry implements IResourceChangeListener {
// Create the singleton instance
private static final TmfProjectRegistry INSTANCE = new TmfProjectRegistry();
// The map of project resource to project model elements
private static Map<IProject, TmfProjectElement> registry = new HashMap<>();
private TmfProjectRegistry() {
ResourcesPlugin.getWorkspace().addResourceChangeListener(this);
}
/**
* Disposes the project registry
*
* @since 2.3
*/
public static void dispose() {
ResourcesPlugin.getWorkspace().removeResourceChangeListener(INSTANCE);
registry.values().forEach(projectElement -> projectElement.dispose());
}
/**
* Get the project model element for a project resource
* @param project the project resource
* @return the project model element or null if it does not exist
*/
public static synchronized TmfProjectElement getProject(IProject project) {
return getProject(project, false);
}
/**
* Get the project model element for a project resource
* @param project the project resource
* @param force a flag controlling whether a new project should be created if it doesn't exist
* @return the project model element
*/
public static synchronized TmfProjectElement getProject(IProject project, boolean force) {
TmfProjectElement element = registry.get(project);
if (element == null && force) {
element = new TmfProjectElement(project.getName(), project, null);
registry.put(project, element);
// force the model to be populated
element.refreshChildren();
}
return element;
}
/**
* Utility method to create a tracing project.
*
* @param projectName
* - A project name
* @param projectLocation
* - A project location URI. Use null for default location (which is workspace).
* @param monitor
* - A progress monitor
* @return the IProject object or null
*/
public static IProject createProject(String projectName, final URI projectLocation, IProgressMonitor monitor) {
final IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceRoot root = workspace.getRoot();
final IProject project = root.getProject(projectName);
WorkspaceModifyOperation action = new WorkspaceModifyOperation() {
@Override
protected void execute(IProgressMonitor progressMonitor) throws CoreException, InvocationTargetException, InterruptedException {
if (!project.exists()) {
IProjectDescription description = workspace.newProjectDescription(project.getName());
if (projectLocation != null) {
description.setLocationURI(projectLocation);
}
project.create(description, progressMonitor);
}
if (!project.isOpen()) {
project.open(progressMonitor);
}
IProjectDescription description = project.getDescription();
description.setNatureIds(new String[] { TmfProjectNature.ID });
project.setDescription(description, null);
IFolder folder = project.getFolder(TmfTracesFolder.TRACES_FOLDER_NAME);
if (!folder.exists()) {
folder.create(true, true, null);
}
folder = project.getFolder(TmfExperimentFolder.EXPER_FOLDER_NAME);
if (!folder.exists()) {
folder.create(true, true, null);
}
// create folder for supplementary tracing files
folder = project.getFolder(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER_NAME);
if (!folder.exists()) {
folder.create(true, true, null);
}
}
};
try {
PlatformUI.getWorkbench().getProgressService().run(false, false, action);
} catch (InvocationTargetException e) {
Activator.getDefault().logError("Error creating TMF project " + project.getName(), e); //$NON-NLS-1$
} catch (InterruptedException e) {
}
return project;
}
// ------------------------------------------------------------------------
// IResourceChangeListener
// ------------------------------------------------------------------------
@Override
public void resourceChanged(IResourceChangeEvent event) {
if (event.getType() == IResourceChangeEvent.PRE_DELETE || event.getType() == IResourceChangeEvent.PRE_CLOSE) {
if (event.getResource() instanceof IProject) {
IProject project = (IProject) event.getResource();
try {
if (project.isAccessible() && project.hasNature(TmfProjectNature.ID)) {
TmfProjectElement tmfProjectElement = registry.get(project);
if (tmfProjectElement == null) {
return;
}
TmfTraceFolder tracesFolder = tmfProjectElement.getTracesFolder();
if (tracesFolder != null) {
final List<TmfTraceElement> traces = tracesFolder.getTraces();
if (!traces.isEmpty()) {
// Close editors in UI Thread
Display.getDefault().syncExec(new Runnable() {
@Override
public void run() {
for (TmfTraceElement traceElement : traces) {
traceElement.closeEditors();
}
}
});
}
}
}
} catch (CoreException e) {
Activator.getDefault().logError("Error handling resource change event for " + project.getName(), e); //$NON-NLS-1$
}
}
} else if (event.getType() == IResourceChangeEvent.POST_CHANGE) {
for (IResourceDelta delta : event.getDelta().getAffectedChildren()) {
if (delta.getResource() instanceof IProject) {
IProject project = (IProject) delta.getResource();
try {
if (delta.getKind() == IResourceDelta.CHANGED &&
project.isOpen() && project.hasNature(TmfProjectNature.ID)) {
TmfProjectElement projectElement = getProject(project, true);
projectElement.refresh();
} else if (delta.getKind() == IResourceDelta.REMOVED) {
TmfProjectElement projectElement = registry.remove(project);
if (projectElement != null) {
projectElement.dispose();
}
}
} catch (CoreException e) {
Activator.getDefault().logError("Error handling resource change event for " + project.getName(), e); //$NON-NLS-1$
}
}
}
}
}
}