1 /*******************************************************************************
2 * Copyright (c) 2011 Ericsson
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
10 * Polytechnique Montréal - Initial API and implementation (based on TCFConnectorService)
11 * Bernd Hufmann - Productification, enhancements and fixes
13 *******************************************************************************/
14 package org
.eclipse
.linuxtools
.lttng
.ui
.tracecontrol
.connectorservice
;
16 import java
.io
.IOException
;
17 import java
.util
.ArrayList
;
18 import java
.util
.HashMap
;
19 import java
.util
.List
;
22 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
23 import org
.eclipse
.linuxtools
.lttng
.ui
.tracecontrol
.TraceControlConstants
;
24 import org
.eclipse
.linuxtools
.lttng
.ui
.tracecontrol
.Messages
;
25 import org
.eclipse
.linuxtools
.lttng
.core
.LttngConstants
;
26 import org
.eclipse
.linuxtools
.lttng
.core
.tracecontrol
.service
.ILttControllerService
;
27 import org
.eclipse
.linuxtools
.lttng
.core
.tracecontrol
.service
.LttControllerServiceProxy
;
28 import org
.eclipse
.linuxtools
.lttng
.ui
.tracecontrol
.subsystems
.TraceSubSystem
;
29 import org
.eclipse
.linuxtools
.lttng
.ui
.tracecontrol
.utility
.DownloadProxy
;
30 import org
.eclipse
.rse
.core
.model
.IHost
;
31 import org
.eclipse
.rse
.core
.subsystems
.CommunicationsEvent
;
32 import org
.eclipse
.rse
.core
.subsystems
.ISubSystem
;
33 import org
.eclipse
.rse
.ui
.SystemBasePlugin
;
34 import org
.eclipse
.rse
.ui
.subsystems
.StandardConnectorService
;
35 import org
.eclipse
.tm
.tcf
.core
.AbstractPeer
;
36 import org
.eclipse
.tm
.tcf
.protocol
.IChannel
;
37 import org
.eclipse
.tm
.tcf
.protocol
.IChannel
.IEventListener
;
38 import org
.eclipse
.tm
.tcf
.protocol
.IPeer
;
39 import org
.eclipse
.tm
.tcf
.protocol
.IService
;
40 import org
.eclipse
.tm
.tcf
.protocol
.Protocol
;
41 import org
.eclipse
.tm
.tcf
.services
.ILocator
;
44 * <b><u>TraceConnectorService</u></b>
46 * Implementation of the Trace Connector class to connect to the remote agent.
49 public class TraceConnectorService
extends StandardConnectorService
{
51 // ------------------------------------------------------------------------
53 // ------------------------------------------------------------------------
54 private final static int INVOCATION_TIMEOUT
= 1000;
55 private boolean fIsConnected
= false;
56 private IChannel fChannel
;
57 private Throwable fChannelError
;
59 private final List
<Runnable
> fWaitList
= new ArrayList
<Runnable
>();
60 private boolean fPollTimerStarted
;
61 private DownloadProxy fDownloadProxy
= null;
63 // ------------------------------------------------------------------------
65 // ------------------------------------------------------------------------
67 * Constructor for TraceConnectorService.
69 * @param host - host reference
72 public TraceConnectorService(IHost host
, int port
) {
73 super(Messages
.Trace_Connector_Service_Name
, Messages
.Trace_Connector_Service_Description
, host
, port
);
78 * @see org.eclipse.rse.core.subsystems.IConnectorService#isConnected()
81 public boolean isConnected() {
87 * @see org.eclipse.rse.core.subsystems.AbstractConnectorService#internalConnect(org.eclipse.core.runtime.IProgressMonitor)
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$
97 Protocol
.invokeLater(new Runnable() {
100 if (!connectTCFChannel(res
, monitor
)) {
101 add_to_wait_list(this);
108 if (res
[0] != null) {
111 // pretend. Normally, we'd connect to our remote server-side code here
117 * @see org.eclipse.rse.core.subsystems.AbstractConnectorService#internalDisconnect(org.eclipse.core.runtime.IProgressMonitor)
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$
127 Protocol
.invokeLater(new Runnable() {
130 if (!disconnectTCFChannel(res
, monitor
)) {
131 add_to_wait_list(this);
138 if (res
[0] != null) {
141 fIsConnected
= false;
146 * @see org.eclipse.rse.core.subsystems.AbstractConnectorService#supportsRemoteServerLaunching()
149 public boolean supportsRemoteServerLaunching() {
155 * @see org.eclipse.rse.core.subsystems.AbstractConnectorService#supportsServerLaunchProperties()
158 public boolean supportsServerLaunchProperties() {
163 * Add Runnable to wait list.
165 private void add_to_wait_list(Runnable cb
) {
167 if (fPollTimerStarted
) {
170 Protocol
.invokeLater(INVOCATION_TIMEOUT
, new Runnable() {
173 fPollTimerStarted
= false;
177 fPollTimerStarted
= true;
181 * Run the runnables of the wait list.
183 private void run_wait_list() {
184 if (fWaitList
.isEmpty()) {
187 Runnable
[] runnables
= fWaitList
.toArray(new Runnable
[fWaitList
.size()]);
189 for (int i
= 0; i
< runnables
.length
; i
++) {
195 * Connect the TCF channel.
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
:
203 if (fChannelError
instanceof Exception
) {
204 res
[0] = (Exception
) fChannelError
;
206 else if (fChannelError
!= null) {
207 res
[0] = new Exception(fChannelError
);
218 if (monitor
.isCanceled()) {
220 res
[0] = new Exception(Messages
.Trace_Connector_Service_Canceled_Msg
);
221 if (fChannel
!= null) {
222 fChannel
.terminate(res
[0]);
228 if (fChannel
== null) {
229 String host
= getHostName().toLowerCase();
230 int port
= getConnectPort();
233 port
= TraceConnectorServiceManager
.TCF_PORT
;
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
))) {
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
);
255 fChannel
= peer
.openChannel();
256 fChannel
.addChannelListener(new IChannel
.IChannelListener() {
258 public void onChannelOpened() {
259 assert fChannel
!= null;
261 // Check if remote server provides LTTng service
262 if (fChannel
.getRemoteService(ILttControllerService
.NAME
) == null) {
265 // Create service proxy, passing the fChannel to the proxy
266 ILttControllerService controllerService
= new LttControllerServiceProxy(fChannel
);
268 fChannel
.setServiceProxy(ILttControllerService
.class, controllerService
);
270 ISubSystem
[] subSystems
= getSubSystems();
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
]);
279 final IEventListener listener
= new IEventListener() {
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
);
287 else if (name
.compareTo(TraceControlConstants
.Lttng_Control_Unwrite_Trace_Data_Event
) == 0) {
289 // TODO implement handling
291 else if (name
.compareTo(TraceControlConstants
.Lttng_Control_Trace_Done_Event
) == 0) {
293 fDownloadProxy
.handleTraceDoneEvent(data
);
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$
304 fChannel
.addEventListener(controllerService
, listener
);
309 public void congestionLevel(int level
) {
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
);
323 fChannelError
= null;
328 assert fChannel
.getState() == IChannel
.STATE_OPENING
;
334 * Disconnect the TCF channel.
336 private boolean disconnectTCFChannel(Exception
[] res
, IProgressMonitor monitor
) {
337 if (fChannel
== null || fChannel
.getState() == IChannel
.STATE_CLOSED
) {
344 if (monitor
.isCanceled()) {
346 res
[0] = new Exception("Canceled"); //$NON-NLS-1$
351 if (fChannel
.getState() == IChannel
.STATE_OPEN
) {
358 * Retrieve the remote service for given service interface.
361 * @param service_interface
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$
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$
377 * Retrieve the LTTng remote service.
379 * @return LTTng remote Service
382 public LttControllerServiceProxy
getControllerService() throws Exception
{
383 return (LttControllerServiceProxy
)getService(ILttControllerService
.class);