blob: e28121a96995b8f9f77c22780148e9c24f5e75b7 [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2008-2019 See4sys, itemis, BMW Car IT 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:
* See4sys - Initial API and implementation
* itemis - Improved API for importing external resources to workspace
* itemis - Improved handling of reference workspace path names so as to make integration tests more stable when running on different platforms
* BMW Car IT - Introduced waitForFamily method, refactored scheduleAndWait method
* itemis - Added option to run integration tests without reusing test reference workspace from previous test to avoid side effects across individual tests
* itemis - [414125] Enhance ResourceDeltaVisitor to enable the analysis of IFolder added/moved/removed
* itemis - [423676] AbstractIntegrationTestCase unable to remove project references that are no longer needed
*
* </copyright>
*/
package org.eclipse.sphinx.testutils.integration;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
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.IWorkspaceRoot;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
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.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.sphinx.emf.metamodel.IMetaModelDescriptor;
import org.eclipse.sphinx.emf.metamodel.MetaModelDescriptorRegistry;
import org.eclipse.sphinx.emf.model.IModelDescriptor;
import org.eclipse.sphinx.emf.model.ModelDescriptorRegistry;
import org.eclipse.sphinx.emf.saving.SaveIndicatorUtil;
import org.eclipse.sphinx.emf.util.EcorePlatformUtil;
import org.eclipse.sphinx.emf.util.EcoreResourceUtil;
import org.eclipse.sphinx.emf.util.WorkspaceEditingDomainUtil;
import org.eclipse.sphinx.emf.workspace.domain.WorkspaceEditingDomainManager;
import org.eclipse.sphinx.emf.workspace.loading.ModelLoadManager;
import org.eclipse.sphinx.platform.IExtendedPlatformConstants;
import org.eclipse.sphinx.platform.util.ExtendedPlatform;
import org.eclipse.sphinx.platform.util.StatusUtil;
import org.eclipse.sphinx.testutils.TestFileAccessor;
import org.eclipse.sphinx.testutils.integration.internal.Activator;
import org.eclipse.sphinx.testutils.integration.internal.IInternalReferenceWorkspace;
import org.eclipse.sphinx.testutils.integration.internal.ReferenceEditingDomainDescriptor;
import org.eclipse.sphinx.testutils.integration.internal.ReferenceModelDescriptor;
import org.eclipse.sphinx.testutils.integration.internal.ReferenceProjectDescriptor;
import org.eclipse.sphinx.testutils.integration.internal.ReferenceWorkspaceExtractor;
import junit.framework.TestCase;
@SuppressWarnings("nls")
public abstract class AbstractIntegrationTestCase<T extends IReferenceWorkspace> extends TestCase {
private static final String REFERENCE_WORKSPACE_PROPERTIES_FILE_NAME = "referenceWorkspaceSourceRootDirectory.properties";
private static final String REFERENCE_WORKSPACE_SOURCE_ROOT_DIRECTORY_PROPERTIES_KEY = "referenceWorksaceSourceDirectory";
private static final String JOB_FAMILY_TIMEOUT = System.getProperty(AbstractIntegrationTestCase.class.getName() + ".JOB_FAMILY_TIMEOUT",
new Integer(1 * 60 * 1000).toString());
private Plugin testPlugin = null;
private TestFileAccessor testFileAccessor = null;
private IInternalReferenceWorkspace internalRefWks;
protected T refWks;
private Set<String> projectSubsetToLoad = null;
private Map<String, Set<String>> projectReferences = null;
private boolean projectsClosedOnStartup = false;
private ModelLoadingJobTracer modelLoadJobTracer = new ModelLoadingJobTracer();
private ResourceProblemListener resourceProblemListener = new ResourceProblemListener();
private ReferenceWorkspaceChangeListener referenceWorkspaceChangeListener = new ReferenceWorkspaceChangeListener();
private File referenceWorkspaceTempDir;
private File referenceWorkspaceSourceDir;
private boolean recycleReferenceWorkspaceOfPreviousTestRun = true;
public AbstractIntegrationTestCase(String referenceWorkspaceTempDirBaseName) {
String tempDirPath = System.getProperty("java.io.tmpdir");
File tempDir = new File(tempDirPath);
// Complement name of temporary reference workspace directory with version suffix to avoid that reference
// workspaces originating from different development streams (i.e., platform versions) get mixed up in same
// temporary directory
String referenceWorkspaceTempDirName = referenceWorkspaceTempDirBaseName + "-" + Activator.getPlugin().getBundle().getVersion();
referenceWorkspaceTempDir = new File(tempDir, referenceWorkspaceTempDirName);
if (!referenceWorkspaceTempDir.exists()) {
referenceWorkspaceTempDir.mkdir();
}
}
protected void setRecycleReferenceWorkspaceOfPreviousTestRun(boolean recycleReferenceWorkspaceOfPreviousTestRun) {
this.recycleReferenceWorkspaceOfPreviousTestRun = recycleReferenceWorkspaceOfPreviousTestRun;
}
protected Set<String> getProjectSubsetToLoad() {
if (projectSubsetToLoad == null) {
projectSubsetToLoad = new HashSet<String>();
}
return projectSubsetToLoad;
}
protected Map<String, Set<String>> getProjectReferences() {
if (projectReferences == null) {
projectReferences = new HashMap<String, Set<String>>();
}
return projectReferences;
}
protected boolean isProjectsClosedOnStartup() {
return projectsClosedOnStartup;
}
protected void setProjectsClosedOnStartup(boolean projectsClosedOnStartup) {
this.projectsClosedOnStartup = projectsClosedOnStartup;
}
protected Plugin getTestPlugin() {
if (testPlugin == null) {
testPlugin = Activator.getPlugin();
}
return testPlugin;
}
protected void setTestPlugin(Plugin testPlugin) {
this.testPlugin = testPlugin;
}
protected final TestFileAccessor getTestFileAccessor() {
if (testFileAccessor == null) {
testFileAccessor = new TestFileAccessor(getTestPlugin(), new File("working-dir"));
}
return testFileAccessor;
}
/**
* Sets up the test workspace by importing the reference workspace given in parameter.
*/
@Override
protected void setUp() throws Exception {
// TODO Surround with appropriate tracing option
// System.out.println(">>> Entering setUp()");
Job.getJobManager().addJobChangeListener(modelLoadJobTracer);
// HACK: Enable workspace preference Window > Preferences > General > Always run in background so as to avoid
// excessive creation of progress dialogs by
// org.eclipse.sphinx.emf.workspace.ui.internal.ModelLoadingProgressIndicator#aboutToRun(IJobChangeEvent) during
// testing.
/*
* !! Important Note !! The ModelLoadingProgressIndicator is there for opening a dialog which shows the progress
* of model loading jobs unless this has been deactivated by enabling above named workspace preference. The
* problem is that org.eclipse.ui.progress.IProgressService#showInDialog(Shell, Job) used for that purpose
* attempts to recreate a new progress dialog each time being invoked. This causes the platform to run out of
* SWT handles when too many of such invocations come across within too short intervals (see
* org.eclipse.ui.internal.progress.ProgressMonitorFocusJobDialog#show(Job, Shell) and
* org.eclipse.jface.dialogs.ProgressMonitorDialog#aboutToRun() for details)
*/
IEclipsePreferences workbenchPrefs = InstanceScope.INSTANCE.getNode("org.eclipse.ui.workbench");
workbenchPrefs.put("RUN_IN_BACKGROUND", Boolean.TRUE.toString());
// Delete complete or unused projects depending on whether the reference workspace is intended to be reused or
// not
if (!recycleReferenceWorkspaceOfPreviousTestRun) {
WorkspaceEditingDomainManager.INSTANCE.resetEditingDomainMapping();
assertTrue(WorkspaceEditingDomainManager.INSTANCE.getEditingDomainMapping().getEditingDomains().isEmpty());
assertAllModelResourcesUnloaded();
synchronizedDeleteWorkspace();
ModelDescriptorRegistry.INSTANCE.removeModels(ResourcesPlugin.getWorkspace().getRoot());
assertTrue(ModelDescriptorRegistry.INSTANCE.getAllModels().size() == 0);
assertAllModelDescriptorsRemoved();
} else {
// Delete un-used reference projects which imported for the previous test
synchronizedDeleteProjects(getUnusedReferenceProjects());
}
// Create reference workspace descriptor
refWks = createReferenceWorkspace(getProjectSubsetToLoad());
Assert.isTrue(refWks instanceof IInternalReferenceWorkspace);
internalRefWks = (IInternalReferenceWorkspace) refWks;
// Unzip reference workspace from archive if needed
if (needToExtractReferenceWorkspaceArchive()) {
synchronizedDeleteWorkspace();
deleteExternalResource(referenceWorkspaceTempDir);
extractReferenceWorkspaceArchive();
} else {
loadReferenceWorkspaceSourceDir();
}
org.eclipse.sphinx.emf.workspace.Activator.getPlugin().stopWorkspaceSynchronizing();
synchronizedImportMissingReferenceProjectsIntoWorkspace();
// In case previous test failed and tearDown() was not called, some projects may still be closed - so open all
// of them to be on the safe side
synchronizedOpenAllProjects();
synchronizedImportMissingReferenceFilesToWorkspace();
synchronizedCreateProjectReferences();
// Add ResourceProblemListener on all editingDomains to listening in problems when loading/unloading resources
internalRefWks.addResourceSetProblemListener(resourceProblemListener);
if (isProjectsClosedOnStartup()) {
synchronizedUnloadAllProjects();
synchronizedCloseAllProjects();
assertReferenceWorkspaceClosed();
} else {
synchronizedLoadAllProjects();
assertReferenceWorkspaceInitialized();
}
assertReferenceWorkspaceConsistent();
// Add ReferenceWorkspaceChangeListener to listening in workspace changes during the test
internalRefWks.addReferenceWorkspaceChangeListener(referenceWorkspaceChangeListener);
org.eclipse.sphinx.emf.workspace.Activator.getPlugin().startWorkspaceSynchronizing();
}
/**
* Tears down the test workspace by deleting all projects.
*/
@Override
protected void tearDown() throws Exception {
// TODO Surround with appropriate tracing option
// System.out.println(">>> Entering tearDown()");
// Remove ResourceProblemListener from all editingDomains
internalRefWks.removeResourceSetProblemListener(resourceProblemListener);
internalRefWks.removeReferenceWorkspaceChangeListener(referenceWorkspaceChangeListener);
// Unload resources which have been changed but not saved yet
synchronizedUnloadDirtyResources();
// Projects which have been renamed will be deleted
synchronizedDeleteProjects(referenceWorkspaceChangeListener.getRenamedProjects());
// Open projects which has been changed during the test
synchronizedOpenProjects(detectProjectsToOpen());
// Delete all folders which have been added during the test, including renamed folders
synchronizedDeleteAddedFolders();
// Delete all files which have been added during the test, including renamed files
synchronizedDeleteAddedFiles();
// Delete all files which have been changed during the test
synchronizedDeleteChangedFiles();
// Unload resources are on memory only, these resources are not marked as dirty
synchronizedUnloadAddedResources();
// If existing Projects' description were changed, reset its by copying contents from reference file
synchronizedResetProjectDescriptions();
// If existing Projects' setting were changed, reset them by copying contents from reference file
synchronizedResetProjectSettings();
// Clear list of resources changed
resourceProblemListener.clearHistory();
referenceWorkspaceChangeListener.clearHistory();
Job.getJobManager().removeJobChangeListener(modelLoadJobTracer);
assertReferenceWorkspaceConsistent();
}
/**
* Detects projects that have resources changed during the test. If projects were closed in the test, we need to
* open it to delete changed files or reset project description and settings
*
* @return
*/
private Collection<IProject> detectProjectsToOpen() {
Set<IProject> projectsToOpen = new HashSet<IProject>();
if (!(referenceWorkspaceChangeListener.getAddedFiles().size() > 0 || referenceWorkspaceChangeListener.getChangedFiles().size() > 0
|| referenceWorkspaceChangeListener.getProjectsWithChangedDescription().size() > 0
|| referenceWorkspaceChangeListener.getProjectsWithChangedSettings().size() > 0)) {
return Collections.emptySet();
}
for (IFile changedFile : referenceWorkspaceChangeListener.getChangedFiles()) {
assertNotNull(changedFile);
IProject project = changedFile.getProject();
assertNotNull(project);
if (project.exists() && !project.isOpen()) {
projectsToOpen.add(project);
}
}
for (IFile addedFile : referenceWorkspaceChangeListener.getAddedFiles()) {
assertNotNull(addedFile);
IProject project = addedFile.getProject();
if (project.exists() && !project.isOpen()) {
projectsToOpen.add(project);
}
}
for (IProject project : referenceWorkspaceChangeListener.getProjectsWithChangedDescription()) {
if (!(project == null || project.exists() || project.isOpen())) {
projectsToOpen.add(project);
}
}
for (IProject project : referenceWorkspaceChangeListener.getProjectsWithChangedSettings().keySet()) {
if (!(project == null || project.exists() || project.isOpen())) {
projectsToOpen.add(project);
}
}
return projectsToOpen;
}
/**
* Unloads all resources created in the previous test. These resources were added to ResourceSets but were not saved
* and not marked as dirty. So we need to detect and unload them
*/
private void synchronizedUnloadAddedResources() {
List<Resource> resourcesToUnload = new ArrayList<Resource>();
for (IMetaModelDescriptor metaModelDescriptor : internalRefWks.getReferenceEditingDomainDescritpors().keySet()) {
TransactionalEditingDomain editingDomain = WorkspaceEditingDomainUtil.getEditingDomain(ResourcesPlugin.getWorkspace().getRoot(),
metaModelDescriptor);
if (editingDomain != null) {
Set<String> referenceFileNames = internalRefWks.getReferenceFileNames(metaModelDescriptor);
for (Resource resource : editingDomain.getResourceSet().getResources()) {
if (!referenceFileNames.contains(resource.getURI().lastSegment())) {
resourcesToUnload.add(resource);
}
}
}
EcorePlatformUtil.unloadResources(editingDomain, resourcesToUnload, true, null);
waitForModelLoading();
}
}
/**
* Deletes files which has been changed in the test. These files will be imported again in setUp() of next test if
* they are required for the test.
*
* @throws Exception
*/
private void synchronizedDeleteChangedFiles() throws Exception {
for (IFile changedFile : referenceWorkspaceChangeListener.getChangedFiles()) {
if (changedFile != null && changedFile.isAccessible()) {
synchronizedDeleteFile(changedFile);
}
}
}
/**
* Deletes all new files which have been added during the test.
*
* @throws Exception
*/
private void synchronizedDeleteAddedFiles() throws Exception {
for (IFile addedFile : referenceWorkspaceChangeListener.getAddedFiles()) {
if (refWks.getAllReferenceFiles().contains(addedFile)) {
continue;
} else if (addedFile != null && addedFile.isAccessible()) {
synchronizedDeleteFile(addedFile);
}
}
}
/**
* Deletes all new folders which have been added during the test.
*
* @throws Exception
*/
private void synchronizedDeleteAddedFolders() throws Exception {
for (IFolder addedFolder : referenceWorkspaceChangeListener.getAddedFolders()) {
if (addedFolder != null && addedFolder.isAccessible()) {
synchronizedDeleteFolder(addedFolder);
}
}
}
/**
* Unloads all dirty resources in editingDomains
*/
private void synchronizedUnloadDirtyResources() {
for (IMetaModelDescriptor metaModelDescriptor : internalRefWks.getReferenceEditingDomainDescritpors().keySet()) {
TransactionalEditingDomain editingDomain = WorkspaceEditingDomainUtil.getEditingDomain(ResourcesPlugin.getWorkspace().getRoot(),
metaModelDescriptor);
if (editingDomain != null) {
Collection<Resource> dirtyResources = SaveIndicatorUtil.getDirtyResources(editingDomain);
EcorePlatformUtil.unloadResources(editingDomain, dirtyResources, true, null);
}
}
waitForModelLoading();
}
/**
* Resets description of projects which have been changed during the test by copying .project file from source
* reference file
*
* @throws Exception
*/
private void synchronizedResetProjectDescriptions() throws Exception {
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
MultiStatus errorStatus = new MultiStatus(Activator.getPlugin().getSymbolicName(), IStatus.ERROR,
"Problems encountered while resetting project descriptions.", new RuntimeException());
for (IProject project : referenceWorkspaceChangeListener.getProjectsWithChangedDescription()) {
try {
if (project.exists()) {
File projectSourceDir = new File(referenceWorkspaceSourceDir, project.getName());
importExternalResourceToWorkspace(new File(projectSourceDir, ".project"), project);
}
} catch (Exception ex) {
errorStatus.add(StatusUtil.createErrorStatus(Activator.getDefault(), ex));
}
}
if (errorStatus.getChildren().length > 0) {
throw new CoreException(errorStatus);
}
}
};
ResourcesPlugin.getWorkspace().run(runnable, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
ResourcesPlugin.getWorkspace().checkpoint(false);
waitForModelLoading();
}
/**
* Resets settings of projects which have been changed during the test by copying .settings folder from source
* reference directory
*
* @throws Exception
*/
private void synchronizedResetProjectSettings() throws Exception {
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
MultiStatus errorStatus = new MultiStatus(Activator.getPlugin().getSymbolicName(), IStatus.ERROR,
"Problems encountered while resetting project settings.", new RuntimeException());
for (IProject project : referenceWorkspaceChangeListener.getProjectsWithChangedSettings().keySet()) {
try {
if (project.exists()) {
File projectSourceDir = new File(referenceWorkspaceSourceDir, project.getName());
importExternalResourceToWorkspace(new File(projectSourceDir, ".settings"), project);
}
} catch (Exception ex) {
errorStatus.add(StatusUtil.createErrorStatus(Activator.getDefault(), ex));
}
}
if (errorStatus.getChildren().length > 0) {
throw new CoreException(errorStatus);
}
}
};
ResourcesPlugin.getWorkspace().run(runnable, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
ResourcesPlugin.getWorkspace().checkpoint(false);
waitForModelLoading();
}
/**
* Checks if it is necessary to unzip reference workspace from archive.
*
* @return <code>true</code> if the reference workspace archive was not already unzipped and reference workspace
* source root directory path was not already saved to the referenceWorkspaceSourceRootDirectory.properties
* file or if reference workspace archive is newer than existing unzipped reference workspace in temporary
* directory; <code>false</code> otherwise.
*/
private boolean needToExtractReferenceWorkspaceArchive() throws Exception {
java.net.URI referenceWorkspaceInputFileURI = getReferenceWorkspaceFileAccessor()
.getInputFileURI(internalRefWks.getReferenceWorkspaceArchiveFileName(), true);
File referenceWorkspaceArchive = null;
if (referenceWorkspaceInputFileURI != null) {
referenceWorkspaceArchive = new File(referenceWorkspaceInputFileURI);
}
File propertiesFile = new File(referenceWorkspaceTempDir, REFERENCE_WORKSPACE_PROPERTIES_FILE_NAME);
return !propertiesFile.exists()
|| referenceWorkspaceArchive != null && referenceWorkspaceArchive.lastModified() > referenceWorkspaceTempDir.lastModified();
}
private TestFileAccessor getReferenceWorkspaceFileAccessor() {
return new TestFileAccessor(internalRefWks.getReferenceWorkspacePlugin());
}
/**
* Saves the reference workspace source directory to read
*
* @throws IOException
*/
private void saveReferenceWorkspaceSourceDir() throws IOException {
Properties properties = new Properties();
properties.put(REFERENCE_WORKSPACE_SOURCE_ROOT_DIRECTORY_PROPERTIES_KEY, referenceWorkspaceSourceDir.getAbsolutePath());
File propertiesFile = new File(referenceWorkspaceTempDir, REFERENCE_WORKSPACE_PROPERTIES_FILE_NAME);
if (!propertiesFile.exists()) {
propertiesFile.createNewFile();
}
OutputStream out = null;
try {
out = new FileOutputStream(propertiesFile);
properties.store(out, "Reference workspace source directory");
} finally {
if (out != null) {
out.close();
}
}
}
private void loadReferenceWorkspaceSourceDir() throws IOException {
Properties properties = new Properties();
File propertiesFile = new File(referenceWorkspaceTempDir, REFERENCE_WORKSPACE_PROPERTIES_FILE_NAME);
InputStream in = new FileInputStream(propertiesFile);
properties.load(in);
String path = properties.getProperty(REFERENCE_WORKSPACE_SOURCE_ROOT_DIRECTORY_PROPERTIES_KEY);
if (path == null) {
throw new RuntimeException("No value for key '" + REFERENCE_WORKSPACE_SOURCE_ROOT_DIRECTORY_PROPERTIES_KEY
+ "' found in properties file '" + propertiesFile.getAbsolutePath() + "'");
}
referenceWorkspaceSourceDir = new File(path);
}
private void synchronizedImportMissingReferenceProjectsIntoWorkspace() throws Exception {
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
MultiStatus errorStatus = new MultiStatus(Activator.getPlugin().getSymbolicName(), IStatus.ERROR,
"Problems encountered while importing missing reference projects into workspace.", new RuntimeException());
Set<IProject> missingProjects = getMissingReferenceProjects();
for (IProject project : missingProjects) {
try {
importExternalResourceToWorkspace(new File(referenceWorkspaceSourceDir, project.getName()), project.getParent());
} catch (Exception ex) {
errorStatus.add(StatusUtil.createErrorStatus(Activator.getDefault(), ex));
}
}
if (errorStatus.getChildren().length > 0) {
throw new CoreException(errorStatus);
}
}
};
ResourcesPlugin.getWorkspace().run(runnable, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
ResourcesPlugin.getWorkspace().checkpoint(false);
waitForModelLoading();
}
private Set<IProject> getMissingReferenceProjects() {
Set<IProject> missingReferenceProjects = new HashSet<IProject>();
for (ReferenceProjectDescriptor descriptor : internalRefWks.getReferenceProjectDescriptors()) {
if (!descriptor.getProject().exists()) {
missingReferenceProjects.add(descriptor.getProject());
}
}
return missingReferenceProjects;
}
private Set<IProject> getUnusedReferenceProjects() {
IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
Set<IProject> unusedReferenceProjects = new HashSet<IProject>();
for (IProject project : projects) {
boolean used = false;
for (String prjName : getProjectSubsetToLoad()) {
if (prjName.equals(project.getName())) {
used = true;
}
}
if (!used) {
unusedReferenceProjects.add(project);
}
}
return unusedReferenceProjects;
}
private void synchronizedImportMissingReferenceFilesToWorkspace() throws Exception {
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
MultiStatus errorStatus = new MultiStatus(Activator.getPlugin().getSymbolicName(), IStatus.ERROR,
"Problems encountered while importing missing reference projects into workspace.", new RuntimeException());
for (IFile missingFile : getMissingReferenceFiles()) {
try {
File sourceFile = referenceWorkspaceSourceDir;
for (String segment : missingFile.getFullPath().segments()) {
sourceFile = new File(sourceFile, segment);
}
importExternalResourceToWorkspace(sourceFile, missingFile.getParent());
} catch (Exception ex) {
errorStatus.add(StatusUtil.createErrorStatus(Activator.getDefault(), ex));
}
}
if (errorStatus.getChildren().length > 0) {
throw new CoreException(errorStatus);
}
}
};
ResourcesPlugin.getWorkspace().run(runnable, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
ResourcesPlugin.getWorkspace().checkpoint(false);
waitForModelLoading();
}
private Set<IFile> getMissingReferenceFiles() {
Set<IFile> missingReferenceFiles = new HashSet<IFile>();
for (IFile file : refWks.getAllReferenceFiles()) {
if (!file.exists()) {
missingReferenceFiles.add(file);
}
}
return missingReferenceFiles;
}
private void extractReferenceWorkspaceArchive() throws CoreException {
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
ReferenceWorkspaceExtractor extractor = new ReferenceWorkspaceExtractor();
extractor.extract(getReferenceWorkspaceFileAccessor(), internalRefWks.getReferenceWorkspaceArchiveFileName(),
referenceWorkspaceTempDir);
referenceWorkspaceSourceDir = extractor.getExtractedWorkspaceRootDirectory();
try {
saveReferenceWorkspaceSourceDir();
} catch (Exception ex) {
IStatus status = StatusUtil.createErrorStatus(Activator.getPlugin(), ex);
throw new CoreException(status);
}
}
};
ResourcesPlugin.getWorkspace().run(runnable, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, null);
}
protected abstract T createReferenceWorkspace(Set<String> referenceProjectNames);
private void synchronizedCreateProjectReferences() throws CoreException {
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
MultiStatus errorStatus = new MultiStatus(Activator.getPlugin().getSymbolicName(), IStatus.ERROR,
"Problems encountered while creating project references.", new RuntimeException());
SubMonitor progress = SubMonitor.convert(monitor, ResourcesPlugin.getWorkspace().getRoot().getProjects().length);
for (IProject project : ResourcesPlugin.getWorkspace().getRoot().getProjects()) {
try {
if (project.isAccessible()) {
IProjectDescription projectDescription = project.getDescription();
// Any project references configured for current project?
if (getProjectReferences().containsKey(project.getName())) {
// Set configured project references
projectDescription.setReferencedProjects(toReferenceProjectArray(getProjectReferences().get(project.getName())));
} else {
// Remove all potentially existing project references
projectDescription.setReferencedProjects(new IProject[0]);
}
project.setDescription(projectDescription, progress.newChild(1));
}
} catch (Exception ex) {
errorStatus.add(StatusUtil.createErrorStatus(Activator.getDefault(), ex));
}
}
if (errorStatus.getChildren().length > 0) {
throw new CoreException(errorStatus);
}
}
};
ResourcesPlugin.getWorkspace().run(runnable, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
ResourcesPlugin.getWorkspace().checkpoint(false);
waitForModelLoading();
}
private IProject[] toReferenceProjectArray(Set<String> referenceProjectNames) {
Set<IProject> projects = new HashSet<IProject>(referenceProjectNames.size());
for (String referenceProjectName : referenceProjectNames) {
IProject referenceProject = refWks.getReferenceProject(referenceProjectName);
if (referenceProject != null) {
projects.add(referenceProject);
}
}
return projects.toArray(new IProject[projects.size()]);
}
private void assertReferenceWorkspaceInitialized() throws Exception {
assertExpectedReferenceProjectsExist();
assertExpectedReferenceFilesExist();
assertExpectedReferenceModelResourcesLoaded();
assertExpectedReferenceModelDescriptorsExist();
}
private void assertReferenceWorkspaceConsistent() {
assertNoEmptyModelDescriptorsExist();
assertNoDuplicatedModelDescriptorsExist();
}
private void assertExpectedReferenceProjectsExist() {
Set<IProject> missingReferenceProjects = getMissingReferenceProjects();
if (missingReferenceProjects.size() > 0) {
System.err.println("Missing reference project(s):");
for (IProject project : missingReferenceProjects) {
System.err.println(" " + project.getFullPath());
}
}
assertEquals("Missing reference project(s).", 0, missingReferenceProjects.size());
}
private void assertExpectedReferenceFilesExist() {
Set<IFile> missingReferenceFiles = getMissingReferenceFiles();
if (missingReferenceFiles.size() > 0) {
System.err.println("Missing reference file(s):");
for (IFile file : missingReferenceFiles) {
System.err.println(" " + file.getFullPath());
}
}
assertEquals("Missing reference file(s).", 0, missingReferenceFiles.size());
}
private void assertExpectedReferenceModelResourcesLoaded() {
Map<TransactionalEditingDomain, Set<URI>> missingReferenceModelResources = new HashMap<TransactionalEditingDomain, Set<URI>>();
for (IMetaModelDescriptor metaModelDescriptor : internalRefWks.getReferenceEditingDomainDescritpors().keySet()) {
ReferenceEditingDomainDescriptor editingDomainDescriptor = internalRefWks.getReferenceEditingDomainDescritpors().get(metaModelDescriptor);
TransactionalEditingDomain editingDomain = WorkspaceEditingDomainUtil.getEditingDomain(ResourcesPlugin.getWorkspace().getRoot(),
metaModelDescriptor);
assertNotNull(editingDomain);
Set<URI> actualResourceURIs = new HashSet<URI>();
for (Resource resource : editingDomain.getResourceSet().getResources()) {
actualResourceURIs.add(resource.getURI());
}
Set<URI> missingResourceURIs = new HashSet<URI>(editingDomainDescriptor.getResourceURIs());
missingResourceURIs.removeAll(actualResourceURIs);
if (missingResourceURIs.size() > 0) {
missingReferenceModelResources.put(editingDomain, missingResourceURIs);
}
}
if (missingReferenceModelResources.size() > 0) {
for (TransactionalEditingDomain editingDomain : missingReferenceModelResources.keySet()) {
System.err.println("Missing model resource(s) in editing domain '" + editingDomain.getID() + "':");
Set<URI> missingResourceURIs = missingReferenceModelResources.get(editingDomain);
for (URI uri : missingResourceURIs) {
System.err.println(" " + uri.toString());
}
for (Resource errorResource : resourceProblemListener.getErrorResources()) {
if (missingResourceURIs.contains(errorResource.getURI())) {
if (errorResource.getErrors().get(0) instanceof Exception) {
throw new WrappedException((Exception) errorResource.getErrors().get(0));
} else {
throw new RuntimeException(errorResource.getErrors().get(0).getMessage());
}
}
}
assertEquals("Missing model resource(s) in editing domain '" + editingDomain.getID() + "'. " + missingResourceURIs.toString(), 0,
missingResourceURIs.size());
}
}
}
private void assertExpectedReferenceModelDescriptorsExist() {
Map<IProject, Set<ReferenceModelDescriptor>> missingModelDescriptors = new HashMap<IProject, Set<ReferenceModelDescriptor>>();
for (ReferenceProjectDescriptor referenceProjectDescriptor : internalRefWks.getReferenceProjectDescriptors()) {
Set<ReferenceModelDescriptor> missingModelDescriptorsInProject = new HashSet<ReferenceModelDescriptor>();
missingModelDescriptorsInProject.addAll(referenceProjectDescriptor.getReferenceModelDescriptors());
for (ReferenceModelDescriptor referenceModelDescriptor : referenceProjectDescriptor.getReferenceModelDescriptors()) {
for (IModelDescriptor modelDescriptor : ModelDescriptorRegistry.INSTANCE.getModels(referenceProjectDescriptor.getProject())) {
if (referenceModelDescriptor.getMetaModelDescriptor().equals(modelDescriptor.getMetaModelDescriptor())
&& referenceModelDescriptor.getEditingDomainName().equals(modelDescriptor.getEditingDomain().getID())
&& referenceModelDescriptor.getRootProject().equals(modelDescriptor.getScope().getRoot())) {
missingModelDescriptorsInProject.remove(referenceModelDescriptor);
break;
}
}
}
if (missingModelDescriptorsInProject.size() > 0) {
missingModelDescriptors.put(referenceProjectDescriptor.getProject(), missingModelDescriptorsInProject);
}
}
if (missingModelDescriptors.size() > 0) {
for (IProject project : missingModelDescriptors.keySet()) {
System.err.println("Missing model(s) in project '" + project.getName() + "':");
Set<ReferenceModelDescriptor> missingModelDescriptorsInProject = missingModelDescriptors.get(project);
for (ReferenceModelDescriptor referenceModelDescriptor : missingModelDescriptorsInProject) {
System.err.println(" " + referenceModelDescriptor);
}
assertEquals("Missing model(s) in project '" + project.getName() + "'.", 0, missingModelDescriptorsInProject.size());
}
}
}
private void assertNoEmptyModelDescriptorsExist() {
Set<IModelDescriptor> emptyModelDescriptors = new HashSet<IModelDescriptor>();
for (IModelDescriptor modelDescriptor : ModelDescriptorRegistry.INSTANCE.getAllModels()) {
if (modelDescriptor.getPersistedFiles(true).isEmpty() && modelDescriptor.getLoadedResources(true).isEmpty()) {
emptyModelDescriptors.add(modelDescriptor);
}
}
if (!emptyModelDescriptors.isEmpty()) {
System.err.println("Empty model(s) encountered:");
for (IModelDescriptor emptyModelDescriptor : emptyModelDescriptors) {
System.err.println(" " + emptyModelDescriptor);
}
assertEquals("Empty model(s) encountered.", 0, emptyModelDescriptors.size());
}
}
private void assertNoDuplicatedModelDescriptorsExist() {
Set<IModelDescriptor> duplicatedModelDescriptors = new HashSet<IModelDescriptor>();
Collection<IModelDescriptor> allModels = ModelDescriptorRegistry.INSTANCE.getAllModels();
for (IModelDescriptor modelDescriptor : allModels) {
if (!duplicatedModelDescriptors.contains(modelDescriptor)) {
if (Collections.frequency(allModels, modelDescriptor) > 1) {
duplicatedModelDescriptors.add(modelDescriptor);
}
}
}
if (!duplicatedModelDescriptors.isEmpty()) {
System.err.println("Duplicated model(s) encountered:");
for (IModelDescriptor duplicatedModelDescriptor : duplicatedModelDescriptors) {
System.err.println(" " + duplicatedModelDescriptor);
}
assertEquals("Duplicated model(s) encountered.", 0, duplicatedModelDescriptors.size());
}
}
private void assertReferenceWorkspaceClosed() {
assertAllModelDescriptorsRemoved();
assertAllProjectsClosed();
assertAllModelResourcesUnloaded();
}
private void assertAllModelDescriptorsRemoved() {
assertWorkspaceModelsSizeEquals(0);
}
private void assertAllModelResourcesUnloaded() {
for (TransactionalEditingDomain editingDomain : WorkspaceEditingDomainUtil.getAllEditingDomains()) {
assertEditingDomainResourcesSizeEquals(editingDomain, 0);
}
}
private void assertAllProjectsClosed() {
Set<IProject> openProjects = new HashSet<IProject>();
for (IProject project : ResourcesPlugin.getWorkspace().getRoot().getProjects()) {
if (project.isOpen()) {
openProjects.add(project);
}
}
if (openProjects.size() > 0) {
System.err.println("Unexpected number of open project(s):");
for (IProject project : openProjects) {
System.err.println(" " + project.getFullPath());
}
}
assertTrue("Unexpected number of open project(s).", openProjects.size() == 0);
}
protected void assertEditingDomainResourcesSizeEquals(TransactionalEditingDomain editingDomain, int expected) {
assertNotNull(editingDomain);
EList<Resource> resources = editingDomain.getResourceSet().getResources();
if (expected == 0 && resources.size() > 0) {
System.err.println("Unexpected number of resources in editingDomain " + editingDomain.getID() + ":");
for (Resource resource : resources) {
System.err.println(" " + resource.getURI());
}
}
assertEquals("Unexpected number of resources in editingDomain " + editingDomain.getID(), expected, resources.size());
}
protected void assertEditingDomainDoesNotContainResource(TransactionalEditingDomain editingDomain, Resource resource) {
assertNotNull(editingDomain);
assertFalse(editingDomain.getResourceSet().getResources().contains(resource));
}
protected void assertEditingDomainContainsResource(TransactionalEditingDomain editingDomain, Resource resource) {
assertNotNull(editingDomain);
assertTrue(editingDomain.getResourceSet().getResources().contains(resource));
}
protected void assertEditingDomainContainsResources(TransactionalEditingDomain editingDomain, Collection<Resource> resources) {
assertNotNull(resources);
for (Resource resource : resources) {
assertEditingDomainContainsResource(editingDomain, resource);
}
}
protected void assertEditingDomainDoesNotContainResources(TransactionalEditingDomain editingDomain, Collection<Resource> resources) {
if (resources != null && resources.size() > 0) {
for (Resource resource : resources) {
assertEditingDomainDoesNotContainResource(editingDomain, resource);
}
}
}
// FIXME Consider to rely on URI rather than just resource name
protected void assertEditingDomainContainsResource(TransactionalEditingDomain editingDomain, String resourceName) {
assertNotNull(editingDomain);
assertNotNull(resourceName);
for (Resource res : editingDomain.getResourceSet().getResources()) {
if (resourceName.equals(res.getURI().lastSegment())) {
assertTrue(true);
return;
}
}
assertTrue("Editing domain " + editingDomain.getID() + " does not contain resource named '" + resourceName + "'.", false);
}
// FIXME Consider to rely on URI rather than just resource name
protected void assertEditingDomainDoesNotContainResource(TransactionalEditingDomain editingDomain, String resourceName) {
if (resourceName == null || editingDomain == null) {
assertTrue(true);
return;
}
for (Resource res : editingDomain.getResourceSet().getResources()) {
if (resourceName.equals(res.getURI().lastSegment())) {
assertTrue(false);
}
}
assertTrue(true);
}
// FIXME Consider to rely on URI rather than just resource name
protected void assertEditingDomainContainsNamedResources(TransactionalEditingDomain editingDomain, Collection<String> resourceNames) {
assertNotNull(resourceNames);
if (resourceNames.size() == 0) {
assertTrue(false);
return;
}
for (String resourceName : resourceNames) {
assertEditingDomainContainsResource(editingDomain, resourceName);
}
}
// FIXME Consider to rely on URI rather than just resource name
protected void assertEditingDomainDoesNotContainNamedResources(TransactionalEditingDomain editingDomain, Collection<String> resourceNames) {
if (resourceNames == null) {
assertTrue(true);
return;
}
if (resourceNames.size() == 0) {
assertTrue(true);
return;
}
for (String resourceName : resourceNames) {
assertEditingDomainDoesNotContainResource(editingDomain, resourceName);
}
}
// FIXME Consider to rely on IProject rather than just project name
protected void assertReferenceProjectAllResourcesLoaded(String projectName) {
ReferenceProjectDescriptor referenceProjectDescriptor = internalRefWks.getReferenceProjectDescriptor(projectName);
assertNotNull("Project " + projectName + " does not exist in test reference workspace", referenceProjectDescriptor);
Map<IMetaModelDescriptor, Set<IFile>> files = referenceProjectDescriptor.getFiles();
if (files != null) {
for (IMetaModelDescriptor metaModelDescriptor : files.keySet()) {
if (metaModelDescriptor != MetaModelDescriptorRegistry.NO_MM) {
assertReferenceProjectResourcesLoaded(metaModelDescriptor, projectName);
}
}
}
}
// FIXME Consider to rely on IProject rather than just project name
protected void assertReferenceProjectAllResourcesNotLoaded(String projectName) {
ReferenceProjectDescriptor referenceProjectDescriptor = internalRefWks.getReferenceProjectDescriptor(projectName);
assertNotNull("Project " + projectName + " does not exist in test reference workspace", referenceProjectDescriptor);
Map<IMetaModelDescriptor, Set<IFile>> files = referenceProjectDescriptor.getFiles();
if (files != null) {
for (IMetaModelDescriptor metaModelDescriptor : files.keySet()) {
if (metaModelDescriptor != MetaModelDescriptorRegistry.NO_MM) {
assertReferenceProjectResourcesNotLoaded(metaModelDescriptor, projectName);
}
}
}
}
// FIXME Consider to rely on IProject rather than just project name
protected void assertReferenceProjectResourcesLoaded(IMetaModelDescriptor metaModelDescriptor, String projectName) {
ReferenceProjectDescriptor referenceProjectDescriptor = internalRefWks.getReferenceProjectDescriptor(projectName);
assertNotNull("Project " + projectName + " does not exist in test reference workspace", referenceProjectDescriptor);
assertTrue(referenceProjectDescriptor.getProject().exists());
List<String> filesNames = referenceProjectDescriptor.getFileNames(metaModelDescriptor);
if (internalRefWks.getReferenceEditingDomainDescriptor(metaModelDescriptor) == null) {
assertTrue("No such resources in editing domain descriptor", false);
}
TransactionalEditingDomain editingDomain = WorkspaceEditingDomainUtil.getEditingDomain(ResourcesPlugin.getWorkspace().getRoot(),
metaModelDescriptor);
assertNotNull(editingDomain);
assertEditingDomainContainsNamedResources(editingDomain, filesNames);
}
// FIXME Consider to rely on IProject rather than just project name
protected void assertReferenceProjectResourcesNotLoaded(IMetaModelDescriptor metaModelDescriptor, String projectName) {
ReferenceProjectDescriptor referenceProjectDescriptor = internalRefWks.getReferenceProjectDescriptor(projectName);
assertNotNull(referenceProjectDescriptor);
List<String> filesNames = referenceProjectDescriptor.getFileNames(metaModelDescriptor);
if (internalRefWks.getReferenceEditingDomainDescriptor(metaModelDescriptor) == null) {
assertTrue(true);
return;
}
TransactionalEditingDomain editingDomain = WorkspaceEditingDomainUtil.getEditingDomain(ResourcesPlugin.getWorkspace().getRoot(),
metaModelDescriptor);
assertNotNull(editingDomain);
assertEditingDomainDoesNotContainNamedResources(editingDomain, filesNames);
}
protected void assertWorkspaceModelsSizeEquals(int expected) {
Collection<IModelDescriptor> modelDescriptors = ModelDescriptorRegistry.INSTANCE.getModels(ResourcesPlugin.getWorkspace().getRoot());
if (expected == 0 && modelDescriptors.size() > 0) {
System.err.println("Unexpected number of model descriptor(s) in workspace:");
for (IModelDescriptor modelDescriptor : modelDescriptors) {
System.err.println(" " + modelDescriptor);
}
}
assertEquals("Unexpected number of model descriptors in workspace.", expected, modelDescriptors.size());
}
protected void assertProjectModelsSizeEquals(IProject project, int expected) {
Collection<IModelDescriptor> modelDescriptors = ModelDescriptorRegistry.INSTANCE.getModels(project);
if (expected == 0 && modelDescriptors.size() > 0) {
System.err.println("Unexpected number of model descriptor(s) in project '" + project.getName() + "':");
for (IModelDescriptor modelDescriptor : modelDescriptors) {
System.err.println(" " + modelDescriptor);
}
}
assertEquals("Unexpected number of model descriptor(s) in project '" + project.getName() + "'.", expected, modelDescriptors.size());
}
protected void assertProjectHasModels(IProject project, IMetaModelDescriptor metaModelDescriptor) {
Collection<IModelDescriptor> models = ModelDescriptorRegistry.INSTANCE.getModels(project, metaModelDescriptor);
assertTrue("Missing '" + metaModelDescriptor + "' model descriptor in project '" + project.getName() + "'.", !models.isEmpty());
}
protected void assertProjectHasNoModels(IProject project, IMetaModelDescriptor metaModelDescriptor) {
Collection<IModelDescriptor> models = ModelDescriptorRegistry.INSTANCE.getModels(project, metaModelDescriptor);
assertTrue("Unexpected '" + metaModelDescriptor + "' model descriptor in project '" + project.getName() + "'.", models.isEmpty());
}
protected void synchronizedLoadFile(IFile file) {
ModelLoadManager.INSTANCE.loadFile(file, true, null);
waitForModelLoading();
}
protected void synchronizedUnloadFile(IFile file) {
ModelLoadManager.INSTANCE.unloadFile(file, true, null);
waitForModelLoading();
}
protected void synchronizedDeleteFile(final IFile file) throws CoreException {
assertNotNull(file);
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
file.delete(true, true, monitor);
}
};
ResourcesPlugin.getWorkspace().run(runnable, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
ResourcesPlugin.getWorkspace().checkpoint(false);
waitForModelLoading();
}
protected void synchronizedMoveFile(final IFile file, final IPath target) throws CoreException {
assertNotNull(file);
assertNotNull(target);
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
file.move(target, true, new NullProgressMonitor());
}
};
ResourcesPlugin.getWorkspace().run(runnable, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
ResourcesPlugin.getWorkspace().checkpoint(false);
waitForModelLoading();
}
protected void synchronizedRenameFile(final IFile file, final String newname) throws CoreException {
assertNotNull(file);
assertNotNull(newname);
assertFalse(newname.length() == 0);
final IPath newPath = file.getFullPath().removeLastSegments(1).append(newname);
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
file.move(newPath, true, new NullProgressMonitor());
}
};
ResourcesPlugin.getWorkspace().run(runnable, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
ResourcesPlugin.getWorkspace().checkpoint(false);
waitForModelLoading();
}
protected void synchronizedSetFileContents(final IFile file, final InputStream source) throws CoreException {
assertNotNull(source);
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
file.setContents(source, true, true, monitor);
}
};
ResourcesPlugin.getWorkspace().run(runnable, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
file.refreshLocal(IResource.DEPTH_ZERO, new NullProgressMonitor());
waitForModelLoading();
}
/**
* Deletes external file or directory with specified <code>path</code>. If external resource is a directory then all
* files and subdirectories under this directory are deleted. If it is a file then only the file is deleted.
*
* @param path
* The path of the file or directory to be deleted.
* @throws IOException
* If a deletion of some file or directory fails; no attempts to delete remaining files or directories
* are made in this case.
*/
protected void deleteExternalResource(String path) throws IOException {
URI uri = URI.createURI(path, true);
URI fileURI = EcoreResourceUtil.convertToAbsoluteFileURI(uri);
File file = new File(fileURI.toFileString());
deleteExternalResource(file);
}
/**
* Deletes specified external <code>file</code>. If external file is a directory then all files and subdirectories
* under this directory are deleted. If it is a file then only the file is deleted.
*
* @param path
* The file or directory to be deleted.
* @throws IOException
* If a deletion of some file or directory fails; no attempts to delete remaining files or directories
* are made in this case.
*/
protected void deleteExternalResource(File file) throws IOException {
Assert.isNotNull(file);
if (file.isDirectory()) {
String[] children = file.list();
// Delete the files and directories in directory to be deleted
for (String child : children) {
deleteExternalResource(new File(file, child));
}
// The directory is now empty so delete it
if (!file.delete()) {
throw new IOException("Unable to delete external directory: '" + file.getPath() + "'");
}
} else {
if (file.exists()) {
if (!file.delete()) {
throw new IOException("Unable to delete external file: '" + file.getPath() + "'");
}
}
}
}
protected void synchronizedDeleteFolder(final IFolder folder) throws Exception {
assertNotNull(folder);
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
folder.delete(true, true, monitor);
}
};
ResourcesPlugin.getWorkspace().run(runnable, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
ResourcesPlugin.getWorkspace().checkpoint(false);
waitForModelLoading();
}
protected void synchronizedMoveFolder(final IFolder folder, final IPath target) throws CoreException {
assertNotNull(folder);
assertNotNull(target);
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
folder.move(target, true, new NullProgressMonitor());
}
};
ResourcesPlugin.getWorkspace().run(runnable, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
ResourcesPlugin.getWorkspace().checkpoint(false);
waitForModelLoading();
}
protected void synchronizedLoadProject(IProject project, boolean includeReferencedProjects) {
ModelLoadManager.INSTANCE.loadProject(project, includeReferencedProjects, true, null);
waitForModelLoading();
}
protected void synchronizedLoadAllProjects() {
ModelLoadManager.INSTANCE.loadProjects(Arrays.asList(ResourcesPlugin.getWorkspace().getRoot().getProjects()), true, true, null);
waitForModelLoading();
}
protected void synchronizedUnloadProject(IProject project, boolean includeReferencedProjects) {
ModelLoadManager.INSTANCE.unloadProject(project, includeReferencedProjects, true, null);
waitForModelLoading();
}
protected void synchronizedUnloadProjects(Collection<IProject> projectsToUnload, boolean includeReferenceProjects) {
ModelLoadManager.INSTANCE.unloadProjects(projectsToUnload, includeReferenceProjects, true, null);
waitForModelLoading();
}
protected void synchronizedUnloadAllProjects() {
ModelLoadManager.INSTANCE.unloadProjects(Arrays.asList(ResourcesPlugin.getWorkspace().getRoot().getProjects()), false, true, null);
waitForModelLoading();
}
protected void synchronizedOpenProject(final IProject project) throws Exception {
assertNotNull(project);
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
project.open(monitor);
}
};
ResourcesPlugin.getWorkspace().run(runnable, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
ResourcesPlugin.getWorkspace().checkpoint(false);
waitForModelLoading();
}
protected void synchronizedOpenProjects(final Collection<IProject> projects) throws Exception {
assertNotNull(projects);
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
for (IProject project : projects) {
project.open(monitor);
}
}
};
ResourcesPlugin.getWorkspace().run(runnable, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
ResourcesPlugin.getWorkspace().checkpoint(false);
waitForModelLoading();
}
protected void synchronizedOpenAllProjects() throws Exception {
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
MultiStatus errorStatus = new MultiStatus(Activator.getPlugin().getSymbolicName(), IStatus.ERROR,
"Problems encountered while opening projects.", new RuntimeException());
SubMonitor progress = SubMonitor.convert(monitor, ResourcesPlugin.getWorkspace().getRoot().getProjects().length);
for (IProject project : ResourcesPlugin.getWorkspace().getRoot().getProjects()) {
try {
project.open(progress.newChild(1));
} catch (CoreException ex) {
errorStatus.add(ex.getStatus());
}
}
if (errorStatus.getChildren().length > 0) {
throw new CoreException(errorStatus);
}
}
};
ResourcesPlugin.getWorkspace().run(runnable, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
ResourcesPlugin.getWorkspace().checkpoint(false);
waitForModelLoading();
}
protected void synchronizedRenameProject(final IProject project, final String newName) throws Exception {
assertNotNull(project);
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
project.move(project.getFullPath().removeLastSegments(1).append(newName), true, monitor);
}
};
ResourcesPlugin.getWorkspace().run(runnable, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
ResourcesPlugin.getWorkspace().checkpoint(false);
waitForModelLoading();
}
protected void synchronizedCloseProject(final IProject project) throws Exception {
assertNotNull(project);
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
project.close(monitor);
}
};
ResourcesPlugin.getWorkspace().run(runnable, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
ResourcesPlugin.getWorkspace().checkpoint(false);
waitForModelLoading();
}
protected void synchronizedCloseAllProjects() throws Exception {
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
MultiStatus errorStatus = new MultiStatus(Activator.getPlugin().getSymbolicName(), IStatus.ERROR,
"Problems encountered while closing projects.", new RuntimeException());
Collection<IProject> safeProjects = new ArrayList<IProject>(Arrays.asList(ResourcesPlugin.getWorkspace().getRoot().getProjects()));
SubMonitor progress = SubMonitor.convert(monitor, safeProjects.size());
for (IProject project : safeProjects) {
try {
project.close(progress.newChild(1));
} catch (CoreException ex) {
errorStatus.add(ex.getStatus());
}
}
if (errorStatus.getChildren().length > 0) {
throw new CoreException(errorStatus);
}
}
};
ResourcesPlugin.getWorkspace().run(runnable, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
ResourcesPlugin.getWorkspace().checkpoint(false);
waitForModelLoading();
}
protected void synchronizedDeleteProject(final IProject project) throws Exception {
assertNotNull(project);
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
safeDeleteProject(project, monitor);
}
};
ResourcesPlugin.getWorkspace().run(runnable, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
ResourcesPlugin.getWorkspace().checkpoint(false);
waitForModelLoading();
}
protected void synchronizedDeleteProjects(final Collection<IProject> projects) throws Exception {
assertNotNull(projects);
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
MultiStatus errorStatus = new MultiStatus(Activator.getPlugin().getSymbolicName(), IStatus.ERROR,
"Problems encountered while closing projects.", new RuntimeException());
SubMonitor progress = SubMonitor.convert(monitor, projects.size());
for (IProject project : projects) {
try {
safeDeleteProject(project, progress.newChild(1));
} catch (CoreException ex) {
errorStatus.add(ex.getStatus());
}
}
if (errorStatus.getChildren().length > 0) {
throw new CoreException(errorStatus);
}
}
};
ResourcesPlugin.getWorkspace().run(runnable, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
ResourcesPlugin.getWorkspace().checkpoint(false);
waitForModelLoading();
}
private void safeDeleteProject(IProject project, IProgressMonitor monitor) throws CoreException {
/*
* !! Important Note !! There may be processes in different threads that periodically lock files in the project
* under deletion (e.g. Java Indexing). This lets project deletions sporadically end up in CoreExceptions with
* the message "Problems encountered while deleting files.". Since it's just a test, we simply try to repeat the
* project deletion a couple times with a random wait of a second or two in between attempts. This should
* normally reduce the rate of failures down to "good enough".
*/
for (int i = 0; i < 5; i++) {
try {
project.delete(true, true, monitor);
return;
} catch (CoreException ex) {
if (i == 4) {
throw ex;
} else {
try {
Thread.sleep(500 + Math.round(1500 * Math.random()));
} catch (InterruptedException iex) {
// Ignore exception
}
}
}
}
}
protected void synchronizedDeleteWorkspace() throws CoreException {
final IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
workspace.getRoot().delete(true, true, null);
}
};
workspace.run(runnable, workspace.getRoot(), IWorkspace.AVOID_UPDATE, null);
workspace.checkpoint(false);
waitForModelLoading();
}
protected Resource getProjectResource(IProject project, String fileName) {
assertNotNull(project);
assertNotNull(fileName);
IFile file = project.getFile(fileName);
return EcorePlatformUtil.getResource(file);
}
protected Collection<IFile> getAllModelFiles() {
Collection<IFile> allFiles = new HashSet<IFile>();
for (IProject project : ExtendedPlatform.getRootProjects()) {
for (IFile file : ExtendedPlatform.getAllFiles(project, true)) {
final String fileName = file.getName();
final String fileExtension = file.getFileExtension();
if (!fileName.startsWith(".") && !hasDotParent(file) && !fileExtension.equals("java") && !fileExtension.equals("xtend")
&& !fileExtension.equals("_trace") && !fileExtension.equals("class") && !fileExtension.equals("MF")
&& !fileName.equals("pom.xml") && !fileName.equals("plugin.xml") && !fileName.equals("plugin.properties")
&& !fileName.equals("build.properties")) {
allFiles.add(file);
}
}
}
return allFiles;
}
private boolean hasDotParent(IResource resource) {
assertNotNull(resource);
IContainer parent = resource.getParent();
if (parent != null) {
if (parent.getName().startsWith(".")) {
return true;
}
return hasDotParent(parent);
}
return false;
}
protected void assertProxiesResolved(Resource inputResource) {
assertNotNull(inputResource);
for (TreeIterator<EObject> allContents = inputResource.getAllContents(); allContents.hasNext();) {
EObject object = allContents.next();
assertFalse(object.eIsProxy());
}
}
/**
* Blocks the calling thread until model loading completes.
*/
protected void waitForModelLoading() {
waitForFamily(IExtendedPlatformConstants.FAMILY_MODEL_LOADING);
}
/**
* Blocks the calling thread until model loading completes.
*/
protected void waitForModelSaving() {
waitForFamily(IExtendedPlatformConstants.FAMILY_MODEL_SAVING);
}
/**
* Blocks the calling thread until automatic build completes.
*/
protected void waitForAutoBuild() {
waitForFamily(ResourcesPlugin.FAMILY_AUTO_BUILD);
}
/**
* Blocks the calling thread until the specified job family completes.
*/
private void waitForFamily(final Object family) {
// wait in a separate thread to realize a timeout to avoid potentially waiting forever
Thread t = new Thread() {
@Override
public void run() {
try {
Job.getJobManager().join(family, null);
} catch (Exception ex) {
// Ignore exception
}
}
};
t.setDaemon(true);
t.start();
try {
t.join(Integer.parseInt(JOB_FAMILY_TIMEOUT));
} catch (InterruptedException ex) {
// Ignore exception
}
if (t.isAlive()) {
throw new RuntimeException("Timeout while waiting for job family '" + family + "'.");
}
}
private class ModelLoadingJobTracer extends JobChangeAdapter {
private boolean isModelLoadingJob(IJobChangeEvent event) {
if (event != null) {
Job job = event.getJob();
if (job != null) {
return job.belongsTo(IExtendedPlatformConstants.FAMILY_MODEL_LOADING);
}
}
return false;
}
@Override
public void scheduled(IJobChangeEvent event) {
if (isModelLoadingJob(event)) {
// TODO Surround with appropriate tracing option
// System.out.println("Model loading job '" + event.getJob().getName() + "' -> SCHEDULED");
}
}
@Override
public void running(IJobChangeEvent event) {
if (isModelLoadingJob(event)) {
// TODO Surround with appropriate tracing option
// System.out.println("Model loading job '" + event.getJob().getName() + "' -> RUNNING");
}
}
@Override
public void done(IJobChangeEvent event) {
if (isModelLoadingJob(event)) {
// TODO Surround with appropriate tracing option
// System.out.println("Model loading job '" + event.getJob().getName() + "' -> DONE");
}
}
}
protected void importExternalResourceToWorkspace(File externalResource, IContainer targetContainer) throws Exception {
assertNotNull(externalResource);
assertNotNull(targetContainer);
if (externalResource.exists()) {
if (externalResource.isDirectory()) {
// Copy files and folders inside external directory to target container
IContainer importedContainer;
if (targetContainer instanceof IWorkspaceRoot) {
importedContainer = ((IWorkspaceRoot) targetContainer).getProject(externalResource.getName());
} else {
importedContainer = targetContainer.getFolder(new Path(externalResource.getName()));
}
for (File file : externalResource.listFiles()) {
importExternalResourceToWorkspace(file, importedContainer);
}
} else {
// Make sure that target container exists
createContainerTree(targetContainer);
// Copy external file to target container
IFile importedFile = targetContainer.getFile(new Path(externalResource.getName()));
InputStream externalFileContents = new FileInputStream(externalResource);
if (importedFile.exists()) {
// Overwrite old file's contents
importedFile.setCharset(null, null);
importedFile.setContents(externalFileContents, true, false, null);
} else {
// Create new file in target container
try {
importedFile.create(externalFileContents, true, null);
importedFile.setCharset(null, null);
} catch (Exception ex) {
// Exception complaining that imported file already exists?
if (ex.getMessage().contains("already exists")) {
// Overwrite existing file's contents
externalFileContents = new FileInputStream(externalResource);
importedFile.setCharset(null, null);
importedFile.setContents(externalFileContents, true, false, null);
} else {
throw ex;
}
}
}
importedFile.refreshLocal(IResource.DEPTH_ZERO, new NullProgressMonitor());
}
}
}
/**
* Creates project and/or any missing folders on path of given container.
*
* @param container
* The container to be processed.
* @throws Exception
*/
private void createContainerTree(IContainer container) throws Exception {
Assert.isNotNull(container);
IProject project = container.getProject();
if (!project.exists()) {
project.create(null);
project.open(null);
} else if (!project.isAccessible()) {
project.open(null);
}
if (container.getFullPath().segmentCount() > 1) {
IContainer parentContainer = project;
for (int i = 1; i < container.getFullPath().segmentCount(); i++) {
IFolder folder = parentContainer.getFolder(new Path(container.getFullPath().segment(i)));
if (!folder.exists()) {
try {
folder.create(true, true, null);
} catch (Exception ex) {
if (ex.getMessage().contains("already exists")) {
// Do nothing
} else {
throw ex;
}
}
}
parentContainer = folder;
}
}
}
protected void synchronizedImportExternalResourceToWorkspace(final File externalResource, final IContainer targetContainer) throws Exception {
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
try {
importExternalResourceToWorkspace(externalResource, targetContainer);
} catch (Exception ex) {
IStatus status = StatusUtil.createErrorStatus(Activator.getPlugin(), ex);
throw new CoreException(status);
}
}
};
ResourcesPlugin.getWorkspace().run(runnable, ResourcesPlugin.getWorkspace().getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
ResourcesPlugin.getWorkspace().checkpoint(false);
waitForModelLoading();
}
protected void synchronizedImportInputFileToWorkspace(String inputFileName, IContainer targetContainer) throws Exception {
java.net.URI inputFileURI = getTestFileAccessor().getInputFileURI(inputFileName, true);
synchronizedImportExternalResourceToWorkspace(new File(inputFileURI), targetContainer);
}
protected ReferenceWorkspaceChangeListener getReferenceWorkspaceChangeListener() {
return referenceWorkspaceChangeListener;
}
}