diff options
Diffstat (limited to 'plugins/org.eclipse.tcf.core/src/org/eclipse/tcf/internal/core/TransportManager.java')
-rw-r--r-- | plugins/org.eclipse.tcf.core/src/org/eclipse/tcf/internal/core/TransportManager.java | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/plugins/org.eclipse.tcf.core/src/org/eclipse/tcf/internal/core/TransportManager.java b/plugins/org.eclipse.tcf.core/src/org/eclipse/tcf/internal/core/TransportManager.java new file mode 100644 index 000000000..58ed4a497 --- /dev/null +++ b/plugins/org.eclipse.tcf.core/src/org/eclipse/tcf/internal/core/TransportManager.java @@ -0,0 +1,220 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 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.tm.internal.tcf.core; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.Set; + +import org.eclipse.tm.tcf.core.AbstractChannel; +import org.eclipse.tm.tcf.core.ChannelPIPE; +import org.eclipse.tm.tcf.core.ChannelTCP; +import org.eclipse.tm.tcf.protocol.IChannel; +import org.eclipse.tm.tcf.protocol.IPeer; +import org.eclipse.tm.tcf.protocol.IService; +import org.eclipse.tm.tcf.protocol.IToken; +import org.eclipse.tm.tcf.protocol.ITransportProvider; +import org.eclipse.tm.tcf.protocol.Protocol; +import org.eclipse.tm.tcf.services.ILocator; + + +public class TransportManager { + + private static final Collection<AbstractChannel> channels = + new LinkedList<AbstractChannel>(); + private static final Collection<Protocol.ChannelOpenListener> listeners = + new LinkedList<Protocol.ChannelOpenListener>(); + private static final HashMap<String,ITransportProvider> transports = + new HashMap<String,ITransportProvider>(); + + static { + addTransportProvider(new ITransportProvider() { + + public String getName() { + return "TCP"; + } + + public IChannel openChannel(IPeer peer) { + assert getName().equals(peer.getTransportName()); + Map<String,String> attrs = peer.getAttributes(); + String host = attrs.get(IPeer.ATTR_IP_HOST); + String port = attrs.get(IPeer.ATTR_IP_PORT); + if (host == null) throw new IllegalArgumentException("No host name"); + return new ChannelTCP(peer, host, parsePort(port), false); + } + }); + + addTransportProvider(new ITransportProvider() { + + public String getName() { + return "SSL"; + } + + public IChannel openChannel(IPeer peer) { + assert getName().equals(peer.getTransportName()); + Map<String,String> attrs = peer.getAttributes(); + String host = attrs.get(IPeer.ATTR_IP_HOST); + String port = attrs.get(IPeer.ATTR_IP_PORT); + if (host == null) throw new IllegalArgumentException("No host name"); + return new ChannelTCP(peer, host, parsePort(port), true); + } + }); + + addTransportProvider(new ITransportProvider() { + + public String getName() { + return "PIPE"; + } + + public IChannel openChannel(IPeer peer) { + assert getName().equals(peer.getTransportName()); + String name = peer.getAttributes().get("PipeName"); + if (name == null) name = "//./pipe/TCF-Agent"; + return new ChannelPIPE(peer, name); + } + }); + + addTransportProvider(new ITransportProvider() { + + public String getName() { + return "Loop"; + } + + public IChannel openChannel(IPeer peer) { + assert getName().equals(peer.getTransportName()); + return new ChannelLoop(peer); + } + }); + } + + private static int parsePort(String port) { + if (port == null) throw new Error("No port number"); + try { + return Integer.parseInt(port); + } + catch (NumberFormatException x) { + IllegalArgumentException y = new IllegalArgumentException( + "Invalid value of \"Port\" attribute. Must be decimal number."); + y.initCause(x); + throw y; + } + } + + public static void addTransportProvider(ITransportProvider transport) { + String name = transport.getName(); + assert name != null; + synchronized (transports) { + if (transports.get(name) != null) throw new Error("Already registered: " + name); + transports.put(name, transport); + } + } + + public static void removeTransportProvider(ITransportProvider transport) { + String name = transport.getName(); + assert name != null; + synchronized (transports) { + if (transports.get(name) == transport) transports.remove(name); + } + } + + public static IChannel openChannel(IPeer peer) { + String name = peer.getTransportName(); + if (name == null) throw new Error("No transport name"); + ITransportProvider transport = null; + synchronized (transports) { + transport = transports.get(name); + if (transport == null) throw new Error("Unknown transport name: " + name); + } + return transport.openChannel(peer); + } + + public static void channelOpened(final AbstractChannel channel) { + assert !channels.contains(channel); + channels.add(channel); + Protocol.ChannelOpenListener[] array = listeners.toArray(new Protocol.ChannelOpenListener[listeners.size()]); + for (Protocol.ChannelOpenListener l : array) { + try { + l.onChannelOpen(channel); + } + catch (Throwable x) { + Protocol.log("Exception in channel listener", x); + } + } + } + + public static void channelClosed(final AbstractChannel channel, final Throwable x) { + assert channels.contains(channel); + channels.remove(channel); + } + + public static IChannel[] getOpenChannels() { + return channels.toArray(new IChannel[channels.size()]); + } + + public static void addChanelOpenListener(Protocol.ChannelOpenListener listener) { + assert listener != null; + listeners.add(listener); + } + + public static void removeChanelOpenListener(Protocol.ChannelOpenListener listener) { + listeners.remove(listener); + } + + /** + * Transmit TCF event message. + * The message is sent to all open communication channels – broadcasted. + * + * This is internal API, TCF clients should use {@code org.eclipse.tm.tcf.protocol.Protocol}. + */ + public static void sendEvent(String service_name, String event_name, byte[] data) { + for (AbstractChannel c : channels) { + // Skip channels that are executing "redirect" command - STATE_OPENING + if (c.getState() == IChannel.STATE_OPEN) { + IService s = c.getLocalService(service_name); + if (s != null) c.sendEvent(s, event_name, data); + } + } + } + + /** + * Call back after TCF messages sent by this host up to this moment are delivered + * to their intended targets. This method is intended for synchronization of messages + * across multiple channels. + * + * Note: Cross channel synchronization can reduce performance and throughput. + * Most clients don't need cross channel synchronization and should not call this method. + * + * @param done will be executed by dispatch thread after communication + * messages are delivered to corresponding targets. + * + * This is internal API, TCF clients should use {@code org.eclipse.tm.tcf.protocol.Protocol}. + */ + public static void sync(final Runnable done) { + final Set<IToken> set = new HashSet<IToken>(); + ILocator.DoneSync done_sync = new ILocator.DoneSync() { + public void doneSync(IToken token) { + assert set.contains(token); + set.remove(token); + if (set.isEmpty()) done.run(); + } + }; + for (AbstractChannel c : channels) { + if (c.getState() == IChannel.STATE_OPEN) { + ILocator s = c.getRemoteService(ILocator.class); + if (s != null) set.add(s.sync(done_sync)); + } + } + if (set.isEmpty()) Protocol.invokeLater(done); + } +} |