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