/******************************************************************************* * 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.IStatus; 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.callback.Callback; import org.eclipse.tcf.te.runtime.concurrent.util.ExecutorsUtil; 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.core.interfaces.IPathMapService; 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); } /* (non-Javadoc) * @see org.eclipse.tcf.internal.debug.model.TCFLaunch#launchConfigurationChanged(org.eclipse.debug.core.ILaunchConfiguration) */ @Override public void launchConfigurationChanged(ILaunchConfiguration cfg) { super.launchConfigurationChanged(cfg); // Apply Path Map changes Protocol.invokeLater(new Runnable() { @Override public void run() { if (getChannel() != null) { final IPeer peer = getPeer(); if (peer != null) { final IPathMapService service = ServiceManager.getInstance().getService(peer, IPathMapService.class); if (service != null) { ExecutorsUtil.execute(new Runnable() { @Override public void run() { service.applyPathMap(peer, false, true, new Callback() { @Override protected void internalDone(Object caller, IStatus status) { } }); } }); } } } } }); } }