Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'target_explorer/plugins/org.eclipse.tcf.te.tcf.filesystem.core/src/org/eclipse/tcf/te/tcf/filesystem/core/internal/operations/OpRefresh.java')
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.tcf.filesystem.core/src/org/eclipse/tcf/te/tcf/filesystem/core/internal/operations/OpRefresh.java379
1 files changed, 239 insertions, 140 deletions
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.filesystem.core/src/org/eclipse/tcf/te/tcf/filesystem/core/internal/operations/OpRefresh.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.filesystem.core/src/org/eclipse/tcf/te/tcf/filesystem/core/internal/operations/OpRefresh.java
index 8df9e38eb..e70332f5f 100644
--- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.filesystem.core/src/org/eclipse/tcf/te/tcf/filesystem/core/internal/operations/OpRefresh.java
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.filesystem.core/src/org/eclipse/tcf/te/tcf/filesystem/core/internal/operations/OpRefresh.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2011, 2012 Wind River Systems, Inc. and others. All rights reserved.
+ * Copyright (c) 2011, 2015 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
@@ -9,185 +9,284 @@
*******************************************************************************/
package org.eclipse.tcf.te.tcf.filesystem.core.internal.operations;
-import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
+import static java.text.MessageFormat.format;
+
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeoutException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
import org.eclipse.osgi.util.NLS;
-import org.eclipse.tcf.protocol.IChannel;
+import org.eclipse.tcf.protocol.IToken;
+import org.eclipse.tcf.protocol.Protocol;
import org.eclipse.tcf.services.IFileSystem;
-import org.eclipse.tcf.te.tcf.core.Tcf;
-import org.eclipse.tcf.te.tcf.filesystem.core.internal.exceptions.TCFException;
-import org.eclipse.tcf.te.tcf.filesystem.core.internal.exceptions.TCFFileSystemException;
-import org.eclipse.tcf.te.tcf.filesystem.core.model.FSTreeNode;
+import org.eclipse.tcf.services.IFileSystem.DirEntry;
+import org.eclipse.tcf.services.IFileSystem.DoneRoots;
+import org.eclipse.tcf.services.IFileSystem.DoneStat;
+import org.eclipse.tcf.services.IFileSystem.FileAttrs;
+import org.eclipse.tcf.services.IFileSystem.FileSystemException;
+import org.eclipse.tcf.te.runtime.callback.Callback;
+import org.eclipse.tcf.te.tcf.core.concurrent.Rendezvous;
+import org.eclipse.tcf.te.tcf.filesystem.core.interfaces.runtime.IFSTreeNode;
+import org.eclipse.tcf.te.tcf.filesystem.core.internal.FSTreeNode;
+import org.eclipse.tcf.te.tcf.filesystem.core.internal.utils.FileState;
+import org.eclipse.tcf.te.tcf.filesystem.core.internal.utils.PersistenceManager;
import org.eclipse.tcf.te.tcf.filesystem.core.nls.Messages;
/**
* FSRefresh refreshes a specified tree node and its children and grand children recursively.
*/
-public class OpRefresh extends Operation {
- //The root node to be refreshed.
- FSTreeNode node;
-
- /**
- * Create an FSRefresh to refresh the specified node and its descendants.
- *
- * @param node The root node to be refreshed.
- */
- public OpRefresh(FSTreeNode node) {
- this.node = node;
+public class OpRefresh extends AbstractOperation {
+ static final FSTreeNode[] NO_CHILDREN = {};
+ private static Map<FSTreeNode, TCFResult<?>> fPendingResults = new HashMap<FSTreeNode, TCFResult<?>>();
+
+ final LinkedList<FSTreeNode> fWork = new LinkedList<FSTreeNode>();
+ final boolean fRecursive;
+ private long fStartTime;
+
+ public OpRefresh(FSTreeNode node, boolean recursive) {
+ fWork.add(node);
+ fRecursive = recursive;
}
- /**
- * Create an FSRefresh to refresh the specified nodes and its descendants.
- *
- * @param nodes The node list to be refreshed.
- */
- public OpRefresh(List<FSTreeNode> nodes) {
- this.node = getAncestor(nodes);
+ public OpRefresh(List<IFSTreeNode> nodes, boolean recursive) {
+ fRecursive = recursive;
+ for (IFSTreeNode node : nodes) {
+ if (node instanceof FSTreeNode) {
+ fWork.add((FSTreeNode) node);
+ }
+ }
}
- /*
- * (non-Javadoc)
- * @see org.eclipse.tcf.te.tcf.filesystem.core.internal.operations.Operation#run(org.eclipse.core.runtime.IProgressMonitor)
- */
@Override
- public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
- super.run(monitor);
- if (node != null && (node.childrenQueried || node.isFile())) {
- IChannel channel = null;
- try {
- channel = openChannel(node.peerNode.getPeer());
- if (channel != null) {
- IFileSystem service = getBlockingFileSystem(channel);
- if (service != null) {
- refresh(node, service);
- }
- else {
- String message = NLS.bind(Messages.Operation_NoFileSystemError, node.peerNode.getPeerId());
- throw new TCFFileSystemException(IStatus.ERROR, message);
- }
+ public IStatus doRun(IProgressMonitor monitor) {
+ FSTreeNode needsNotification = null;
+ FSTreeNode trigger = fWork.peek();
+ fStartTime = System.currentTimeMillis();
+ monitor.beginTask(getName(), IProgressMonitor.UNKNOWN);
+ while (!fWork.isEmpty()) {
+ FSTreeNode node = fWork.remove();
+ boolean isTop = trigger == node;
+ if (isTop) {
+ if (needsNotification != null) {
+ needsNotification.notifyChange();
}
+ needsNotification = node;
+ trigger = fWork.peek();
}
- catch (TCFException e) {
- throw new InvocationTargetException(e, e.getMessage());
- }
- finally {
- if (channel != null) Tcf.getChannelManager().closeChannel(channel);
- monitor.done();
+ IStatus s = refreshNode(node, isTop, monitor);
+ if (!s.isOK()) {
+ if (needsNotification != null)
+ needsNotification.notifyChange();
+ return s;
}
}
- else {
- monitor.done();
- }
+ if (needsNotification != null)
+ needsNotification.notifyChange();
+ return Status.OK_STATUS;
}
- /**
- * Refresh the specified node and its children recursively using the file system service.
- *
- * @param node The node to be refreshed.
- * @param service The file system service.
- * @throws TCFFileSystemException Thrown during refreshing.
- */
- void refresh(final FSTreeNode node, final IFileSystem service) throws InterruptedException {
- if(monitor.isCanceled()) throw new InterruptedException();
- if ((node.isSystemRoot() || node.isDirectory()) && node.childrenQueried) {
- if (!node.isSystemRoot()) {
- try {
- updateChildren(node, service);
+ private IStatus refreshNode(final FSTreeNode node, final boolean isTop, IProgressMonitor monitor) {
+ if (node.getLastRefresh() >= fStartTime) {
+ FSTreeNode[] children = node.getChildren();
+ if (children != null) {
+ for (FSTreeNode child : children) {
+ fWork.addFirst(child);
}
- catch (TCFException e) {
- }
- }
- monitor.worked(1);
- List<FSTreeNode> children = node.getChildren();
- for (FSTreeNode child : children) {
- refresh(child, service);
}
+ return Status.OK_STATUS;
}
- else if(node.isFile()) {
- node.refresh();
+
+ boolean isDir = node.isDirectory();
+ boolean isFile = node.isFile();
+
+ if (!node.isFileSystem() && !isDir && !isFile)
+ return Status.OK_STATUS;
+
+ final Rendezvous rendezvous;
+ if (!isTop) {
+ rendezvous = null;
+ if (isFile || node.getChildren() == null)
+ return Status.OK_STATUS;
+ } else {
+ if (isFile) {
+ FileState digest = PersistenceManager.getInstance().getFileDigest(node);
+ rendezvous = new Rendezvous();
+ digest.updateState(new Callback(){
+ @Override
+ protected void internalDone(Object caller, IStatus status) {
+ rendezvous.arrive();
+ }
+ });
+ } else {
+ rendezvous = null;
+ }
}
- }
+ monitor.subTask(format(Messages.OpRefresh_name, node.getLocation()));
+ IStatus status;
+ synchronized (fPendingResults) {
+ TCFResult<?> result = fPendingResults.get(node);
+ if (result == null) {
+ result = new TCFResult<Object>(false);
+ fPendingResults.put(node, result);
+ scheduleTcfRefresh(node, isTop, result);
+ }
+ status = result.waitDone(monitor);
+ if (!result.hasWaiters()) {
+ result.setCancelled();
+ fPendingResults.remove(node);
+ }
+ }
- /**
- * Update the children of the specified folder node using the file system service.
- *
- * @param node The folder node.
- * @param service The file system service.
- * @throws TCFFileSystemException Thrown during querying the children nodes.
- */
- protected void updateChildren(final FSTreeNode node, final IFileSystem service) throws TCFFileSystemException, InterruptedException {
- if(monitor.isCanceled()) throw new InterruptedException();
- List<FSTreeNode> current = node.getChildren();
- List<FSTreeNode> latest = queryChildren(node, service);
- List<FSTreeNode> newNodes = diff(latest, current);
- List<FSTreeNode> deleted = diff(current, latest);
- node.removeChildren(deleted);
- node.addChidren(newNodes);
+ if (rendezvous != null) {
+ try {
+ rendezvous.waiting(10000);
+ } catch (TimeoutException e) {
+ }
+ }
+ return status;
}
- /**
- * Find those nodes which are in aList yet not in bList and return them as a list.
- *
- * @param aList
- * @param bList
- * @return the difference list.
- */
- private List<FSTreeNode> diff(List<FSTreeNode> aList, List<FSTreeNode> bList) {
- List<FSTreeNode> newList = new ArrayList<FSTreeNode>();
- for (FSTreeNode aNode : aList) {
- boolean found = false;
- for (FSTreeNode bNode : bList) {
- if (aNode.name.equals(bNode.name)) {
- found = true;
- break;
+ private void scheduleTcfRefresh(final FSTreeNode node, final boolean isTop, final TCFResult<?> result) {
+ Protocol.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ if (node.isFileSystem()) {
+ tcfRefreshRoots(node, result);
+ } else if (isTop && !node.isRootDirectory()) {
+ tcfStatAndRefresh(node, result);
+ } else {
+ tcfRefreshDir(node, result);
}
}
- if (!found) {
- newList.add(aNode);
+ });
+ }
+
+ protected void tcfStatAndRefresh(final FSTreeNode node, final TCFResult<?> result) {
+ if (!result.checkCancelled()) {
+ final IFileSystem fs = node.getRuntimeModel().getFileSystem();
+ if (fs == null) {
+ result.setCancelled();
+ return;
}
+
+ fs.stat(node.getLocation(true), new DoneStat() {
+ @Override
+ public void doneStat(IToken token, FileSystemException error, FileAttrs attrs) {
+ if (error != null) {
+ handleFSError(node, Messages.OpRefresh_errorReadAttributes, error, result);
+ } else {
+ node.setAttributes(attrs, false);
+ if (!attrs.isDirectory()) {
+ node.operationDownload(new OutputStream() {
+ @Override
+ public void write(int b) {}
+ }).runInJob(new Callback() {
+ @Override
+ protected void internalDone(Object caller, IStatus status) {
+ result.setDone(null);
+ }
+ });
+ result.setDone(null);
+ } else if (!result.checkCancelled()){
+ tcfRefreshDir(node, result);
+ }
+ }
+ }
+ });
}
- return newList;
}
- /*
- * (non-Javadoc)
- * @see org.eclipse.tcf.te.tcf.filesystem.core.interfaces.IOperation#getName()
- */
- @Override
- public String getName() {
- return NLS.bind(Messages.OpRefresh_RefreshJobTitle, node == null ? "" : node.name); //$NON-NLS-1$
- }
+ protected void tcfRefreshRoots(final FSTreeNode node, final TCFResult<?> result) {
+ if (!result.checkCancelled()) {
+ final IFileSystem fs = node.getRuntimeModel().getFileSystem();
+ if (fs == null) {
+ result.setCancelled();
+ return;
+ }
- /*
- * (non-Javadoc)
- * @see org.eclipse.tcf.te.tcf.filesystem.core.internal.operations.Operation#getTotalWork()
- */
- @Override
- public int getTotalWork() {
- return count(node);
+ fs.roots(new DoneRoots() {
+ @Override
+ public void doneRoots(IToken token, FileSystemException error, DirEntry[] entries) {
+ if (error != null) {
+ result.setError(format(Messages.OpRefresh_errorGetRoots, node.getRuntimeModel().getName()), error);
+ } else if (!result.checkCancelled()) {
+ int i = 0;
+ FSTreeNode[] nodes = new FSTreeNode[entries.length];
+ for (DirEntry entry : entries) {
+ nodes[i++] = new FSTreeNode(node, entry.filename, true, entry.attrs);
+ }
+ node.setContent(nodes, false);
+ if (fRecursive) {
+ for (FSTreeNode node : nodes) {
+ fWork.addFirst(node);
+ }
+ }
+ result.setDone(null);
+ }
+ }
+ });
+ }
}
- /**
- * Count the nodes that should be refreshed under
- * the specified directory.
- *
- * @param node The specified directory.
- * @return the total count of the qualified nodes.
- */
- private int count(FSTreeNode node) {
- if ((node.isSystemRoot() || node.isDirectory()) && node.childrenQueried) {
- int total = 1;
- List<FSTreeNode> children = node.getChildren();
- for (FSTreeNode child : children) {
- total += count(child);
+ protected void tcfRefreshDir(final FSTreeNode node, final TCFResult<?> result) {
+ if (!result.checkCancelled()) {
+ final String path = node.getLocation(true);
+ final IFileSystem fs = node.getRuntimeModel().getFileSystem();
+ if (fs == null) {
+ result.setCancelled();
+ return;
}
- return total;
+
+ tcfReadDir(fs, path, new IReadDirDone() {
+ @Override
+ public void error(FileSystemException error) {
+ result.setError(format(Messages.OpRefresh_errorOpenDir, path), error);
+ }
+
+ @Override
+ public boolean checkCancelled() {
+ return result.checkCancelled();
+ }
+
+ @Override
+ public void done(List<DirEntry> entries) {
+ int i = 0;
+ FSTreeNode[] nodes = new FSTreeNode[entries.size()];
+ for (DirEntry entry : entries) {
+ nodes[i++] = new FSTreeNode(node, entry.filename, false, entry.attrs);
+ }
+ node.setContent(nodes, false);
+ if (fRecursive) {
+ for (FSTreeNode node : nodes) {
+ fWork.addFirst(node);
+ }
+ }
+ result.setDone(null);
+ }
+ });
+ }
+ }
+
+ protected void handleFSError(final FSTreeNode node, String msg, FileSystemException error, final TCFResult<?> result) {
+ int status = error.getStatus();
+ if (status == IFileSystem.STATUS_NO_SUCH_FILE) {
+ node.getParent().removeNode(node, true);
+ result.setDone(null);
+ } else {
+ node.setContent(NO_CHILDREN, false);
+ result.setDone(null);
}
- return 0;
}
+
+ @Override
+ public String getName() {
+ return NLS.bind(Messages.OpRefresh_name, ""); //$NON-NLS-1$
+ }
}

Back to the top