/******************************************************************************* * Copyright (c) 2008, 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.internal.services.local; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.eclipse.tcf.internal.core.ChannelLoop; import org.eclipse.tcf.core.AbstractChannel; import org.eclipse.tcf.protocol.IChannel; import org.eclipse.tcf.protocol.IService; import org.eclipse.tcf.protocol.IToken; /** * ChannelProxy implements forwarding of TCF messages between two channels. * The class is used to implement Locator service "redirect" command. */ class ChannelProxy { private final AbstractChannel ch_x; private final AbstractChannel ch_y; private boolean closed_x; private boolean closed_y; private final Map<IToken,IToken> tokens_x = new HashMap<IToken,IToken>(); private final Map<IToken,IToken> tokens_y = new HashMap<IToken,IToken>(); private final AbstractChannel.Proxy proxy_x = new AbstractChannel.Proxy() { public void onChannelClosed(Throwable error) { closed_x = true; if (closed_y) return; if (error == null) ch_y.close(); else ch_y.terminate(error); } public void onCommand(IToken token, String service, String name, byte[] data) { if (closed_y) return; assert ch_y.getState() == IChannel.STATE_OPEN; IService s = ch_y.getRemoteService(service); if (s == null) ch_x.terminate(new IOException("Invalid service name")); else tokens_x.put(ch_y.sendCommand(s, name, data, cmd_listener_x), token); } public void onEvent(String service, String name, byte[] data) { IService s = ch_x.getRemoteService(service); if (s == null) ch_x.terminate(new IOException("Invalid service name")); else if (!closed_y) ch_y.sendEvent(s, name, data); } }; private final AbstractChannel.Proxy proxy_y = new AbstractChannel.Proxy() { public void onChannelClosed(Throwable error) { closed_y = true; if (closed_x) return; if (error == null) ch_x.close(); else ch_x.terminate(error); } public void onCommand(IToken token, String service, String name, byte[] data) { if (closed_x) return; assert ch_x.getState() == IChannel.STATE_OPEN; IService s = ch_x.getRemoteService(service); if (s == null) ch_y.terminate(new IOException("Invalid service name")); else tokens_y.put(ch_x.sendCommand(s, name, data, cmd_listener_y), token); } public void onEvent(String service, String name, byte[] data) { IService s = ch_y.getRemoteService(service); if (s == null) ch_y.terminate(new IOException("Invalid service name")); else if (!closed_x) ch_x.sendEvent(s, name, data); } }; private final IChannel.ICommandListener cmd_listener_x = new IChannel.ICommandListener() { public void progress(IToken token, byte[] data) { ch_x.sendProgress(tokens_x.get(token), data); } public void result(IToken token, byte[] data) { ch_x.sendResult(tokens_x.remove(token), data); } public void terminated(IToken token, Exception error) { ch_x.rejectCommand(tokens_x.remove(token)); } }; private final IChannel.ICommandListener cmd_listener_y = new IChannel.ICommandListener() { public void progress(IToken token, byte[] data) { ch_y.sendProgress(tokens_y.get(token), data); } public void result(IToken token, byte[] data) { ch_y.sendResult(tokens_y.remove(token), data); } public void terminated(IToken token, Exception error) { ch_y.rejectCommand(tokens_y.remove(token)); } }; ChannelProxy(IChannel x, IChannel y) { assert !(x instanceof ChannelLoop); assert !(y instanceof ChannelLoop); ch_x = (AbstractChannel)x; ch_y = (AbstractChannel)y; assert ch_x.getState() == IChannel.STATE_OPEN; assert ch_y.getState() == IChannel.STATE_OPENING; try { ch_y.setProxy(proxy_y, ch_x.getRemoteServices()); ch_y.addChannelListener(new IChannel.IChannelListener() { public void congestionLevel(int level) { } public void onChannelClosed(Throwable error) { ch_y.removeChannelListener(this); if (error == null) error = new Exception("Channel closed"); ch_x.terminate(error); } public void onChannelOpened() { ch_y.removeChannelListener(this); try { ch_x.setProxy(proxy_x, ch_y.getRemoteServices()); } catch (IOException e) { ch_x.terminate(e); ch_y.terminate(e); } } }); } catch (IOException e) { ch_x.terminate(e); ch_y.terminate(e); } } }