/*******************************************************************************
* This file is protected by Copyright.
* Please refer to the COPYRIGHT file distributed with this source distribution.
*
* This file is part of REDHAWK IDE.
*
* 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
*******************************************************************************/
package gov.redhawk.ide.debug.internal;
import gov.redhawk.core.resourcefactory.AbstractResourceFactoryProvider;
import gov.redhawk.core.resourcefactory.ComponentDesc;
import gov.redhawk.core.resourcefactory.ResourceDesc;
import gov.redhawk.ide.debug.ScaDebugPlugin;
import gov.redhawk.ide.debug.SpdResourceFactory;
import gov.redhawk.ide.natures.ScaProjectNature;
import gov.redhawk.model.sca.ScaModelPlugin;
import gov.redhawk.sca.util.Debug;
import gov.redhawk.sca.util.MutexRule;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import mil.jpeojtrs.sca.spd.SoftPkg;
import mil.jpeojtrs.sca.spd.SpdPackage;
import mil.jpeojtrs.sca.util.ScaResourceFactoryUtil;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceVisitor;
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.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.emf.ecore.resource.ResourceSet;
import CF.ResourceFactoryOperations;
/**
* Provides descriptions of resources in the workspace which can be launched in the sandbox.
*/
public class WorkspaceResourceFactoryProvider extends AbstractResourceFactoryProvider {
private static final MutexRule RULE = new MutexRule(WorkspaceResourceFactoryProvider.class);
private static final String WORKSPACE_CATEGORY = "Workspace";
private static final Debug TRACE_LOGGER = new Debug(ScaModelPlugin.ID, "WorkspaceResourceFactoryProvider");
private final IResourceChangeListener listener = new IResourceChangeListener() {
@Override
public void resourceChanged(final IResourceChangeEvent event) {
if (disposed) {
return;
}
try {
if (event.getResource() == null || !WorkspaceResourceFactoryProvider.shouldVisit(event.getResource().getProject())) {
return;
}
} catch (final CoreException e1) {
return;
}
switch (event.getType()) {
case IResourceChangeEvent.PRE_REFRESH:
case IResourceChangeEvent.POST_CHANGE:
if (event.getResource() instanceof IFile) {
final IFile file = (IFile) event.getResource();
if (file.getName().endsWith(SpdPackage.FILE_EXTENSION)) {
addSpdResource(file);
}
} else if (event.getResource() instanceof IProject) {
final IProject project = (IProject) event.getResource();
try {
for (final IResource resource : project.members()) {
if (resource instanceof IFile) {
final IFile file = (IFile) resource;
if (resource.getName().endsWith(SpdPackage.FILE_EXTENSION)) {
addSpdResource(file);
}
}
}
} catch (CoreException e) {
ScaDebugPlugin.getInstance().getLog().log(new Status(IStatus.ERROR, ScaDebugPlugin.ID,
"Failed to search project contents for new resources to add: " + event.getResource().getFullPath(), e));
}
}
break;
case IResourceChangeEvent.PRE_CLOSE:
case IResourceChangeEvent.PRE_DELETE:
if (event.getResource() instanceof IFile) {
removeComponent((IFile) event.getResource());
} else if (event.getResource() instanceof IProject) {
final IProject project = (IProject) event.getResource();
try {
for (final IResource resource : project.members()) {
if (resource instanceof IFile) {
final IFile file = (IFile) resource;
if (resource.getName().endsWith(SpdPackage.FILE_EXTENSION)) {
removeComponent(file);
}
}
}
} catch (final CoreException e) {
// PASS
}
}
break;
default:
break;
}
}
};
private final Map<IFile, ResourceDesc> componentMap = Collections.synchronizedMap(new HashMap<IFile, ResourceDesc>());
private boolean disposed;
public WorkspaceResourceFactoryProvider() {
try {
ResourcesPlugin.getWorkspace().getRoot().accept(new IResourceVisitor() {
@Override
public boolean visit(final IResource resource) throws CoreException {
if (resource instanceof IWorkspaceRoot) {
return true;
} else if (resource instanceof IProject) {
return WorkspaceResourceFactoryProvider.shouldVisit((IProject) resource);
} else if (resource instanceof IFile && resource.getName().endsWith(SpdPackage.FILE_EXTENSION)) {
addSpdResource((IFile) resource);
}
return false;
}
});
} catch (final CoreException e) {
ScaDebugPlugin.getInstance().getLog().log(
new Status(e.getStatus().getSeverity(), ScaDebugPlugin.ID, "Error while to creating WorkspaceResourceFactoryProvider", e));
}
ResourcesPlugin.getWorkspace().addResourceChangeListener(this.listener,
IResourceChangeEvent.POST_CHANGE | IResourceChangeEvent.PRE_CLOSE | IResourceChangeEvent.PRE_DELETE | IResourceChangeEvent.PRE_REFRESH);
}
private SoftPkg loadSpd(IFile resource) {
try {
final ResourceSet resourceSet = ScaResourceFactoryUtil.createResourceSet();
final SoftPkg spd = SoftPkg.Util.getSoftPkg(
resourceSet.getResource(URI.createPlatformResourceURI(resource.getFullPath().toPortableString(), true), true));
return spd;
} catch (WrappedException we) {
if (TRACE_LOGGER.enabled) {
TRACE_LOGGER.catching("Unable to load SPD: " + resource, we);
}
return null;
}
}
private void addSpdResource(final IFile resource) {
if (componentMap.containsKey(resource)) {
// Remove old component previously mapped
removeComponent(resource);
}
SoftPkg spd = loadSpd(resource);
if (spd == null) {
return;
}
ResourceFactoryOperations resourceFactory;
try {
resourceFactory = SpdResourceFactory.createResourceFactory(spd);
} catch (IllegalArgumentException e) {
// Ignore invalid SPDs
return;
}
ComponentDesc desc = new ComponentDesc(spd, resourceFactory);
desc.setCategory(WORKSPACE_CATEGORY);
this.componentMap.put(resource, desc);
addResourceDesc(desc);
}
private void removeComponent(final IFile resource) {
final ResourceDesc desc = this.componentMap.remove(resource);
if (desc != null) {
removeResourceDesc(desc);
}
}
public static boolean shouldVisit(final IProject project) throws CoreException {
if (!project.isOpen()) {
return false;
}
final IProjectDescription desc = project.getDescription();
final List<String> natures = Arrays.asList(desc.getNatureIds());
return natures.contains(ScaProjectNature.ID) && desc.getName().charAt(0) != '.';
}
@Override
public void dispose() {
Job.getJobManager().beginRule(RULE, null);
try {
if (disposed) {
return;
}
disposed = true;
} finally {
Job.getJobManager().endRule(RULE);
}
ResourcesPlugin.getWorkspace().removeResourceChangeListener(this.listener);
synchronized (this.componentMap) {
for (final ResourceDesc desc : this.componentMap.values()) {
removeResourceDesc(desc);
}
this.componentMap.clear();
}
}
}