Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: e6fd71a06cd8bb31fad33e8955642ec0d7f64ddd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
/*******************************************************************************
 * Copyright (c) 2012, 2016 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.tcf.te.tcf.launch.core.delegates;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.tcf.internal.debug.model.TCFLaunch;
import org.eclipse.tcf.protocol.IChannel;
import org.eclipse.tcf.protocol.IPeer;
import org.eclipse.tcf.protocol.IToken;
import org.eclipse.tcf.protocol.Protocol;
import org.eclipse.tcf.services.IPathMap;
import org.eclipse.tcf.services.IPathMap.PathMapRule;
import org.eclipse.tcf.te.runtime.interfaces.callback.ICallback;
import org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer;
import org.eclipse.tcf.te.runtime.properties.PropertiesContainer;
import org.eclipse.tcf.te.runtime.services.ServiceManager;
import org.eclipse.tcf.te.runtime.utils.StatusHelper;
import org.eclipse.tcf.te.tcf.core.Tcf;
import org.eclipse.tcf.te.tcf.core.interfaces.IChannelManager;
import org.eclipse.tcf.te.tcf.core.interfaces.IPathMapGeneratorService;
import org.eclipse.tcf.te.tcf.launch.core.internal.services.PathMapService;
import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerNode;

/**
 * Default tcf launch implementation.
 * <p>
 * The launch can be adapted to {@link IPropertiesContainer} to exchange user defined data
 * between the launch steps.
 */
public final class Launch extends TCFLaunch {

	private ICallback callback = null;

	private boolean manualDisconnected = false;

	/**
	 * Non-notifying properties container used for data exchange between the steps.
	 */
	private final IPropertiesContainer properties = new PropertiesContainer() {
		@Override
		public Object getAdapter(Class adapter) {
			if (ILaunch.class.equals(adapter)) {
				return Launch.this;
			}
			return super.getAdapter(adapter);
		}
	};

	/**
	 * Constructor.
	 *
	 * @param configuration The launch configuration that was launched.
	 * @param mode The launch mode.
	 */
	public Launch(ILaunchConfiguration configuration, String mode) {
		super(configuration, mode);
	}

	public void setCallback(ICallback callback) {
		this.callback = callback;
	}

	public ICallback getCallback() {
		return callback;
	}

	/**
	 * Attach the tcf debugger to the given peer model node.
	 *
	 * @param node The peer model node. Must not be <code>null</code>.
	 */
	public void attachDebugger(IPeerNode node, final ICallback callback) {
		Assert.isNotNull(node);
		Assert.isNotNull(callback);

		manualDisconnected = false;

		// Remember the peer node
		properties.setProperty("node", node); //$NON-NLS-1$
		// Determine the peer name to pass on to the TCF launch
		final String name = node.getName();

		// The debugger is using it's own channel as the implementation
		// calls for channel.terminate(...) directly
		Map<String, Boolean> flags = new HashMap<String, Boolean>();
		flags.put(IChannelManager.FLAG_FORCE_NEW, Boolean.TRUE);
		Tcf.getChannelManager().openChannel(node.getPeer(), flags, new IChannelManager.DoneOpenChannel() {
			@Override
			public void doneOpenChannel(Throwable error, IChannel channel) {
				if (error == null && channel != null) {
					LaunchListener listener = new LaunchListener() {
						@Override
						public void onProcessStreamError(TCFLaunch launch, String process_id, int stream_id, Exception error, int lost_size) {
						}
						@Override
						public void onProcessOutput(TCFLaunch launch, String process_id, int stream_id, byte[] data) {
						}
						@Override
						public void onDisconnected(TCFLaunch launch) {
							callback.done(Launch.this, StatusHelper.getStatus(Launch.this.getError()));
							removeListener(this);
						}
						@Override
						public void onCreated(TCFLaunch launch) {
						}
						@Override
						public void onConnected(TCFLaunch launch) {
							callback.done(Launch.this, Status.OK_STATUS);
							removeListener(this);
						}
					};
					addListener(listener);
					launchTCF(getLaunchMode(), name, channel);
				}
				else {
					callback.done(Launch.this, StatusHelper.getStatus(error));
				}
			}
		});
	}

