Re-structure LTTng sub-project as per the Linux Tools guidelines
[deliverable/tracecompass.git] / org.eclipse.linuxtools.lttng.ui / src / org / eclipse / linuxtools / lttng / ui / tracecontrol / connectorservice / TraceConnectorService.java
CommitLineData
e8d771d5
BH
1/*******************************************************************************
2 * Copyright (c) 2011 Ericsson
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Polytechnique Montréal - Initial API and implementation (based on TCFConnectorService)
11 * Bernd Hufmann - Productification, enhancements and fixes
12 *
13 *******************************************************************************/
14package org.eclipse.linuxtools.lttng.ui.tracecontrol.connectorservice;
15
16import java.io.IOException;
17import java.util.ArrayList;
18import java.util.HashMap;
19import java.util.List;
20import java.util.Map;
21
22import org.eclipse.core.runtime.IProgressMonitor;
e8d771d5
BH
23import org.eclipse.linuxtools.lttng.ui.tracecontrol.TraceControlConstants;
24import org.eclipse.linuxtools.lttng.ui.tracecontrol.Messages;
6c13869b
FC
25import org.eclipse.linuxtools.lttng.core.LttngConstants;
26import org.eclipse.linuxtools.lttng.core.tracecontrol.service.ILttControllerService;
27import org.eclipse.linuxtools.lttng.core.tracecontrol.service.LttControllerServiceProxy;
e8d771d5
BH
28import org.eclipse.linuxtools.lttng.ui.tracecontrol.subsystems.TraceSubSystem;
29import org.eclipse.linuxtools.lttng.ui.tracecontrol.utility.DownloadProxy;
30import org.eclipse.rse.core.model.IHost;
31import org.eclipse.rse.core.subsystems.CommunicationsEvent;
32import org.eclipse.rse.core.subsystems.ISubSystem;
33import org.eclipse.rse.ui.SystemBasePlugin;
34import org.eclipse.rse.ui.subsystems.StandardConnectorService;
35import org.eclipse.tm.tcf.core.AbstractPeer;
36import org.eclipse.tm.tcf.protocol.IChannel;
37import org.eclipse.tm.tcf.protocol.IChannel.IEventListener;
38import org.eclipse.tm.tcf.protocol.IPeer;
39import org.eclipse.tm.tcf.protocol.IService;
40import org.eclipse.tm.tcf.protocol.Protocol;
41import org.eclipse.tm.tcf.services.ILocator;
42
43/**
44 * <b><u>TraceConnectorService</u></b>
45 * <p>
46 * Implementation of the Trace Connector class to connect to the remote agent.
47 * </p>
48 */
49public class TraceConnectorService extends StandardConnectorService {
50
51 // ------------------------------------------------------------------------
52 // Attributes
53 // ------------------------------------------------------------------------
54 private final static int INVOCATION_TIMEOUT = 1000;
55 private boolean fIsConnected = false;
56 private IChannel fChannel;
57 private Throwable fChannelError;
58
59 private final List<Runnable> fWaitList = new ArrayList<Runnable>();
60 private boolean fPollTimerStarted;
61 private DownloadProxy fDownloadProxy = null;
62
63 // ------------------------------------------------------------------------
64 // Constructors
65 // ------------------------------------------------------------------------
66 /**
67 * Constructor for TraceConnectorService.
68 *
69 * @param host - host reference
70 * @param port - port
71 */
72 public TraceConnectorService(IHost host, int port) {
73 super(Messages.Trace_Connector_Service_Name, Messages.Trace_Connector_Service_Description, host, port);
74 }
75
76 /*
77 * (non-Javadoc)
78 * @see org.eclipse.rse.core.subsystems.IConnectorService#isConnected()
79 */
80 @Override
81 public boolean isConnected() {
82 return fIsConnected;
83 }
84
85 /*
86 * (non-Javadoc)
87 * @see org.eclipse.rse.core.subsystems.AbstractConnectorService#internalConnect(org.eclipse.core.runtime.IProgressMonitor)
88 */
89 @Override
90 protected void internalConnect(final IProgressMonitor monitor) throws Exception {
91 assert !Protocol.isDispatchThread();
92 final Exception[] res = new Exception[1];
93 // Fire comm event to signal state about to change
94 fireCommunicationsEvent(CommunicationsEvent.BEFORE_CONNECT);
95 monitor.beginTask(Messages.Trace_Connector_Service_Connect_Msg + " " + getHostName(), 1); //$NON-NLS-1$
96 synchronized (res) {
97 Protocol.invokeLater(new Runnable() {
98 @Override
99 public void run() {
100 if (!connectTCFChannel(res, monitor)) {
101 add_to_wait_list(this);
102 }
103 }
104 });
105 res.wait();
106 }
107 monitor.done();
108 if (res[0] != null) {
109 throw res[0];
110 }
111 // pretend. Normally, we'd connect to our remote server-side code here
112 fIsConnected = true;
113 }
114
115 /*
116 * (non-Javadoc)
117 * @see org.eclipse.rse.core.subsystems.AbstractConnectorService#internalDisconnect(org.eclipse.core.runtime.IProgressMonitor)
118 */
119 @Override
120 public void internalDisconnect(final IProgressMonitor monitor) throws Exception {
121 assert !Protocol.isDispatchThread();
122 final Exception[] res = new Exception[1];
123 // Fire comm event to signal state about to change
124 fireCommunicationsEvent(CommunicationsEvent.BEFORE_DISCONNECT);
125 monitor.beginTask(Messages.Trace_Connector_Service_Disconnect_Msg + " " + getHostName(), 1); //$NON-NLS-1$
126 synchronized (res) {
127 Protocol.invokeLater(new Runnable() {
128 @Override
129 public void run() {
130 if (!disconnectTCFChannel(res, monitor)) {
131 add_to_wait_list(this);
132 }
133 }
134 });
135 res.wait();
136 }
137 monitor.done();
138 if (res[0] != null) {
139 throw res[0];
140 }
141 fIsConnected = false;
142 }
143
144 /*
145 * (non-Javadoc)
146 * @see org.eclipse.rse.core.subsystems.AbstractConnectorService#supportsRemoteServerLaunching()
147 */
148 @Override
149 public boolean supportsRemoteServerLaunching() {
150 return false;
151 }
152
153 /*
154 * (non-Javadoc)
155 * @see org.eclipse.rse.core.subsystems.AbstractConnectorService#supportsServerLaunchProperties()
156 */
157 @Override
158 public boolean supportsServerLaunchProperties() {
159 return false;
160 }
161
162 /*
163 * Add Runnable to wait list.
164 */
165 private void add_to_wait_list(Runnable cb) {
166 fWaitList.add(cb);
167 if (fPollTimerStarted) {
168 return;
169 }
170 Protocol.invokeLater(INVOCATION_TIMEOUT, new Runnable() {
171 @Override
172 public void run() {
173 fPollTimerStarted = false;
174 run_wait_list();
175 }
176 });
177 fPollTimerStarted = true;
178 }
179
180 /*
181 * Run the runnables of the wait list.
182 */
183 private void run_wait_list() {
184 if (fWaitList.isEmpty()) {
185 return;
186 }
187 Runnable[] runnables = fWaitList.toArray(new Runnable[fWaitList.size()]);
188 fWaitList.clear();
189 for (int i = 0; i < runnables.length; i++) {
190 runnables[i].run();
191 }
192 }
193
194 /*
195 * Connect the TCF channel.
196 */
197 private boolean connectTCFChannel(Exception[] res, IProgressMonitor monitor) {
198 if (fChannel != null) {
199 switch (fChannel.getState()) {
200 case IChannel.STATE_OPEN:
201 case IChannel.STATE_CLOSED:
202 synchronized (res) {
203 if (fChannelError instanceof Exception) {
204 res[0] = (Exception) fChannelError;
205 }
206 else if (fChannelError != null) {
207 res[0] = new Exception(fChannelError);
208 }
209 else {
210 res[0] = null;
211 }
212 res.notifyAll();
213 return true;
214 }
215 default:
216 }
217 }
218 if (monitor.isCanceled()) {
219 synchronized (res) {
220 res[0] = new Exception(Messages.Trace_Connector_Service_Canceled_Msg);
221 if (fChannel != null) {
222 fChannel.terminate(res[0]);
223 }
224 res.notifyAll();
225 return true;
226 }
227 }
228 if (fChannel == null) {
229 String host = getHostName().toLowerCase();
230 int port = getConnectPort();
231 if (port <= 0) {
232 // Default fallback
233 port = TraceConnectorServiceManager.TCF_PORT;
234 }
235 IPeer peer = null;
236 String port_str = Integer.toString(port);
237 ILocator locator = Protocol.getLocator();
238 for (IPeer p : locator.getPeers().values()) {
239 Map<String, String> attrs = p.getAttributes();
240 if ("TCP".equals(attrs.get(IPeer.ATTR_TRANSPORT_NAME)) && //$NON-NLS-1$
241 host.equalsIgnoreCase(attrs.get(IPeer.ATTR_IP_HOST)) && port_str.equals(attrs.get(IPeer.ATTR_IP_PORT))) {
242 peer = p;
243 break;
244 }
245 }
246 if (peer == null) {
247 Map<String, String> attrs = new HashMap<String, String>();
248 attrs.put(IPeer.ATTR_ID, "RSE:" + host + ":" + port_str); //$NON-NLS-1$ //$NON-NLS-2$
249 attrs.put(IPeer.ATTR_NAME, getName());
250 attrs.put(IPeer.ATTR_TRANSPORT_NAME, "TCP"); //$NON-NLS-1$
251 attrs.put(IPeer.ATTR_IP_HOST, host);
252 attrs.put(IPeer.ATTR_IP_PORT, port_str);
253 peer = new AbstractPeer(attrs);
254 }
255 fChannel = peer.openChannel();
256 fChannel.addChannelListener(new IChannel.IChannelListener() {
257 @Override
258 public void onChannelOpened() {
259 assert fChannel != null;
260
261 // Check if remote server provides LTTng service
262 if (fChannel.getRemoteService(ILttControllerService.NAME) == null) {
263 return;
264 }
265 // Create service proxy, passing the fChannel to the proxy
266 ILttControllerService controllerService = new LttControllerServiceProxy(fChannel);
267
268 fChannel.setServiceProxy(ILttControllerService.class, controllerService);
269
270 ISubSystem[] subSystems = getSubSystems();
271
272 for (int i = 0; i < subSystems.length; i++) {
273 if (subSystems[i] instanceof TraceSubSystem) {
274 // There is only one trace subsystem per trace connector service
275 fDownloadProxy = new DownloadProxy((TraceSubSystem)subSystems[i]);
276 }
277 }
278
279 final IEventListener listener = new IEventListener() {
280
281 @Override
282 public void event(String name, byte[] data) {
283 if (fDownloadProxy != null) {
284 if (name.compareTo(TraceControlConstants.Lttng_Control_New_Event_Data) == 0) {
285 fDownloadProxy.writeDownloadedTrace(data);
286 }
287 else if (name.compareTo(TraceControlConstants.Lttng_Control_Unwrite_Trace_Data_Event) == 0) {
288 // only for UST
289 // TODO implement handling
290 }
291 else if (name.compareTo(TraceControlConstants.Lttng_Control_Trace_Done_Event) == 0) {
292 // finished
293 fDownloadProxy.handleTraceDoneEvent(data);
294 } else {
295 try {
296 throw new IOException(LttngConstants.Lttng_Control_Command + ": " + Messages.Lttng_Control_Unknown_Event_Msg + ": " + name); //$NON-NLS-1$ //$NON-NLS-2$
297 } catch (IOException e) {
298 SystemBasePlugin.logError("TraceConnectorService", e); //$NON-NLS-1$
299 }
300 }
301 }
302 }
303 };
304 fChannel.addEventListener(controllerService, listener);
305 run_wait_list();
306 }
307
308 @Override
309 public void congestionLevel(int level) {
310 }
311
312 @Override
313 public void onChannelClosed(Throwable error) {
314 assert fChannel != null;
315 fChannel.removeChannelListener(this);
316 fChannelError = error;
317 if (fWaitList.isEmpty()) {
318 fireCommunicationsEvent(CommunicationsEvent.CONNECTION_ERROR);
319 } else {
320 run_wait_list();
321 }
322 fChannel = null;
323 fChannelError = null;
324 }
325
326 });
327
328 assert fChannel.getState() == IChannel.STATE_OPENING;
329 }
330 return false;
331 }
332
333 /*
334 * Disconnect the TCF channel.
335 */
336 private boolean disconnectTCFChannel(Exception[] res, IProgressMonitor monitor) {
337 if (fChannel == null || fChannel.getState() == IChannel.STATE_CLOSED) {
338 synchronized (res) {
339 res[0] = null;
340 res.notifyAll();
341 return true;
342 }
343 }
344 if (monitor.isCanceled()) {
345 synchronized (res) {
346 res[0] = new Exception("Canceled"); //$NON-NLS-1$
347 res.notifyAll();
348 return true;
349 }
350 }
351 if (fChannel.getState() == IChannel.STATE_OPEN) {
352 fChannel.close();
353 }
354 return false;
355 }
356
357 /**
358 * Retrieve the remote service for given service interface.
359 *
360 * @param <V>
361 * @param service_interface
362 * @return Service
363 * @throws Exception
364 */
365 public <V extends IService> V getService(Class<V> service_interface) throws Exception {
366 if (fChannel == null || fChannel.getState() != IChannel.STATE_OPEN) {
367 throw new Exception(Messages.Ltt_Controller_Service_Not_Connected_Msg + ": " + service_interface.getName()); //$NON-NLS-1$
368 }
369 V service = fChannel.getRemoteService(service_interface);
370 if (service == null) {
371 throw new Exception(Messages.Ltt_Controller_Service_Unsupported_Msg + ": " + service_interface.getName()); //$NON-NLS-1$
372 }
373 return service;
374 }
375
376 /**
377 * Retrieve the LTTng remote service.
378 *
379 * @return LTTng remote Service
380 * @throws Exception
381 */
382 public LttControllerServiceProxy getControllerService() throws Exception {
383 return (LttControllerServiceProxy)getService(ILttControllerService.class);
384 }
385}
This page took 0.04589 seconds and 5 git commands to generate.