/******************************************************************************* * Copyright (c) 2011 Wind River Systems, Inc. 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: * Wind River Systems - initial API and implementation *******************************************************************************/ package org.eclipse.tm.te.tcf.processes.ui.controls; import org.eclipse.core.runtime.Assert; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.StructuredViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.tm.tcf.protocol.IChannel; import org.eclipse.tm.tcf.protocol.IPeer; import org.eclipse.tm.tcf.protocol.IToken; import org.eclipse.tm.tcf.protocol.Protocol; import org.eclipse.tm.tcf.services.ISysMonitor; import org.eclipse.tm.te.tcf.core.Tcf; import org.eclipse.tm.te.tcf.core.interfaces.IChannelManager; import org.eclipse.tm.te.tcf.locator.interfaces.nodes.IPeerModel; import org.eclipse.tm.te.tcf.locator.interfaces.nodes.IPeerModelProperties; import org.eclipse.tm.te.ui.nls.Messages; import org.eclipse.ui.PlatformUI; /** * Processes tree control content provider implementation. */ public class ProcessesTreeContentProvider implements ITreeContentProvider { /** * Static reference to the return value representing no elements. */ protected final static Object[] NO_ELEMENTS = new Object[0]; /* default */ IPeerModel peerNode = null; private ProcessesTreeNode rootNode = null; private IChannel channel = null; private ISysMonitor service = null; /* default */ Viewer viewer = null; /* (non-Javadoc) * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object) */ @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { this.viewer = viewer; if (oldInput != null && newInput == null) { closeOpenChannel(); } } /* (non-Javadoc) * @see org.eclipse.jface.viewers.IContentProvider#dispose() */ @Override public void dispose() { closeOpenChannel(); } /** * Close the open communication channel and set back the node references. */ protected void closeOpenChannel() { if (channel != null) { final IChannel finChannel = channel; if (Protocol.isDispatchThread()) { finChannel.close(); } else { Protocol.invokeAndWait(new Runnable() { @Override public void run() { finChannel.close(); } }); } channel = null; service = null; } peerNode = null; rootNode = null; } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ITreeContentProvider#getElements(java.lang.Object) */ @Override public Object[] getElements(Object inputElement) { return getChildren(inputElement); } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object) */ @Override public Object getParent(Object element) { if (element instanceof ProcessesTreeNode) { return ((ProcessesTreeNode)element).parent; } return null; } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object) */ @Override public Object[] getChildren(Object parentElement) { Assert.isNotNull(parentElement); Object[] children = NO_ELEMENTS; // For the file system, we need the peer node if (parentElement instanceof IPeerModel) { // Is it the same peer node we have seen before? if (peerNode == null || peerNode != null && !peerNode.equals(parentElement)) { // Remember the peer node peerNode = (IPeerModel)parentElement; // If we still have a channel open, for now, we just close the old channel if (channel != null) { final IChannel finChannel = channel; if (Protocol.isDispatchThread()) { finChannel.close(); } else { Protocol.invokeAndWait(new Runnable() { @Override public void run() { finChannel.close(); } }); } channel = null; } IPeer peer = peerNode.getPeer(); final int[] state = new int[1]; Protocol.invokeAndWait(new Runnable() { @Override public void run() { state[0] = peerNode.getIntProperty(IPeerModelProperties.PROP_STATE); } }); if (peer != null && IPeerModelProperties.STATE_ERROR != state[0] && IPeerModelProperties.STATE_NOT_REACHABLE != state[0]) { ProcessesTreeNode pendingNode = new ProcessesTreeNode(); pendingNode.name = Messages.PendingOperation_label; pendingNode.type ="ProcPendingNode"; //$NON-NLS-1$ children = new Object[] { pendingNode }; Tcf.getChannelManager().openChannel(peer, new IChannelManager.DoneOpenChannel() { @Override @SuppressWarnings("synthetic-access") public void doneOpenChannel(Throwable error, IChannel channel) { Assert.isTrue(Protocol.isDispatchThread()); if (channel != null) { ProcessesTreeContentProvider.this.channel = channel; service = channel.getRemoteService(ISysMonitor.class); if (service != null) { rootNode = new ProcessesTreeNode(); rootNode.type = "ProcRootNode"; //$NON-NLS-1$ rootNode.childrenQueried = false; rootNode.childrenQueryRunning = true; Protocol.invokeLater(new Runnable() { @Override public void run() { service.getChildren(null, new ISysMonitor.DoneGetChildren() { /* (non-Javadoc) * @see org.eclipse.tm.tcf.services.ISysMonitor.DoneGetChildren#doneGetChildren(org.eclipse.tm.tcf.protocol.IToken, java.lang.Exception, java.lang.String[]) */ @Override public void doneGetChildren(IToken token, Exception error, String[] context_ids) { if (rootNode != null) { if (error == null && context_ids != null && context_ids.length > 0) { for (String contextId : context_ids) { service.getContext(contextId, new ISysMonitor.DoneGetContext() { /* (non-Javadoc) * @see org.eclipse.tm.tcf.services.ISysMonitor.DoneGetContext#doneGetContext(org.eclipse.tm.tcf.protocol.IToken, java.lang.Exception, org.eclipse.tm.tcf.services.ISysMonitor.SysMonitorContext) */ @Override public void doneGetContext(IToken token, Exception error, ISysMonitor.SysMonitorContext context) { if (error == null && context != null) { ProcessesTreeNode node = createNodeFromSysMonitorContext(context); if (node != null) { node.parent = rootNode; rootNode.children.add(node); } } } }); } } Protocol.invokeLater(new Runnable() { @Override public void run() { // Reset the children query marker rootNode.childrenQueryRunning = false; rootNode.childrenQueried = true; PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { @Override public void run() { if (viewer != null) viewer.refresh(); } }); } }); } } }); } }); } else { // TCF file system service is not available, close the just opened channel closeOpenChannel(); } } } }); } else { dispose(); } } else if (rootNode != null && rootNode.childrenQueried) { children = rootNode.children.toArray(); } } else if (parentElement instanceof ProcessesTreeNode) { ProcessesTreeNode node = (ProcessesTreeNode)parentElement; // Get possible children children = node.children.toArray(); // No children -> check for "childrenQueried" property. If false, trigger the query. if (children.length == 0 && !node.childrenQueried) { ProcessesTreeNode pendingNode = new ProcessesTreeNode(); pendingNode.name = Messages.PendingOperation_label; pendingNode.type ="ProcPendingNode"; //$NON-NLS-1$ children = new Object[] { pendingNode }; doGetChildrenForProcessContext(node); } } return children; } /** * Query the children of the given process context. * * @param node The process context node. Must be not <code>null</code>. */ protected void doGetChildrenForProcessContext(ProcessesTreeNode node) { Assert.isNotNull(node); if (!node.childrenQueryRunning) { final ProcessesTreeNode parentNode = node; final String parentId = node.id; if (parentId != null && service != null) { parentNode.childrenQueryRunning = true; Protocol.invokeLater(new Runnable() { @Override @SuppressWarnings("synthetic-access") public void run() { service.getChildren(parentId, new ISysMonitor.DoneGetChildren() { /* (non-Javadoc) * @see org.eclipse.tm.tcf.services.IProcesses.DoneGetChildren#doneGetChildren(org.eclipse.tm.tcf.protocol.IToken, java.lang.Exception, java.lang.String[]) */ @Override public void doneGetChildren(IToken token, Exception error, String[] context_ids) { if (error == null && context_ids != null && context_ids.length > 0) { for (String contextId : context_ids) { service.getContext(contextId, new ISysMonitor.DoneGetContext() { /* (non-Javadoc) * @see org.eclipse.tm.tcf.services.ISysMonitor.DoneGetContext#doneGetContext(org.eclipse.tm.tcf.protocol.IToken, java.lang.Exception, org.eclipse.tm.tcf.services.ISysMonitor.SysMonitorContext) */ @Override public void doneGetContext(IToken token, Exception error, ISysMonitor.SysMonitorContext context) { if (error == null && context != null) { ProcessesTreeNode node = createNodeFromSysMonitorContext(context); if (node != null) { node.parent = parentNode; parentNode.children.add(node); } } } }); } } Protocol.invokeLater(new Runnable() { @Override public void run() { // Reset the children query marker parentNode.childrenQueryRunning = false; parentNode.childrenQueried = true; PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { @Override public void run() { if (viewer instanceof StructuredViewer) ((StructuredViewer)viewer).refresh(parentNode); } }); } }); } }); } }); } } } /** * Creates a node from the given system monitor context. * * @param context The system monitor context. Must be not <code>null</code>. * * @return The node. */ protected ProcessesTreeNode createNodeFromSysMonitorContext(ISysMonitor.SysMonitorContext context) { Assert.isTrue(Protocol.isDispatchThread()); Assert.isNotNull(context); ProcessesTreeNode node = new ProcessesTreeNode(); node.childrenQueried = false; node.childrenQueryRunning = false; node.context = context; node.name = context.getFile(); node.type = "ProcNode"; //$NON-NLS-1$ node.id = context.getID(); node.pid = context.getPID(); node.ppid = context.getPPID(); node.parentId = context.getParentID(); node.state = context.getState(); node.username = context.getUserName(); doGetChildrenForProcessContext(node); return node; } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object) */ @Override public boolean hasChildren(Object element) { Assert.isNotNull(element); boolean hasChildren = false; // No children yet and the element is a process node if (element instanceof ProcessesTreeNode) { ProcessesTreeNode node = (ProcessesTreeNode)element; if (!node.childrenQueried || node.childrenQueryRunning) { hasChildren = true; } else if (node.childrenQueried) { hasChildren = node.children.size() > 0; } } return hasChildren; } }