	public boolean isManualDisconnected() {
		return manualDisconnected;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.tcf.internal.debug.model.TCFLaunch#disconnect()
	 */
	@Override
	public void disconnect() throws DebugException {
		manualDisconnected = true;
	    super.disconnect();
	}

	/* (non-Javadoc)
	 * @see org.eclipse.tcf.internal.debug.model.TCFLaunch#getPeerName(org.eclipse.tcf.protocol.IPeer)
	 */
	@Override
	protected String getPeerName(IPeer peer) {
		Assert.isTrue(Protocol.isDispatchThread(), "Illegal Thread Access"); //$NON-NLS-1$
		Assert.isNotNull(peer);

		IPeerNode node = (IPeerNode)properties.getProperty("node"); //$NON-NLS-1$

	    return node != null ? node.getName() : super.getPeerName(peer);
	}

	private Collection<PathMapRule> readCustomPathMapConfiguration() {
		IPeerNode node = (IPeerNode)properties.getProperty("node"); //$NON-NLS-1$
		IPeer peer = node != null ? node.getPeer() : getChannel().getRemotePeer();
		ArrayList<PathMapRule> list = new ArrayList<PathMapRule>();

        IPathMapGeneratorService generator = ServiceManager.getInstance().getService(peer, IPathMapGeneratorService.class);
        if (generator != null) {
        	PathMapRule[] generatedRules = generator.getPathMap(peer);
        	if (generatedRules != null && generatedRules.length > 0) {
        		for (PathMapRule rule : generatedRules) list.add(rule);
        	}
        }
        return list;
	}

	@Override
	protected void applyPathMap(final Runnable done) {

		final List<PathMapRule> configuredMap = getHostPathMap();
		configuredMap.addAll(readCustomPathMapConfiguration());

        int cnt = 0;
        String id = getClientID();
        for (IPathMap.PathMapRule r : configuredMap) r.getProperties().put(IPathMap.PROP_ID, id + "/" + cnt++);

		// Get the client ID
		final String clientID = getClientID();
		// If we have a client ID, we can identify path map rules set by other clients
		// and leave them alone. Otherwise, just set the path map.
		if (clientID != null) {
	        final IPathMap svc = getService(IPathMap.class);
			if (svc != null) {
				// Get the old path maps first. Keep path map rules not coming from us
				svc.get(new IPathMap.DoneGet() {
					@Override
					public void doneGet(IToken token, Exception error, PathMapRule[] map) {
						// Merge the path maps
						List<PathMapRule> rules = PathMapService.mergePathMaps(clientID, map,
										configuredMap.toArray(new IPathMap.PathMapRule[configuredMap.size()]));

						// 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, false, new IPathMap.DoneSet() {
								@Override
								public void doneSet(IToken token, Exception error) {
					                if (error != null) getChannel().terminate(error);
					                else if (done != null) done.run();
								}
							});
						} else if (done != null) {
							done.run();
						}
					}
				});

			} else if (done != null) {
				done.run();
			}
		} else {
			super.applyPathMap(done);
		}
	}

    /* (non-Javadoc)
	 * @see org.eclipse.debug.core.Launch#getAdapter(java.lang.Class)
	 */
	@Override
	public Object getAdapter(Class adapter) {
		if (IPropertiesContainer.class.equals(adapter)) {
			return properties;
		}

		// Must force adapters to be loaded: (Defect WIND00243348, and Eclipse bug 197664).
		Platform.getAdapterManager().loadAdapter(this, adapter.getName());

		return super.getAdapter(adapter);
	}
}

Back to the top