/*******************************************************************************
* Copyright (c) 2011 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is 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:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.kie.eclipse.navigator.view;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.wst.server.core.IServer;
import org.kie.eclipse.navigator.KieNavigatorContentRoot;
import org.kie.eclipse.navigator.view.content.IContainerNode;
import org.kie.eclipse.navigator.view.content.IContentNode;
import org.kie.eclipse.navigator.view.content.ServerNode;
/**
* Content provider implementation for server management details.
*/
public class KieNavigatorContentProvider implements ITreeContentProvider {
/** Represents a pending request in the tree. */
static final Object PENDING = new Object();
private ConcurrentMap<IContainerNode<?>, Object> pendingUpdates = new ConcurrentHashMap<IContainerNode<?>, Object>();
private transient TreeViewer viewer;
/**
* Loads content for specified nodes, then refreshes the content in the
* tree.
*/
private Job loadElementJob = new Job("Refresh Server") {
@Override
public boolean shouldRun() {
return pendingUpdates.size() > 0;
}
@Override
protected IStatus run(final IProgressMonitor monitor) {
monitor.beginTask("Loading Server Content", IProgressMonitor.UNKNOWN);
try {
final List<IContainerNode<?>> updatedNodes = new ArrayList<IContainerNode<?>>(pendingUpdates.size());
for (IContainerNode<?> node : pendingUpdates.keySet()) {
try {
node.load();
updatedNodes.add(node);
} catch (Exception e) {
}
if (monitor.isCanceled()) {
pendingUpdates.keySet().removeAll(updatedNodes);
return Status.CANCEL_STATUS;
}
}
final TreeViewer viewer = KieNavigatorContentProvider.this.viewer;
if (viewer == null) {
pendingUpdates.keySet().clear();
} else {
viewer.getTree().getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
if (viewer.getTree().isDisposed()) {
return;
}
for (IContainerNode<?> node : updatedNodes) {
pendingUpdates.remove(node);
viewer.refresh(node);
}
}
});
}
} finally {
monitor.done();
}
return Status.OK_STATUS;
}
};
@Override
public void dispose() {
viewer = null;
loadElementJob.cancel();
pendingUpdates.clear();
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
if (viewer instanceof TreeViewer) {
this.viewer = (TreeViewer) viewer;
} else {
viewer = null;
}
}
@Override
public Object[] getElements(Object inputElement) {
return getChildren(inputElement);
}
List<ServerNode> rootElements;
@Override
public Object[] getChildren(Object parentElement) {
final List<Object> results = new ArrayList<Object>();
if (parentElement instanceof KieNavigatorContentRoot) {
List<? extends Object> children = ((KieNavigatorContentRoot) parentElement).getChildren();
results.addAll(children);
}
else if (parentElement instanceof IContainerNode) {
IContainerNode<?> container = (IContainerNode<?>) parentElement;
if (pendingUpdates.containsKey(container)) {
return new Object[] { PENDING };
}
List<? extends Object> children = container.getChildren();
if (children == null) {
pendingUpdates.putIfAbsent(container, PENDING);
loadElementJob.schedule();
return new Object[] { PENDING };
}
for (Object node : children) {
if (node instanceof IContentNode) {
// Resolve the content of this node: this may or
// may not be the node itself. This is currently
// used only by IProjectNode, which may return
// the workspace IProject itself. From the IProject
// level down, we will delegate to the Project View
// for node content and labels.
node = ((IContentNode) node).resolveContent();
}
results.add(node);
}
}
else if (parentElement instanceof IProject) {
// TODO: support GoInto actions for Projects
final IProject project = (IProject) parentElement;
if (project.isAccessible()) {
try {
project.accept(new IResourceVisitor() {
@Override
public boolean visit(IResource resource) throws CoreException {
if (resource!=project)
results.add(resource);
return !(resource instanceof IFolder) || resource==project;
}
});
}
catch (CoreException e) {
e.printStackTrace();
}
}
}
return results.toArray();
}
@Override
public Object getParent(Object element) {
if (element instanceof IContentNode) {
Object parent = ((IContentNode<?>) element).getParent();
if (parent == null) {
parent = ((IContentNode<?>) element).getServer();
}
return parent;
}
return null;
}
@Override
public boolean hasChildren(Object element) {
if (element instanceof IServer) {
return true;
} else if (element instanceof IContainerNode) {
return ((IContainerNode)element).hasChildren();
}
return false;
}
}