diff options
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.java | 379 |
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$ + } } |