/**
* 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.sca.ui.wizards;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileInfo;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.IJobChangeListener;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.progress.UIJob;
import gov.redhawk.model.sca.DomainConnectionException;
import gov.redhawk.model.sca.RefreshDepth;
import gov.redhawk.model.sca.ScaDomainManager;
import gov.redhawk.model.sca.ScaDomainManagerFileSystem;
import gov.redhawk.model.sca.ScaFactory;
import gov.redhawk.model.sca.WaveformsContainer;
import gov.redhawk.sca.ScaPlugin;
import gov.redhawk.sca.preferences.ScaPreferenceConstants;
import gov.redhawk.sca.ui.ScaUiPlugin;
import mil.jpeojtrs.sca.sad.SadPackage;
import mil.jpeojtrs.sca.sad.SoftwareAssembly;
import mil.jpeojtrs.sca.util.ScaResourceFactoryUtil;
/**
* @since 9.0
*
*/
public class InstallApplicationContentProvider implements ITreeContentProvider {
private List<SoftwareAssembly> children;
private class RefreshJob extends UIJob {
public RefreshJob(final Display jobDisplay) {
super(jobDisplay, "Refreshing");
}
@Override
public IStatus runInUIThread(final IProgressMonitor monitor) {
if (!InstallApplicationContentProvider.this.viewer.getControl().isDisposed()) {
InstallApplicationContentProvider.this.viewer.refresh();
}
return Status.OK_STATUS;
}
};
private final Job fetchChildrenJob = new Job("Loading...") {
{
setSystem(true);
}
@Override
public boolean shouldSchedule() {
return super.shouldSchedule() && children == null;
}
@Override
public boolean shouldRun() {
return super.shouldRun() && children == null;
}
@Override
protected IStatus run(final IProgressMonitor monitor) {
if (children != null) {
return Status.CANCEL_STATUS;
}
final MultiStatus mergedStatus = new MultiStatus(ScaUiPlugin.PLUGIN_ID, IStatus.WARNING, "Problems while loading SAD files.", null);
InstallApplicationContentProvider.this.children = InstallApplicationContentProvider.fetchDeferredChildren(InstallApplicationContentProvider.this.input, monitor,
mergedStatus);
InstallApplicationContentProvider.this.refreshJob.schedule();
if (!mergedStatus.isOK()) {
InstallApplicationContentProvider.this.loadStatus = mergedStatus;
} else {
InstallApplicationContentProvider.this.loadStatus = Status.OK_STATUS;
}
return Status.OK_STATUS;
}
@Override
public String toString() {
return getName();
}
};
private Viewer viewer;
private RefreshJob refreshJob;
private ScaDomainManager input;
private IStatus loadStatus;
/**
* Returns the status of loading the SAD files from the domain.
* @since 9.0
*/
public IStatus getLoadStatus() {
return this.loadStatus;
}
@Override
public void dispose() {
this.children = null;
}
@Override
public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) {
this.viewer = viewer;
if (viewer != null) {
this.refreshJob = new RefreshJob(viewer.getControl().getDisplay());
}
this.input = (ScaDomainManager) newInput;
}
/**
* @since 9.0
*/
public void addContentCompletionListener(final IJobChangeListener listener) {
this.fetchChildrenJob.addJobChangeListener(listener);
}
@Override
public Object[] getElements(final Object inputElement) {
return getChildren(inputElement);
}
public List<SoftwareAssembly> getChildren() {
if (this.children != null) {
return Collections.unmodifiableList(this.children);
} else {
return Collections.emptyList();
}
}
@Override
public Object[] getChildren(final Object parentElement) {
if (parentElement instanceof ScaDomainManager) {
if (this.children == null) {
this.fetchChildrenJob.schedule();
return new Object[] { this.fetchChildrenJob };
} else {
return createNamespaceStructure(this.children);
}
} else if (parentElement instanceof WaveformsContainer) {
WaveformsContainer container = (WaveformsContainer) parentElement;
List<Object> containerChildren = new ArrayList<Object>();
containerChildren.addAll(container.getSubContainers());
containerChildren.addAll(container.getWaveforms());
return containerChildren.toArray();
}
return Collections.EMPTY_LIST.toArray();
}
private Object[] createNamespaceStructure(List<SoftwareAssembly> sadList) {
List<Object> retList = new ArrayList<Object>();
List<WaveformsContainer> waveformContainers = new ArrayList<WaveformsContainer>();
for (SoftwareAssembly sad : sadList) {
String name = sad.getName();
if (name != null && name.contains(".")) {
createSubContainers(sad, waveformContainers);
} else {
retList.add(sad);
}
}
retList.addAll(waveformContainers);
return retList.toArray();
}
private void createSubContainers(SoftwareAssembly sad, List<WaveformsContainer> topLevelContainers) {
// Namespaces are all segments of the name except the last (the 'basename')
String[] names = sad.getName().split("\\.");
int numContainers = names.length - 1;
List<WaveformsContainer> containerList = new ArrayList<WaveformsContainer>();
// Create containers for each namespace
for (int i = 0; i < numContainers; i++) {
WaveformsContainer container = null;
if (i == 0) {
// Top-level namespace -- check if a container already exists
for (WaveformsContainer topLevelContainer : topLevelContainers) {
if (names[i].equals(topLevelContainer.getContainerName())) {
container = topLevelContainer;
break;
}
}
// Create a new container if we couldn't find an existing one
if (container == null) {
container = ScaFactory.eINSTANCE.createWaveformsContainer();
container.setContainerName(names[i]);
topLevelContainers.add(container);
}
} else {
// Namespace OTHER than top-level -- check if its parent already has a container for the namespace
WaveformsContainer parent = containerList.get(i - 1);
for (WaveformsContainer child : parent.getSubContainers()) {
if (names[i].equals(child.getContainerName())) {
container = child;
break;
}
}
// Create a new container if we couldn't find an existing one
if (container == null) {
container = ScaFactory.eINSTANCE.createWaveformsContainer();
container.setContainerName(names[i]);
parent.getSubContainers().add(container);
}
}
// Keep track of the containers for this waveform
containerList.add(container);
}
// Add the waveform to the final container
containerList.get(numContainers - 1).getWaveforms().add(sad);
}
@Override
public Object getParent(final Object element) {
return null;
}
@Override
public boolean hasChildren(final Object element) {
if (element instanceof ScaDomainManager) {
return true;
} else if (element instanceof WaveformsContainer) {
return true;
}
return false;
}
private static List<SoftwareAssembly> fetchDeferredChildren(final ScaDomainManager domMgr, final IProgressMonitor monitor, final MultiStatus status) {
try {
if (domMgr != null) {
try {
final SubMonitor subMonitor = SubMonitor.convert(monitor, "Fetching SAD files...", 3);
domMgr.connect(subMonitor.newChild(1), RefreshDepth.SELF);
final ScaDomainManagerFileSystem fileManager = domMgr.fetchFileManager(subMonitor.newChild(1), RefreshDepth.SELF);
if (fileManager != null) {
final IFileStore fileStore = fileManager.getFileStore();
final ResourceSet resourceSet = ScaResourceFactoryUtil.createResourceSet();
final String[] paths = ScaPreferenceConstants.parsePath(ScaPlugin.getDefault()
.getScaPreferenceAccessor()
.getString(ScaPreferenceConstants.SCA_DOMAIN_WAVEFORMS_SEARCH_PATH));
return InstallApplicationContentProvider.fetchAssemblies(domMgr, resourceSet, fileStore, paths, status);
} else {
final IllegalStateException exception = new IllegalStateException("No file manager available");
exception.fillInStackTrace();
status.add(new Status(IStatus.ERROR, ScaUiPlugin.PLUGIN_ID, "Failed to load SAD files: " + exception.getMessage(), exception));
}
} catch (final DomainConnectionException e1) {
status.add(new Status(IStatus.ERROR, ScaUiPlugin.PLUGIN_ID, "Failed to connect to domain: " + domMgr.getLabel(), e1));
}
}
return Collections.emptyList();
} finally {
monitor.done();
}
}
private static List<SoftwareAssembly> fetchAssemblies(final ScaDomainManager domMgr, final ResourceSet resourceSet, final IFileStore fileStore, final String[] paths, final MultiStatus status) {
IFileInfo info;
try {
info = fileStore.fetchInfo(EFS.NONE, null);
} catch (final CoreException e1) {
status.add(new Status(e1.getStatus().getSeverity(), ScaUiPlugin.PLUGIN_ID, e1.getLocalizedMessage(), e1));
return Collections.emptyList();
}
boolean proceed = false;
final String fileStorePath = fileStore.toURI().getPath();
if (fileStorePath.length() == 0) {
proceed = true;
} else if (fileStore.getName().charAt(0) != '.') {
final IFileStore parent = fileStore.getParent();
if (parent.getParent() != null) {
proceed = true;
} else {
if (paths.length == 0) {
proceed = true;
} else {
for (final String s : paths) {
if (fileStorePath.contains(s)) {
proceed = true;
break;
}
}
}
}
}
if (!proceed) {
return Collections.emptyList();
}
if (info.isDirectory()) {
final ArrayList<SoftwareAssembly> retVal = new ArrayList<SoftwareAssembly>();
try {
final IFileStore[] stores = fileStore.childStores(0, null);
for (final IFileStore child : stores) {
try {
retVal.addAll(InstallApplicationContentProvider.fetchAssemblies(domMgr, resourceSet, child, paths, status));
} catch (WrappedException we) {
String uriPath = child.toURI().getPath();
status.add(new Status(Status.WARNING, ScaUiPlugin.PLUGIN_ID,
"Failed to load SAD file: " + uriPath + " from Domain: " + domMgr.getLabel(), we));
}
}
} catch (final CoreException e) {
status.add(new Status(e.getStatus().getSeverity(), ScaUiPlugin.PLUGIN_ID, e.getLocalizedMessage(), e));
}
return retVal;
} else {
if (!fileStore.getName().endsWith(SadPackage.FILE_EXTENSION)) {
return Collections.emptyList();
}
final URI uri = fileStore.toURI();
final Resource sadResource = resourceSet.getResource(org.eclipse.emf.common.util.URI.createURI(uri.toString()), true);
try {
final SoftwareAssembly sad = SoftwareAssembly.Util.getSoftwareAssembly(sadResource);
if (sad != null) {
return Collections.singletonList(sad);
}
} catch (final Exception e) { // SUPPRESS CHECKSTYLE Logged Error
status.add(new Status(IStatus.WARNING, ScaUiPlugin.PLUGIN_ID, "Failed to parse SAD file: " + uri.getPath(), e));
}
return Collections.emptyList();
}
}
/**
* @deprecated Use {@link #addContentCompletionListener(IJobChangeListener)} instead
* @param jobChangeAdapter
* @since 9.0
*/
@Deprecated
public void setContentCompletionListener(final IJobChangeListener jobChangeAdapter) {
addContentCompletionListener(jobChangeAdapter);
}
}