From b5c49b1ecfd3b2aadcc701aa01d33ee601b56301 Mon Sep 17 00:00:00 2001 From: Uwe Stieber Date: Wed, 3 Oct 2012 18:40:08 +0200 Subject: Target Explorer: Fix several issue in handling remote peer associations to static configuration or peers --- .../runtime/services/interfaces/IMenuService.java | 4 +- .../te/tcf/core/interfaces/IChannelManager.java | 9 + .../tcf/te/tcf/core/internal/ChannelManager.java | 46 ++ .../te/tcf/core/va/AbstractExternalValueAdd.java | 5 +- .../tcf/te/tcf/locator/ScannerRunnable.java | 11 + .../te/tcf/locator/listener/LocatorListener.java | 68 ++- .../services/LocatorModelPeerNodeQueryService.java | 518 +++++++++++---------- .../services/LocatorModelRefreshService.java | 12 +- .../services/LocatorModelUpdateService.java | 30 +- .../org/eclipse/tcf/te/tests/tcf/TcfTestCase.java | 430 ++++++++--------- .../src/org/eclipse/tcf/te/ui/views/ViewsUtil.java | 39 ++ 11 files changed, 683 insertions(+), 489 deletions(-) (limited to 'target_explorer/plugins') diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.services/src/org/eclipse/tcf/te/runtime/services/interfaces/IMenuService.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.services/src/org/eclipse/tcf/te/runtime/services/interfaces/IMenuService.java index 7b8da18c1..6fd9479f4 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.runtime.services/src/org/eclipse/tcf/te/runtime/services/interfaces/IMenuService.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.services/src/org/eclipse/tcf/te/runtime/services/interfaces/IMenuService.java @@ -20,8 +20,8 @@ public interface IMenuService extends IService { * Tests if or if not the menu contribution identified by the given id is * visible for the given context. * - * @param context The context. Must be not null. - * @param contributionID The contribution ID. Must be not null. + * @param context The context. Must not be null. + * @param contributionID The contribution ID. Must not be null. * * @return True if the contribution is visible, false otherwise. */ 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 b5e2b90db..85c8a4bbb 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 @@ -112,10 +112,19 @@ public interface IChannelManager extends IAdaptable { */ public void closeChannel(IChannel channel); + /** + * Shutdown the communication to the given peer, no matter of the current + * reference count. A possible associated value-add is shutdown as well. + * + * @param peer The peer. Must not be null. + */ + public void shutdown(IPeer peer); + /** * Close all open channel, no matter of the current reference count. *

* The method can be called from any thread context. */ public void closeAll(); + } diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/internal/ChannelManager.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/internal/ChannelManager.java index 3274e1979..3d5e36d13 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/internal/ChannelManager.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/internal/ChannelManager.java @@ -417,6 +417,52 @@ public final class ChannelManager extends PlatformObject implements IChannelMana } } + /* (non-Javadoc) + * @see org.eclipse.tcf.te.tcf.core.interfaces.IChannelManager#shutdown(org.eclipse.tcf.protocol.IPeer) + */ + @Override + public void shutdown(final IPeer peer) { + Runnable runnable = new Runnable() { + @Override + public void run() { + Assert.isTrue(Protocol.isDispatchThread(), "Illegal Thread Access"); //$NON-NLS-1$ + internalShutdown(peer); + } + }; + if (Protocol.isDispatchThread()) runnable.run(); + else Protocol.invokeLater(runnable); + } + + /** + * Shutdown the communication to the given peer, no matter of the current + * reference count. A possible associated value-add is shutdown as well. + * + * @param peer The peer. Must not be null. + */ + /* default */ void internalShutdown(IPeer peer) { + Assert.isTrue(Protocol.isDispatchThread(), "Illegal Thread Access"); //$NON-NLS-1$ + Assert.isNotNull(peer); + + // Get the peer id + String id = peer.getID(); + + // Get the channel + IChannel channel = internalGetChannel(peer); + if (channel != null) { + // Reset the reference count (will force a channel close) + refCounters.remove(id); + + // Close the channel + internalCloseChannel(channel); + + // Get the value-add's for the peer to shutdown + IValueAdd[] valueAdds = ValueAddManager.getInstance().getValueAdd(peer); + if (valueAdds != null && valueAdds.length > 0) { + internalShutdownValueAdds(peer, valueAdds); + } + } + } + /* (non-Javadoc) * @see org.eclipse.tcf.te.tcf.core.interfaces.IChannelManager#closeAll() */ diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/va/AbstractExternalValueAdd.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/va/AbstractExternalValueAdd.java index c4b88ba98..e4860fe63 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/va/AbstractExternalValueAdd.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/va/AbstractExternalValueAdd.java @@ -232,7 +232,7 @@ public abstract class AbstractExternalValueAdd extends AbstractValueAdd { // Find the "Server-Properties: ..." string within the output int start = output.indexOf("Server-Properties:"); //$NON-NLS-1$ - if (start != -1) { + if (start != -1 && start > 0) { output = output.substring(start); } @@ -275,6 +275,9 @@ public abstract class AbstractExternalValueAdd extends AbstractValueAdd { entries.put(id, entry); } + + // Stop the output reader thread + launcher.getOutputReader().interrupt(); } else { error = new FileNotFoundException(NLS.bind(Messages.AbstractExternalValueAdd_error_invalidLocation, this.getId())); } diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/ScannerRunnable.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/ScannerRunnable.java index ffe413c25..a2f7f1853 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/ScannerRunnable.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/ScannerRunnable.java @@ -83,6 +83,11 @@ public class ScannerRunnable implements Runnable, IChannel.IChannelListener { public void run() { Assert.isTrue(Protocol.isDispatchThread(), "Illegal Thread Access"); //$NON-NLS-1$ + // If a scanner runnable already active for this peer node, there + // is no need to run another scan. + if (peerNode.getProperty("scanner.transient") != null) return; //$NON-NLS-1$ + peerNode.setProperty("scanner.transient", this); //$NON-NLS-1$ + // Determine the peer IPeer peer = peerNode.getPeer(); if (peer == null) return; @@ -306,6 +311,9 @@ public class ScannerRunnable implements Runnable, IChannel.IChannelListener { if (!sharedChannel && !keepOpen) channel.close(); } + // Reset the scanner runnable marker + peerNode.setProperty("scanner.transient", null); //$NON-NLS-1$ + // Re-enable the change events a fire a "properties" change event if (changed) { peerNode.setChangeEventsEnabled(true); @@ -350,6 +358,9 @@ public class ScannerRunnable implements Runnable, IChannel.IChannelListener { peerNode.setProperty("dns.lastIP.transient", null); //$NON-NLS-1$ peerNode.setProperty("dns.skip.transient", null); //$NON-NLS-1$ + // Reset the scanner runnable marker + peerNode.setProperty("scanner.transient", null); //$NON-NLS-1$ + // Re-enable the change events a fire a "properties" change event if (changed) { peerNode.setChangeEventsEnabled(true); diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/listener/LocatorListener.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/listener/LocatorListener.java index 1e53d377e..f2ac8a12a 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/listener/LocatorListener.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/listener/LocatorListener.java @@ -9,7 +9,9 @@ *******************************************************************************/ package org.eclipse.tcf.te.tcf.locator.listener; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; @@ -126,6 +128,13 @@ public class LocatorListener implements ILocator.LocatorListener { if (model != null && peer != null) { // find the corresponding model node to remove IPeerModel peerNode = model.getService(ILocatorModelLookupService.class).lkupPeerModelById(peer.getID()); + if (peerNode == null) { + // Double check with "ClientID" if set + String clientID = peer.getAttributes().get("ClientID"); //$NON-NLS-1$ + if (clientID != null) { + peerNode = model.getService(ILocatorModelLookupService.class).lkupPeerModelById(clientID); + } + } // Update the peer instance if (peerNode != null) { // Get the old peer instance @@ -138,7 +147,15 @@ public class LocatorListener implements ILocator.LocatorListener { } // Non-visible peers are updated else { - model.getService(ILocatorModelUpdateService.class).mergeUserDefinedAttributes(peerNode, peer, false); + // Validate the peer node before updating + IPeer myPeer = model.validatePeer(peer); + if (myPeer != null) { + boolean changed = peerNode.setChangeEventsEnabled(false); + // Merge user configured properties between the peers + model.getService(ILocatorModelUpdateService.class).mergeUserDefinedAttributes(peerNode, myPeer, true); + if (changed) peerNode.setChangeEventsEnabled(true); + peerNode.fireChangeEvent(IPeerModelProperties.PROP_INSTANCE, myPeer, peerNode.getPeer()); + } } } } @@ -167,19 +184,50 @@ public class LocatorListener implements ILocator.LocatorListener { String value = peer.getAttributes().get("static.transient"); //$NON-NLS-1$ boolean isStatic = value != null && Boolean.parseBoolean(value.trim()); if (isStatic) { + boolean changed = peerNode.setChangeEventsEnabled(false); + // Create a modifiable copy of the peer attributes Map attrs = new HashMap(peerNode.getPeer().getAttributes()); - attrs.remove("remote.transient"); //$NON-NLS-1$ - attrs.remove("remote.id.transient"); //$NON-NLS-1$ - attrs.remove("ClientID"); //$NON-NLS-1$ - - // Update the peer attributes - if (peer instanceof PeerRedirector) { - ((PeerRedirector)peer).updateAttributes(attrs); - } else if (peer instanceof Peer) { - ((Peer)peer).updateAttributes(attrs); + // Remember the remote peer id before removing it + String remotePeerID = attrs.get("remote.id.transient"); //$NON-NLS-1$ + + // Remove all merged attributes from the peer instance + String merged = attrs.remove("remote.merged.transient"); //$NON-NLS-1$ + if (merged != null) { + merged = merged.replace('[', ' ').replace(']', ' ').trim(); + List keysToRemove = Arrays.asList(merged.split(",\\ ")); //$NON-NLS-1$ + String[] keys = attrs.keySet().toArray(new String[attrs.keySet().size()]); + for (String key : keys) { + if (keysToRemove.contains(key)) { + attrs.remove(key); + } + } + + // Make sure the ID is set correctly + if (attrs.get(IPeer.ATTR_ID) == null) { + attrs.put(IPeer.ATTR_ID, peer.getID()); + } + + // Update the peer attributes + if (peer instanceof PeerRedirector) { + ((PeerRedirector)peer).updateAttributes(attrs); + } else if (peer instanceof Peer) { + ((Peer)peer).updateAttributes(attrs); + } + } + + // Remove the attributes stored at peer node level + peerNode.setProperty(IPeerModelProperties.PROP_LOCAL_SERVICES, null); + peerNode.setProperty(IPeerModelProperties.PROP_REMOTE_SERVICES, null); + + // Check if we have to remote the peer in the underlying locator service too + if (remotePeerID != null) { + Map peers = Protocol.getLocator().getPeers(); + IPeer remotePeer = peers.get(remotePeerID); + if (remotePeer instanceof AbstractPeer) ((AbstractPeer)remotePeer).dispose(); } + if (changed) peerNode.setChangeEventsEnabled(true); peerNode.fireChangeEvent(IPeerModelProperties.PROP_INSTANCE, peer, peerNode.getPeer()); } else { // Dynamic peer -> Remove peer model node from the model diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/services/LocatorModelPeerNodeQueryService.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/services/LocatorModelPeerNodeQueryService.java index 02b9c7348..0f0e573f2 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/services/LocatorModelPeerNodeQueryService.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/services/LocatorModelPeerNodeQueryService.java @@ -1,253 +1,265 @@ -/******************************************************************************* - * Copyright (c) 2012 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.locator.services; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; - -import org.eclipse.core.runtime.Assert; -import org.eclipse.tcf.protocol.IChannel; -import org.eclipse.tcf.protocol.Protocol; -import org.eclipse.tcf.te.runtime.interfaces.IConditionTester; -import org.eclipse.tcf.te.tcf.core.Tcf; -import org.eclipse.tcf.te.tcf.core.interfaces.IChannelManager; -import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.ILocatorModel; -import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerModel; -import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerModelProperties; -import org.eclipse.tcf.te.tcf.locator.interfaces.services.ILocatorModelPeerNodeQueryService; -import org.eclipse.tcf.te.tcf.locator.interfaces.services.ILocatorModelUpdateService; - -/** - * Default locator model peer node query service implementation. - */ -public class LocatorModelPeerNodeQueryService extends AbstractLocatorModelService implements ILocatorModelPeerNodeQueryService { - - /** - * Constructor. - * - * @param parentModel The parent locator model instance. Must not be null. - */ - public LocatorModelPeerNodeQueryService(ILocatorModel parentModel) { - super(parentModel); - } - - /* (non-Javadoc) - * @see org.eclipse.tcf.te.tcf.locator.interfaces.services.ILocatorModelPeerNodeQueryService#queryLocalServices(org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerModel) - */ - @Override - public String queryLocalServices(final IPeerModel node) { - Assert.isTrue(!Protocol.isDispatchThread(), "Illegal Thread Access"); //$NON-NLS-1$ - Assert.isNotNull(node); - - // Check if the services has been cached before - final AtomicReference services = new AtomicReference(); - Protocol.invokeAndWait(new Runnable() { - @Override - public void run() { - services.set(node.getStringProperty(IPeerModelProperties.PROP_LOCAL_SERVICES)); - } - }); - - if (services.get() != null && !"".equals(services.get())) { //$NON-NLS-1$ - // Services are cached -> return immediately - return services.get(); - } - - // Get the service asynchronously and block the caller thread until - // the callback returned - final AtomicBoolean completed = new AtomicBoolean(false); - Protocol.invokeLater(new Runnable() { - @Override - public void run() { - doQueryServices(node, new DoneQueryServices() { - @Override - public void doneQueryServices(Throwable error) { - if (error == null) services.set(node.getStringProperty(IPeerModelProperties.PROP_LOCAL_SERVICES)); - completed.set(true); - } - }); - } - }); - - final long startTime = System.currentTimeMillis(); - final IConditionTester tester = new IConditionTester() { - @Override - public boolean isConditionFulfilled() { - return completed.get(); - } - - @Override - public void cleanup() {} - }; - - while ((startTime + 1000) < System.currentTimeMillis() && !tester.isConditionFulfilled()) { - try { - Thread.sleep(100); - } catch (InterruptedException e) { /* ignored on purpose */ } - } - - return services.get(); - } - - /* (non-Javadoc) - * @see org.eclipse.tcf.te.tcf.locator.interfaces.services.ILocatorModelPeerNodeQueryService#queryRemoteServices(org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerModel) - */ - @Override - public String queryRemoteServices(final IPeerModel node) { - Assert.isTrue(!Protocol.isDispatchThread(), "Illegal Thread Access"); //$NON-NLS-1$ - Assert.isNotNull(node); - - // Check if the services has been cached before - final AtomicReference services = new AtomicReference(); - Protocol.invokeAndWait(new Runnable() { - @Override - public void run() { - services.set(node.getStringProperty(IPeerModelProperties.PROP_REMOTE_SERVICES)); - } - }); - - if (services.get() != null && !"".equals(services.get())) { //$NON-NLS-1$ - // Services are cached -> return immediately - return services.get(); - } - - // Get the service asynchronously and block the caller thread until - // the callback returned - final AtomicBoolean completed = new AtomicBoolean(false); - Protocol.invokeLater(new Runnable() { - @Override - public void run() { - doQueryServices(node, new DoneQueryServices() { - @Override - public void doneQueryServices(Throwable error) { - if (error == null) services.set(node.getStringProperty(IPeerModelProperties.PROP_REMOTE_SERVICES)); - completed.set(true); - } - }); - } - }); - - final long startTime = System.currentTimeMillis(); - final IConditionTester tester = new IConditionTester() { - @Override - public boolean isConditionFulfilled() { - return completed.get(); - } - - @Override - public void cleanup() {} - }; - - while ((startTime + 1000) < System.currentTimeMillis() && !tester.isConditionFulfilled()) { - try { - Thread.sleep(100); - } catch (InterruptedException e) { /* ignored on purpose */ } - } - - return services.get(); - } - - /** - * Client call back interface for doQueryServices(...). - */ - /* default */ interface DoneQueryServices { - /** - * Called when the services query completed. - * - * @param error The error description if operation failed, null if succeeded. - */ - void doneQueryServices(Throwable error); - } - - /* default */ final Map> serviceQueriesInProgress = new HashMap>(); - - /** - * Opens a channel to the peer node and query the services from the opened channel. - * - * @param node The peer node. Must not be null. - * @param serviceType The type of the requested services. See {@link IPeerModelProperties#PROP_LOCAL_SERVICES} and {@link IPeerModelProperties#PROP_REMOTE_SERVICES}. - * @param done The client callback. Must not be null. - */ - protected void doQueryServices(final IPeerModel node, final DoneQueryServices done) { - Assert.isTrue(Protocol.isDispatchThread(), "Illegal Thread Access"); //$NON-NLS-1$ - Assert.isNotNull(node); - Assert.isNotNull(done); - - // If a service query for the same peer is already in progress, - // attach the new done to the list to call and drop out - if (serviceQueriesInProgress.containsKey(node)) { - List dones = serviceQueriesInProgress.get(node); - Assert.isNotNull(dones); - dones.add(done); - return; - } - - // Add the done callback to a list of waiting callbacks per peer node - List dones = new ArrayList(); - dones.add(done); - serviceQueriesInProgress.put(node, dones); - - // Create the inner callback that invokes the queued outer callbacks - final DoneQueryServices innerDone = new DoneQueryServices() { - - @Override - public void doneQueryServices(Throwable error) { - // Get the list of the original done callbacks - List dones = serviceQueriesInProgress.remove(node); - for (DoneQueryServices done : dones) { - done.doneQueryServices(error); - } - } - }; - - // Do not try to open a channel to peers known to be unreachable - int state = node.getIntProperty(IPeerModelProperties.PROP_STATE); - if (state == IPeerModelProperties.STATE_ERROR || state == IPeerModelProperties.STATE_NOT_REACHABLE || !node.isComplete()) { - innerDone.doneQueryServices(null); - return; - } - - // Opens a channel with the full value-add chain - Tcf.getChannelManager().openChannel(node.getPeer(), null, new IChannelManager.DoneOpenChannel() { - - @Override - public void doneOpenChannel(Throwable error, IChannel channel) { - // If the channel opening failed -> return immediately - if (error != null) { - innerDone.doneQueryServices(error); - } else { - // Get the local service - List localServices = new ArrayList(channel.getLocalServices()); - // Get the remote services - List remoteServices = new ArrayList(channel.getRemoteServices()); - - // Close the channel - Tcf.getChannelManager().closeChannel(channel); - - // Sort the service lists - Collections.sort(localServices); - Collections.sort(remoteServices); - - // Update the services - ILocatorModelUpdateService updateService = node.getModel().getService(ILocatorModelUpdateService.class); - updateService.updatePeerServices(node, localServices, remoteServices); - - // Invoke the callback - innerDone.doneQueryServices(null); - } - } - }); - } -} +/******************************************************************************* + * Copyright (c) 2012 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.locator.services; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.tcf.protocol.IChannel; +import org.eclipse.tcf.protocol.Protocol; +import org.eclipse.tcf.te.runtime.interfaces.IConditionTester; +import org.eclipse.tcf.te.tcf.core.Tcf; +import org.eclipse.tcf.te.tcf.core.interfaces.IChannelManager; +import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.ILocatorModel; +import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerModel; +import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerModelProperties; +import org.eclipse.tcf.te.tcf.locator.interfaces.services.ILocatorModelPeerNodeQueryService; +import org.eclipse.tcf.te.tcf.locator.interfaces.services.ILocatorModelUpdateService; + +/** + * Default locator model peer node query service implementation. + */ +public class LocatorModelPeerNodeQueryService extends AbstractLocatorModelService implements ILocatorModelPeerNodeQueryService { + + /** + * Constructor. + * + * @param parentModel The parent locator model instance. Must not be null. + */ + public LocatorModelPeerNodeQueryService(ILocatorModel parentModel) { + super(parentModel); + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.tcf.locator.interfaces.services.ILocatorModelPeerNodeQueryService#queryLocalServices(org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerModel) + */ + @Override + public String queryLocalServices(final IPeerModel node) { + Assert.isTrue(!Protocol.isDispatchThread(), "Illegal Thread Access"); //$NON-NLS-1$ + Assert.isNotNull(node); + + // Check if the services has been cached before + final AtomicReference services = new AtomicReference(); + Protocol.invokeAndWait(new Runnable() { + @Override + public void run() { + services.set(node.getStringProperty(IPeerModelProperties.PROP_LOCAL_SERVICES)); + } + }); + + if (services.get() != null && !"".equals(services.get())) { //$NON-NLS-1$ + // Services are cached -> return immediately + return services.get(); + } + + // Get the service asynchronously and block the caller thread until + // the callback returned + final AtomicBoolean completed = new AtomicBoolean(false); + Protocol.invokeLater(new Runnable() { + @Override + public void run() { + // If the peer is a RemotePeer or has the "remote.transient" property set + // --> an agent is running and has been associated with the peer model. + if ("RemotePeer".equals(node.getPeer().getClass().getSimpleName()) || Boolean.valueOf(node.getPeer().getAttributes().get("remote.transient")).booleanValue()) { //$NON-NLS-1$ //$NON-NLS-2$ + doQueryServices(node, new DoneQueryServices() { + @Override + public void doneQueryServices(Throwable error) { + if (error == null) services.set(node.getStringProperty(IPeerModelProperties.PROP_LOCAL_SERVICES)); + completed.set(true); + } + }); + } else { + completed.set(true); + } + } + }); + + final long startTime = System.currentTimeMillis(); + final IConditionTester tester = new IConditionTester() { + @Override + public boolean isConditionFulfilled() { + return completed.get(); + } + + @Override + public void cleanup() {} + }; + + while ((startTime + 1000) < System.currentTimeMillis() && !tester.isConditionFulfilled()) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { /* ignored on purpose */ } + } + + return services.get(); + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.tcf.locator.interfaces.services.ILocatorModelPeerNodeQueryService#queryRemoteServices(org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerModel) + */ + @Override + public String queryRemoteServices(final IPeerModel node) { + Assert.isTrue(!Protocol.isDispatchThread(), "Illegal Thread Access"); //$NON-NLS-1$ + Assert.isNotNull(node); + + // Check if the services has been cached before + final AtomicReference services = new AtomicReference(); + Protocol.invokeAndWait(new Runnable() { + @Override + public void run() { + services.set(node.getStringProperty(IPeerModelProperties.PROP_REMOTE_SERVICES)); + } + }); + + if (services.get() != null && !"".equals(services.get())) { //$NON-NLS-1$ + // Services are cached -> return immediately + return services.get(); + } + + // Get the service asynchronously and block the caller thread until + // the callback returned + final AtomicBoolean completed = new AtomicBoolean(false); + Protocol.invokeLater(new Runnable() { + @Override + public void run() { + // If the peer is a RemotePeer or has the "remote.transient" property set + // --> an agent is running and has been associated with the peer model. + if ("RemotePeer".equals(node.getPeer().getClass().getSimpleName()) || Boolean.valueOf(node.getPeer().getAttributes().get("remote.transient")).booleanValue()) { //$NON-NLS-1$ //$NON-NLS-2$ + doQueryServices(node, new DoneQueryServices() { + @Override + public void doneQueryServices(Throwable error) { + if (error == null) services.set(node.getStringProperty(IPeerModelProperties.PROP_REMOTE_SERVICES)); + completed.set(true); + } + }); + } else { + completed.set(true); + } + } + }); + + final long startTime = System.currentTimeMillis(); + final IConditionTester tester = new IConditionTester() { + @Override + public boolean isConditionFulfilled() { + return completed.get(); + } + + @Override + public void cleanup() {} + }; + + while ((startTime + 1000) < System.currentTimeMillis() && !tester.isConditionFulfilled()) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { /* ignored on purpose */ } + } + + return services.get(); + } + + /** + * Client call back interface for doQueryServices(...). + */ + /* default */ interface DoneQueryServices { + /** + * Called when the services query completed. + * + * @param error The error description if operation failed, null if succeeded. + */ + void doneQueryServices(Throwable error); + } + + /* default */ final Map> serviceQueriesInProgress = new HashMap>(); + + /** + * Opens a channel to the peer node and query the services from the opened channel. + * + * @param node The peer node. Must not be null. + * @param serviceType The type of the requested services. See {@link IPeerModelProperties#PROP_LOCAL_SERVICES} and {@link IPeerModelProperties#PROP_REMOTE_SERVICES}. + * @param done The client callback. Must not be null. + */ + protected void doQueryServices(final IPeerModel node, final DoneQueryServices done) { + Assert.isTrue(Protocol.isDispatchThread(), "Illegal Thread Access"); //$NON-NLS-1$ + Assert.isNotNull(node); + Assert.isNotNull(done); + + // If a service query for the same peer is already in progress, + // attach the new done to the list to call and drop out + if (serviceQueriesInProgress.containsKey(node)) { + List dones = serviceQueriesInProgress.get(node); + Assert.isNotNull(dones); + dones.add(done); + return; + } + + // Add the done callback to a list of waiting callbacks per peer node + List dones = new ArrayList(); + dones.add(done); + serviceQueriesInProgress.put(node, dones); + + // Create the inner callback that invokes the queued outer callbacks + final DoneQueryServices innerDone = new DoneQueryServices() { + + @Override + public void doneQueryServices(Throwable error) { + // Get the list of the original done callbacks + List dones = serviceQueriesInProgress.remove(node); + for (DoneQueryServices done : dones) { + done.doneQueryServices(error); + } + } + }; + + // Do not try to open a channel to peers known to be unreachable + int state = node.getIntProperty(IPeerModelProperties.PROP_STATE); + if (state == IPeerModelProperties.STATE_ERROR || state == IPeerModelProperties.STATE_NOT_REACHABLE || !node.isComplete()) { + innerDone.doneQueryServices(null); + return; + } + + // Opens a channel with the full value-add chain + Tcf.getChannelManager().openChannel(node.getPeer(), null, new IChannelManager.DoneOpenChannel() { + + @Override + public void doneOpenChannel(Throwable error, IChannel channel) { + // If the channel opening failed -> return immediately + if (error != null) { + innerDone.doneQueryServices(error); + } else { + // Get the local service + List localServices = new ArrayList(channel.getLocalServices()); + // Get the remote services + List remoteServices = new ArrayList(channel.getRemoteServices()); + + // Close the channel + Tcf.getChannelManager().closeChannel(channel); + + // Sort the service lists + Collections.sort(localServices); + Collections.sort(remoteServices); + + // Update the services + ILocatorModelUpdateService updateService = node.getModel().getService(ILocatorModelUpdateService.class); + updateService.updatePeerServices(node, localServices, remoteServices); + + // Invoke the callback + innerDone.doneQueryServices(null); + } + } + }); + } +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/services/LocatorModelRefreshService.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/services/LocatorModelRefreshService.java index f1bfca9db..16e5b6f4c 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/services/LocatorModelRefreshService.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/services/LocatorModelRefreshService.java @@ -156,8 +156,16 @@ public class LocatorModelRefreshService extends AbstractLocatorModelService impl else { oldChildren.remove(peerNode); } - // Merge user configured properties between the peers - model.getService(ILocatorModelUpdateService.class).mergeUserDefinedAttributes(peerNode, peer, false); + + if (peerNode.getPeer() != peer) { + if ("RemotePeer".equals(peerNode.getPeer().getClass().getSimpleName())) { //$NON-NLS-1$ + peerNode.setProperty(IPeerModelProperties.PROP_INSTANCE, peer); + } else { + // Merge user configured properties between the peers + model.getService(ILocatorModelUpdateService.class).mergeUserDefinedAttributes(peerNode, peer, false); + } + } + // Validate the peer node before adding peerNode = model.validatePeerNodeForAdd(peerNode); if (peerNode != null) { diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/services/LocatorModelUpdateService.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/services/LocatorModelUpdateService.java index 321614c2d..883a30f70 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/services/LocatorModelUpdateService.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/services/LocatorModelUpdateService.java @@ -16,7 +16,6 @@ import java.util.List; import java.util.Map; import org.eclipse.core.runtime.Assert; -import org.eclipse.tcf.core.AbstractPeer; import org.eclipse.tcf.protocol.IPeer; import org.eclipse.tcf.protocol.Protocol; import org.eclipse.tcf.te.tcf.core.peers.Peer; @@ -187,7 +186,7 @@ public class LocatorModelUpdateService extends AbstractLocatorModelService imple // We can merge the peer attributes only if the destination peer is a AbstractPeer IPeer dst = node.getPeer(); // If not of correct type, than we cannot update the attributes - if (!(dst instanceof AbstractPeer) && !(dst instanceof PeerRedirector) && !(dst instanceof Peer)) return; + if (!(dst instanceof PeerRedirector) && !(dst instanceof Peer)) return; // If destination and source peer are the same objects(!) nothing to do here if (dst == peer) return; @@ -206,23 +205,38 @@ public class LocatorModelUpdateService extends AbstractLocatorModelService imple srcAttrs.remove(IPeer.ATTR_NAME); } + // Determine the peer class + String peerClassSimpleName = peer.getClass().getSimpleName(); + if (peer.getAttributes().containsKey("remote.transient")) { //$NON-NLS-1$ + peerClassSimpleName = "RemotePeer"; //$NON-NLS-1$ + } + // If the source is a RemotePeer and the destination not, attributes from // the remote peer overwrites local attributes. - if ("RemotePeer".equals(peer.getClass().getSimpleName()) && !"RemotePeer".equals(dst.getClass().getSimpleName())) { //$NON-NLS-1$ //$NON-NLS-2$ + if ("RemotePeer".equals(peerClassSimpleName) && !"RemotePeer".equals(dst.getClass().getSimpleName())) { //$NON-NLS-1$ //$NON-NLS-2$ + // The ID is not merged from remote to local + srcAttrs.remove(IPeer.ATTR_ID); + // Eliminate all attributes already set in the destination attributes map + String merged = dstAttrs.get("remote.merged.transient"); //$NON-NLS-1$ for (String key : dstAttrs.keySet()) { - srcAttrs.remove(key); + if (merged == null || !merged.contains(key)) { + srcAttrs.remove(key); + } } } // Mark the peer as a remote peer and remember the remote peer id - if ("RemotePeer".equals(peer.getClass().getSimpleName()) && !"RemotePeer".equals(dst.getClass().getSimpleName())) { //$NON-NLS-1$ //$NON-NLS-2$ + if ("RemotePeer".equals(peerClassSimpleName) && !"RemotePeer".equals(dst.getClass().getSimpleName())) { //$NON-NLS-1$ //$NON-NLS-2$ srcAttrs.put("remote.transient", Boolean.TRUE.toString()); //$NON-NLS-1$ srcAttrs.put("remote.id.transient", peer.getID()); //$NON-NLS-1$ + srcAttrs.put("remote.merged.transient", srcAttrs.keySet().toString()); //$NON-NLS-1$ } // Copy all remaining attributes from source to destination - if (!srcAttrs.isEmpty()) dstAttrs.putAll(srcAttrs); + if (!srcAttrs.isEmpty()) { + dstAttrs.putAll(srcAttrs); + } // If the ID's are different between the peers to merge and force is set, // we have set the ID in dstAttrs to the original one as set in the destination peer. @@ -231,9 +245,7 @@ public class LocatorModelUpdateService extends AbstractLocatorModelService imple } // And update the destination peer attributes - if (dst instanceof AbstractPeer) { - ((AbstractPeer)dst).updateAttributes(dstAttrs); - } else if (dst instanceof PeerRedirector) { + if (dst instanceof PeerRedirector) { ((PeerRedirector)dst).updateAttributes(dstAttrs); } else if (dst instanceof Peer) { ((Peer)dst).updateAttributes(dstAttrs); diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tests/src/org/eclipse/tcf/te/tests/tcf/TcfTestCase.java b/target_explorer/plugins/org.eclipse.tcf.te.tests/src/org/eclipse/tcf/te/tests/tcf/TcfTestCase.java index f79d47dac..1763f438e 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tests/src/org/eclipse/tcf/te/tests/tcf/TcfTestCase.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tests/src/org/eclipse/tcf/te/tests/tcf/TcfTestCase.java @@ -1,213 +1,219 @@ -/******************************************************************************* - * Copyright (c) 2012 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.tests.tcf; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; - -import org.eclipse.core.runtime.IPath; -import org.eclipse.tcf.core.TransientPeer; -import org.eclipse.tcf.protocol.IPeer; -import org.eclipse.tcf.protocol.JSON; -import org.eclipse.tcf.protocol.Protocol; -import org.eclipse.tcf.te.runtime.model.factory.Factory; -import org.eclipse.tcf.te.runtime.utils.Host; -import org.eclipse.tcf.te.runtime.utils.net.IPAddressUtil; -import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.ILocatorModel; -import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerModel; -import org.eclipse.tcf.te.tcf.locator.interfaces.services.ILocatorModelLookupService; -import org.eclipse.tcf.te.tcf.locator.model.Model; -import org.eclipse.tcf.te.tests.CoreTestCase; - -/** - * TCF test case implementation. - *

- * Launches a TCF agent at local host and make it available for a test case. - */ -public class TcfTestCase extends CoreTestCase { - // The agent launcher instance - private AgentLauncher launcher; - // The peer instance - protected IPeer peer; - // The peer model instance - protected IPeerModel peerModel; - - /* (non-Javadoc) - * @see org.eclipse.tcf.te.tests.CoreTestCase#setUp() - */ - @Override - protected void setUp() throws Exception { - super.setUp(); - launchAgent(); - } - - /* (non-Javadoc) - * @see org.eclipse.tcf.te.tests.CoreTestCase#tearDown() - */ - @Override - protected void tearDown() throws Exception { - if (launcher != null) launcher.dispose(); - peer = null; - peerModel = null; - super.tearDown(); - } - - /** - * Launches a TCF agent at local host. - */ - protected void launchAgent() { - // Get the agent location - IPath path = getAgentLocation(); - assertNotNull("Cannot determine TCF agent location.", path); //$NON-NLS-1$ - // Add the agent executable name - path = path.append("agent"); //$NON-NLS-1$ - if (Host.isWindowsHost()) path = path.addFileExtension("exe"); //$NON-NLS-1$ - assertTrue("Invalid agent location: " + path.toString(), path.toFile().isFile()); //$NON-NLS-1$ - - Throwable error = null; - String message = null; - - // If the agent is not marked executable on Linux, we have to change that - if (Host.isLinuxHost() && !path.toFile().canExecute()) { - try { - Runtime.getRuntime().exec(new String[] { "chmod", "u+x", path.toString() }); //$NON-NLS-1$ //$NON-NLS-2$ - } catch (IOException e) { - error = e; - message = e.getLocalizedMessage(); - } - } - assertNull("Failed to make the agent executable for the current user.", message); //$NON-NLS-1$ - - error = null; - message = null; - - assertTrue("Agent should be executable but is not.", path.toFile().canExecute()); //$NON-NLS-1$ - - // Create the agent launcher - launcher = new AgentLauncher(path); - try { - launcher.launch(); - } catch (Throwable e) { - error = e; - message = e.getLocalizedMessage(); - } - assertNull("Failed to launch agent: " + message, error); //$NON-NLS-1$ - - error = null; - message = null; - - assertNotNull("Process handle not associated with launcher.", launcher.getProcess()); //$NON-NLS-1$ - assertNotNull("Process output reader not associated with launcher.", launcher.getOutputReader()); //$NON-NLS-1$ - - Process process = launcher.getProcess(); - int exitCode = -1; - try { - exitCode = process.exitValue(); - } catch (IllegalThreadStateException e) { - error = e; - message = e.getLocalizedMessage(); - } - assertNotNull("Agent process died with exit code " + exitCode, error); //$NON-NLS-1$ - - error = null; - message = null; - - // The agent is started with "-S" to write out the peer attributes in JSON format. - String output = null; - int counter = 10; - while (counter > 0 && output == null) { - // Try to read in the output - output = launcher.getOutputReader().getOutput(); - if ("".equals(output)) { //$NON-NLS-1$ - output = null; - waitAndDispatch(200); - } - counter--; - } - assertNotNull("Failed to read output from agent.", output); //$NON-NLS-1$ - - // Strip away "Server-Properties:" - output = output.replace("Server-Properties:", " "); //$NON-NLS-1$ //$NON-NLS-2$ - output = output.trim(); - - // Read into an object +/******************************************************************************* + * Copyright (c) 2012 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.tests.tcf; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.tcf.core.TransientPeer; +import org.eclipse.tcf.protocol.IPeer; +import org.eclipse.tcf.protocol.JSON; +import org.eclipse.tcf.protocol.Protocol; +import org.eclipse.tcf.te.runtime.model.factory.Factory; +import org.eclipse.tcf.te.runtime.utils.Host; +import org.eclipse.tcf.te.runtime.utils.net.IPAddressUtil; +import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.ILocatorModel; +import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerModel; +import org.eclipse.tcf.te.tcf.locator.interfaces.services.ILocatorModelLookupService; +import org.eclipse.tcf.te.tcf.locator.model.Model; +import org.eclipse.tcf.te.tests.CoreTestCase; + +/** + * TCF test case implementation. + *

+ * Launches a TCF agent at local host and make it available for a test case. + */ +public class TcfTestCase extends CoreTestCase { + // The agent launcher instance + private AgentLauncher launcher; + // The peer instance + protected IPeer peer; + // The peer model instance + protected IPeerModel peerModel; + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.tests.CoreTestCase#setUp() + */ + @Override + protected void setUp() throws Exception { + super.setUp(); + launchAgent(); + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.tests.CoreTestCase#tearDown() + */ + @Override + protected void tearDown() throws Exception { + if (launcher != null) launcher.dispose(); + peer = null; + peerModel = null; + super.tearDown(); + } + + /** + * Launches a TCF agent at local host. + */ + protected void launchAgent() { + // Get the agent location + IPath path = getAgentLocation(); + assertNotNull("Cannot determine TCF agent location.", path); //$NON-NLS-1$ + // Add the agent executable name + path = path.append("agent"); //$NON-NLS-1$ + if (Host.isWindowsHost()) path = path.addFileExtension("exe"); //$NON-NLS-1$ + assertTrue("Invalid agent location: " + path.toString(), path.toFile().isFile()); //$NON-NLS-1$ + + Throwable error = null; + String message = null; + + // If the agent is not marked executable on Linux, we have to change that + if (Host.isLinuxHost() && !path.toFile().canExecute()) { + try { + Runtime.getRuntime().exec(new String[] { "chmod", "u+x", path.toString() }); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (IOException e) { + error = e; + message = e.getLocalizedMessage(); + } + } + assertNull("Failed to make the agent executable for the current user.", message); //$NON-NLS-1$ + + error = null; + message = null; + + assertTrue("Agent should be executable but is not.", path.toFile().canExecute()); //$NON-NLS-1$ + + // Create the agent launcher + launcher = new AgentLauncher(path); + try { + launcher.launch(); + } catch (Throwable e) { + error = e; + message = e.getLocalizedMessage(); + } + assertNull("Failed to launch agent: " + message, error); //$NON-NLS-1$ + + error = null; + message = null; + + assertNotNull("Process handle not associated with launcher.", launcher.getProcess()); //$NON-NLS-1$ + assertNotNull("Process output reader not associated with launcher.", launcher.getOutputReader()); //$NON-NLS-1$ + + Process process = launcher.getProcess(); + int exitCode = -1; + try { + exitCode = process.exitValue(); + } catch (IllegalThreadStateException e) { + error = e; + message = e.getLocalizedMessage(); + } + assertNotNull("Agent process died with exit code " + exitCode, error); //$NON-NLS-1$ + + error = null; + message = null; + + // The agent is started with "-S" to write out the peer attributes in JSON format. + String output = null; + int counter = 10; + while (counter > 0 && output == null) { + // Try to read in the output + output = launcher.getOutputReader().getOutput(); + if ("".equals(output)) { //$NON-NLS-1$ + output = null; + waitAndDispatch(200); + } + counter--; + } + assertNotNull("Failed to read output from agent.", output); //$NON-NLS-1$ + + // Find the "Server-Properties: ..." string within the output + int start = output.indexOf("Server-Properties:"); //$NON-NLS-1$ + if (start != -1 && start > 0) { + output = output.substring(start); + } + + // Strip away "Server-Properties:" + output = output.replace("Server-Properties:", " "); //$NON-NLS-1$ //$NON-NLS-2$ + output = output.trim(); + + // Read into an object Object object = parseOne(output); - @SuppressWarnings("unchecked") - final Map attrs = new HashMap((Map)object); - - // Lookup the corresponding peer object - final ILocatorModel model = Model.getModel(); - assertNotNull("Failed to access locator model instance.", model); //$NON-NLS-1$ - - // The expected peer id is "::" - String transport = attrs.get(IPeer.ATTR_TRANSPORT_NAME); - assertNotNull("Unexpected return value 'null'.", transport); //$NON-NLS-1$ - String port = attrs.get(IPeer.ATTR_IP_PORT); - assertNotNull("Unexpected return value 'null'.", port); //$NON-NLS-1$ - String ip = IPAddressUtil.getInstance().getIPv4LoopbackAddress(); - assertNotNull("Unexpected return value 'null'.", ip); //$NON-NLS-1$ - - final String id = transport + ":" + ip + ":" + port; //$NON-NLS-1$ //$NON-NLS-2$ - final AtomicReference node = new AtomicReference(); - - Runnable runnable = new Runnable() { - @Override - public void run() { - node.set(model.getService(ILocatorModelLookupService.class).lkupPeerModelById(id)); - // If the peer model is not found by id, try the agent id as fallback. - if (node.get() == null) { - String agentID = attrs.get(IPeer.ATTR_AGENT_ID); - assertNotNull("Unexpected return value 'null'.", agentID); //$NON-NLS-1$ - IPeerModel[] candidates = model.getService(ILocatorModelLookupService.class).lkupPeerModelByAgentId(agentID); - if (candidates != null && candidates.length > 0) node.set(candidates[0]); - } - } - }; - assertFalse("Test is running in TCF dispatch thread.", Protocol.isDispatchThread()); //$NON-NLS-1$ - Protocol.invokeAndWait(runnable); - - // If the peer model is still not found, we create a transient peer - if (node.get() == null) { - attrs.put(IPeer.ATTR_ID, id); - attrs.put(IPeer.ATTR_IP_HOST, ip); - peer = new TransientPeer(attrs); - peerModel = Factory.getInstance().newInstance(IPeerModel.class, new Object[] { model, peer }); - } else { - peerModel = node.get(); - peer = peerModel.getPeer(); - } - assertNotNull("Failed to determine the peer to use for the tests.", peer); //$NON-NLS-1$ - } - - /** - * Returns the agent location. - * - * @return The agent location or null if not found. - */ - protected IPath getAgentLocation() { - return getDataLocation("agent", true, true); //$NON-NLS-1$ - } - - /** - * Parses a object from the given encoded string. - * - * @param encoded The encoded string. Must not be null. - * @return The object + @SuppressWarnings("unchecked") + final Map attrs = new HashMap((Map)object); + + // Lookup the corresponding peer object + final ILocatorModel model = Model.getModel(); + assertNotNull("Failed to access locator model instance.", model); //$NON-NLS-1$ + + // The expected peer id is "::" + String transport = attrs.get(IPeer.ATTR_TRANSPORT_NAME); + assertNotNull("Unexpected return value 'null'.", transport); //$NON-NLS-1$ + String port = attrs.get(IPeer.ATTR_IP_PORT); + assertNotNull("Unexpected return value 'null'.", port); //$NON-NLS-1$ + String ip = IPAddressUtil.getInstance().getIPv4LoopbackAddress(); + assertNotNull("Unexpected return value 'null'.", ip); //$NON-NLS-1$ + + final String id = transport + ":" + ip + ":" + port; //$NON-NLS-1$ //$NON-NLS-2$ + final AtomicReference node = new AtomicReference(); + + Runnable runnable = new Runnable() { + @Override + public void run() { + node.set(model.getService(ILocatorModelLookupService.class).lkupPeerModelById(id)); + // If the peer model is not found by id, try the agent id as fallback. + if (node.get() == null) { + String agentID = attrs.get(IPeer.ATTR_AGENT_ID); + assertNotNull("Unexpected return value 'null'.", agentID); //$NON-NLS-1$ + IPeerModel[] candidates = model.getService(ILocatorModelLookupService.class).lkupPeerModelByAgentId(agentID); + if (candidates != null && candidates.length > 0) node.set(candidates[0]); + } + } + }; + assertFalse("Test is running in TCF dispatch thread.", Protocol.isDispatchThread()); //$NON-NLS-1$ + Protocol.invokeAndWait(runnable); + + // If the peer model is still not found, we create a transient peer + if (node.get() == null) { + attrs.put(IPeer.ATTR_ID, id); + attrs.put(IPeer.ATTR_IP_HOST, ip); + peer = new TransientPeer(attrs); + peerModel = Factory.getInstance().newInstance(IPeerModel.class, new Object[] { model, peer }); + } else { + peerModel = node.get(); + peer = peerModel.getPeer(); + } + assertNotNull("Failed to determine the peer to use for the tests.", peer); //$NON-NLS-1$ + } + + /** + * Returns the agent location. + * + * @return The agent location or null if not found. + */ + protected IPath getAgentLocation() { + return getDataLocation("agent", true, true); //$NON-NLS-1$ + } + + /** + * Parses a object from the given encoded string. + * + * @param encoded The encoded string. Must not be null. + * @return The object */ - private static Object parseOne(final String encoded) { - assertNotNull(encoded); + private static Object parseOne(final String encoded) { + assertNotNull(encoded); - final AtomicReference object = new AtomicReference(); - final AtomicReference message = new AtomicReference(); + final AtomicReference object = new AtomicReference(); + final AtomicReference message = new AtomicReference(); final AtomicReference error = new AtomicReference(); Runnable runnable = new Runnable() { @@ -220,13 +226,13 @@ public class TcfTestCase extends CoreTestCase { message.set(e.getLocalizedMessage()); } } - }; - assertFalse("Test is running in TCF dispatch thread.", Protocol.isDispatchThread()); //$NON-NLS-1$ - Protocol.invokeAndWait(runnable); + }; + assertFalse("Test is running in TCF dispatch thread.", Protocol.isDispatchThread()); //$NON-NLS-1$ + Protocol.invokeAndWait(runnable); assertNull("Failed to parse server properties: " + message.get(), error.get()); //$NON-NLS-1$ - assertTrue("Server properties object is not of expected type Map.", object.get() instanceof Map); //$NON-NLS-1$ + assertTrue("Server properties object is not of expected type Map.", object.get() instanceof Map); //$NON-NLS-1$ return object.get(); } -} +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.ui.views/src/org/eclipse/tcf/te/ui/views/ViewsUtil.java b/target_explorer/plugins/org.eclipse.tcf.te.ui.views/src/org/eclipse/tcf/te/ui/views/ViewsUtil.java index ef92b92a1..980c8c485 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.ui.views/src/org/eclipse/tcf/te/ui/views/ViewsUtil.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.ui.views/src/org/eclipse/tcf/te/ui/views/ViewsUtil.java @@ -14,6 +14,7 @@ import org.eclipse.jface.action.IAction; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.StructuredViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.tcf.te.ui.views.extensions.CategoriesExtensionPointManager; import org.eclipse.tcf.te.ui.views.handler.PropertiesCommandHandler; @@ -112,6 +113,44 @@ public class ViewsUtil { } } + /** + * Asynchronously refresh the given element within the view identified + * by the given id. + * + * @param id The view id. Must not be null. + * @param element The element to refresh. Must not be null. + */ + public static void refresh(final String id, final Object element) { + Assert.isNotNull(id); + Assert.isNotNull(element); + + // Create the runnable + Runnable runnable = new Runnable() { + @Override + public void run() { + // Check the active workbench window and active page instances + if (PlatformUI.getWorkbench().getActiveWorkbenchWindow() != null && PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage() != null) { + // Get the view reference + IViewReference reference = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().findViewReference(id); + // Get the view part from the reference, but do not restore it + IWorkbenchPart part = reference != null ? reference.getPart(false) : null; + // If the part is a common navigator, get the common viewer + Viewer viewer = part instanceof CommonNavigator ? ((CommonNavigator)part).getCommonViewer() : null; + // If not a common navigator, try to adapt to the viewer + if (viewer == null) viewer = part != null ? (Viewer)part.getAdapter(Viewer.class) : null; + // Refresh the viewer + if (viewer instanceof StructuredViewer) ((StructuredViewer)viewer).refresh(element, true); + else viewer.refresh(); + } + } + }; + + // Execute asynchronously + if (PlatformUI.isWorkbenchRunning()) { + PlatformUI.getWorkbench().getDisplay().asyncExec(runnable); + } + } + /** * Asynchronously set the given selection to the view identified by the given id. * -- cgit v1.2.3