From ec1c4b2813475dba9d9434b859b1e63706f5984d Mon Sep 17 00:00:00 2001 From: Uwe Stieber Date: Sun, 20 Jul 2014 13:28:30 +0200 Subject: Target Explorer: Fix path map not applied with stepper based channel manager --- .../te/tcf/core/interfaces/IChannelManager.java | 9 +++++ .../channelmanager/steps/ApplyPathMapsStep.java | 38 ++++++++-------------- .../tcf/te/tcf/launch/core/delegates/Launch.java | 2 +- .../core/internal/services/PathMapService.java | 24 +++++++++----- 4 files changed, 38 insertions(+), 35 deletions(-) diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/interfaces/IChannelManager.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/interfaces/IChannelManager.java index a8f564f6f..dc6850971 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/interfaces/IChannelManager.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/interfaces/IChannelManager.java @@ -109,6 +109,9 @@ public interface IChannelManager extends IAdaptable { * If the given channel is a reference counted channel, the channel will be closed if the reference counter * reaches 0. For non reference counted channels, the channel is closed immediately. *

+ * Note: Closing a channel is an asynchronous operation and the {@link #closeChannel(IChannel)} + * method can return while closing the channel is still in progress. + *

* The method can be called from any thread context. * * @param channel The channel. Must not be null. @@ -118,6 +121,12 @@ public interface IChannelManager extends IAdaptable { /** * Shutdown the communication to the given peer, no matter of the current * reference count. A possible associated value-add is shutdown as well. + *

+ * Note: Shutting down a channel is an asynchronous operation and the + * {@link #shutdown(IPeer)} method can return while shutting down the channel + * is still in progress. + *

+ * The method can be called from any thread context. * * @param peer The peer. Must not be null. */ diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/internal/channelmanager/steps/ApplyPathMapsStep.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/internal/channelmanager/steps/ApplyPathMapsStep.java index dd753775e..5d3f94a2c 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/internal/channelmanager/steps/ApplyPathMapsStep.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/internal/channelmanager/steps/ApplyPathMapsStep.java @@ -18,7 +18,6 @@ import org.eclipse.core.runtime.Status; import org.eclipse.tcf.protocol.IChannel; import org.eclipse.tcf.protocol.IPeer; import org.eclipse.tcf.protocol.Protocol; -import org.eclipse.tcf.services.IPathMap; import org.eclipse.tcf.te.runtime.interfaces.callback.ICallback; import org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer; import org.eclipse.tcf.te.runtime.services.ServiceManager; @@ -67,30 +66,19 @@ public class ApplyPathMapsStep extends AbstractPeerStep { final IPeer peer = getActivePeerContext(context, data, fullQualifiedId); Assert.isNotNull(peer); - Runnable runnable = new Runnable() { - @Override - public void run() { - final IPathMapService service = ServiceManager.getInstance().getService(peer, IPathMapService.class); - final IPathMap svc = channel.getRemoteService(IPathMap.class); - if (service != null && svc != null) { - // Apply the initial path map to the opened channel. - // This must happen outside the TCF dispatch thread as it may trigger - // the launch configuration change listeners. - Thread thread = new Thread(new Runnable() { - @Override - public void run() { - service.applyPathMap(peer, true, callback); - } - }); - thread.start(); - } else { - callback(data, fullQualifiedId, callback, Status.OK_STATUS, null); - } - } - }; - - if (Protocol.isDispatchThread()) runnable.run(); - else Protocol.invokeLater(runnable); + // Apply the initial path map to the opened channel. + // + // This must happen outside the TCF dispatch thread as it may trigger + // the launch configuration change listeners. + Assert.isTrue(!Protocol.isDispatchThread(), "Illegal Thread Access"); //$NON-NLS-1$ + final IPathMapService service = ServiceManager.getInstance().getService(peer, IPathMapService.class); + if (service != null) { + // Pass in the channel for direct use. IChannelManager.getChannel(peer) + // does return null while still executing the "open channel" step group. + service.applyPathMap(channel, true, callback); + } else { + callback(data, fullQualifiedId, callback, Status.OK_STATUS, null); + } } } diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.core/src/org/eclipse/tcf/te/tcf/launch/core/delegates/Launch.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.core/src/org/eclipse/tcf/te/tcf/launch/core/delegates/Launch.java index 8b46fe0ef..04d8be0ae 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.core/src/org/eclipse/tcf/te/tcf/launch/core/delegates/Launch.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.core/src/org/eclipse/tcf/te/tcf/launch/core/delegates/Launch.java @@ -167,7 +167,7 @@ public final class Launch extends TCFLaunch { // If the merged path map differs from the agent side path map, apply the map if (PathMapService.isDifferent(rules, map)) { // Apply the path map - PathMapService.set(rules, svc, done); + PathMapService.set(rules, svc, false, done); } else { done.doneSet(null, null); } diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.core/src/org/eclipse/tcf/te/tcf/launch/core/internal/services/PathMapService.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.core/src/org/eclipse/tcf/te/tcf/launch/core/internal/services/PathMapService.java index 4fe0a039e..6cf937d6c 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.core/src/org/eclipse/tcf/te/tcf/launch/core/internal/services/PathMapService.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.core/src/org/eclipse/tcf/te/tcf/launch/core/internal/services/PathMapService.java @@ -207,7 +207,7 @@ public class PathMapService extends AbstractService implements IPathMapService { updateLaunchConfiguration(config, rulesList); // Apply the path map - applyPathMap(context, false, new Callback() { + applyPathMap(context, true, new Callback() { @Override protected void internalDone(Object caller, IStatus status) { if (status != null && Platform.inDebugMode()) { @@ -317,27 +317,33 @@ public class PathMapService extends AbstractService implements IPathMapService { if (peer == null && context instanceof IPeerNode) peer = ((IPeerNode)context).getPeer(); if (peer == null && context instanceof IPeerNodeProvider && ((IPeerNodeProvider)context).getPeerNode() != null) peer = ((IPeerNodeProvider)context).getPeerNode().getPeer(); + // If called as part of the "open channel" step group, IChannelManager.getChannel(peer) + // will return null. For this case, the channel to use is passed as context directly. + IChannel channel = context instanceof IChannel ? (IChannel)context : null; + // The peer in that case is the remote peer of the channel + if (peer == null && channel != null) peer = channel.getRemotePeer(); + // Make sure that the callback is invoked in the TCF dispatch thread final AsyncCallbackCollector collector = new AsyncCallbackCollector(callback, new CallbackInvocationDelegate()); final ICallback innerCallback = new AsyncCallbackCollector.SimpleCollectorCallback(collector); collector.initDone(); if (peer != null) { - final IChannel channel = Tcf.getChannelManager().getChannel(peer); - if (channel != null && IChannel.STATE_OPEN == channel.getState()) { + final IChannel c = channel != null ? channel : Tcf.getChannelManager().getChannel(peer); + if (c != null && IChannel.STATE_OPEN == c.getState()) { // Channel is open -> Have to update the path maps // Get the configured path mappings. This must be called from // outside the runnable as getPathMap(...) must be called from // outside of the TCF dispatch thread. - final PathMapRule[] configuredMap = getPathMap(context); + final PathMapRule[] configuredMap = getPathMap(context instanceof IChannel ? peer : context); if (configuredMap != null && configuredMap.length > 0) { // Create the runnable which set the path map Runnable runnable = new Runnable() { @Override public void run() { - final IPathMap svc = channel.getRemoteService(IPathMap.class); + final IPathMap svc = c.getRemoteService(IPathMap.class); if (svc != null) { // Get the old path maps first. Keep path map rules not coming from us svc.get(new IPathMap.DoneGet() { @@ -349,7 +355,7 @@ public class PathMapService extends AbstractService implements IPathMapService { // If the merged path map differs from the agent side path map, apply the map if (force || isDifferent(rules, map)) { // Apply the path map - set(rules, svc, new IPathMap.DoneSet() { + set(rules, svc, force, new IPathMap.DoneSet() { @Override public void doneSet(IToken token, Exception error) { innerCallback.done(PathMapService.this, StatusHelper.getStatus(error)); @@ -473,7 +479,7 @@ public class PathMapService extends AbstractService implements IPathMapService { * @param svc The path map service. Must not be null. * @param done The callback to invoke. Must not be null. */ - public static void set(List map, IPathMap svc, IPathMap.DoneSet done) { + public static void set(List map, IPathMap svc, boolean force, IPathMap.DoneSet done) { Assert.isTrue(Protocol.isDispatchThread(), "Illegal Thread Access"); //$NON-NLS-1$ Assert.isNotNull(map); Assert.isNotNull(svc); @@ -487,8 +493,8 @@ public class PathMapService extends AbstractService implements IPathMapService { iter.remove(); } } - // Apply the path map rules if not empty - if (!map.isEmpty()) { + // Apply the path map rules if not empty or forced + if (!map.isEmpty() || force) { svc.set(map.toArray(new PathMapRule[map.size()]), done); } else { done.doneSet(null, null); -- cgit v1.2.3