2
* JBoss, Home of Professional Open Source
3
* Copyright 2005, JBoss Inc., and individual contributors as indicated
4
* by the @authors tag. See the copyright.txt in the distribution for a
5
* full listing of individual contributors.
7
* This is free software; you can redistribute it and/or modify it
8
* under the terms of the GNU Lesser General Public License as
9
* published by the Free Software Foundation; either version 2.1 of
10
* the License, or (at your option) any later version.
12
* This software is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with this software; if not, write to the Free
19
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23
package org.jboss.remoting.transport.multiplex;
25
import org.jboss.logging.Logger;
26
import org.jboss.remoting.ConnectionFailedException;
27
import org.jboss.remoting.InvokerLocator;
28
import org.jboss.remoting.marshal.Marshaller;
29
import org.jboss.remoting.marshal.UnMarshaller;
30
import org.jboss.remoting.marshal.serializable.SerializableMarshaller;
31
import org.jboss.remoting.transport.BidirectionalClientInvoker;
32
import org.jboss.remoting.transport.PortUtil;
33
import org.jboss.remoting.transport.multiplex.MultiplexServerInvoker.SocketGroupInfo;
34
import org.jboss.remoting.transport.multiplex.utility.AddressPair;
35
import org.jboss.remoting.transport.socket.ClientSocketWrapper;
36
import org.jboss.remoting.transport.socket.SocketClientInvoker;
38
import java.io.IOException;
39
import java.net.InetAddress;
40
import java.net.InetSocketAddress;
41
import java.net.Socket;
45
* <code>MultiplexClientInvoker</code> is the client side of the Multiplex transport.
46
* For more information, see Remoting documentation on labs.jboss.org.
48
* @author <a href="mailto:tom.elrod@jboss.com">Tom Elrod</a>
49
* @author <a href="mailto:ron.sigal@jboss.com">Ron Sigal</a>
51
* @deprecated As of release 2.4.0 the multiplex transport will no longer be actively supported.
53
public class MultiplexClientInvoker extends SocketClientInvoker implements BidirectionalClientInvoker
55
private static final Logger log = Logger.getLogger(MultiplexClientInvoker.class);
56
private static final boolean isTraceEnabled = log.isTraceEnabled();
58
private InetAddress connectAddress;
59
private String connectHost;
60
private int connectPort;
61
private InetSocketAddress connectSocketAddress;
62
private InetSocketAddress bindSocketAddress;
63
private String socketGroupId;
64
private MultiplexServerInvoker.SocketGroupInfo socketGroupInfo;
65
private AddressPair addressPair;
66
private boolean readyToRun;
68
protected String clientSocketClassName = ClientSocketWrapper.class.getName();
72
* Create a new <code>MultiplexClientInvoker</code>.
76
public MultiplexClientInvoker(InvokerLocator locator) throws IOException
83
* Create a new <code>MultiplexClientInvoker</code>.
87
public MultiplexClientInvoker(InvokerLocator locator, Map configuration) throws IOException
89
super(locator, configuration);
93
protected void handleConnect() throws ConnectionFailedException
97
log.debug("configuring MultiplexClientInvoker for: " + locator);
98
super.handleConnect();
100
this.connectAddress = InetAddress.getByName(locator.getHost());
101
this.connectHost = connectAddress.getHostName();
102
this.connectPort = locator.getPort();
103
this.connectSocketAddress = new InetSocketAddress(connectAddress, connectPort);
105
if (getSocketFactory() != null)
106
configuration.put(Multiplex.SOCKET_FACTORY, getSocketFactory());
108
Map parameters = configuration;
110
if (parameters != null)
112
configureSocketGroupParameters(parameters);
117
throw new ConnectionFailedException(e.getMessage());
123
* Finishes the start up process, once adequate bind and connect information is
124
* made available. For more information, see the Multiplex subsystem documentation
127
public void finishStart() throws IOException
129
if (socketGroupInfo != null &&
130
socketGroupInfo.getBindAddress() != null &&
131
bindSocketAddress == null)
133
InetAddress bindAddress = socketGroupInfo.getBindAddress();
134
int bindPort = socketGroupInfo.getBindPort();
135
bindSocketAddress = new InetSocketAddress(bindAddress, bindPort);
138
if (socketGroupInfo != null &&
139
socketGroupInfo.getBindAddress() != null &&
142
String bindHost = socketGroupInfo.getBindAddress().getHostName();
143
int bindPort = socketGroupInfo.getBindPort();
144
addressPair = new AddressPair(connectHost, connectPort, bindHost, bindPort);
150
public InvokerLocator getCallbackLocator(Map metadata)
152
Socket socket = socketGroupInfo.getPrimingSocket();
153
metadata.put(Multiplex.MULTIPLEX_CONNECT_HOST,
154
socket.getInetAddress().getHostAddress());
155
metadata.put(Multiplex.MULTIPLEX_CONNECT_PORT,
156
Integer.toString(socket.getPort()));
157
metadata.put(Multiplex.MULTIPLEX_BIND_HOST,
158
socket.getInetAddress().getHostAddress());
159
metadata.put(Multiplex.MULTIPLEX_BIND_PORT,
160
Integer.toString(socket.getPort()));
161
InvokerLocator locator = new InvokerLocator("multiplex",
162
socket.getLocalAddress().getHostAddress(),
163
socket.getLocalPort(),
171
* @throws IOException
173
protected void configureSocketGroupParameters(Map parameters) throws IOException
176
String bindPortString;
178
InetAddress bindAddress = null;
179
socketGroupId = (String) parameters.get(Multiplex.CLIENT_MULTIPLEX_ID);
180
log.debug("socketGroupId: " + socketGroupId);
182
synchronized (MultiplexServerInvoker.SocketGroupInfo.class)
184
if (socketGroupId != null)
185
socketGroupInfo = (SocketGroupInfo) MultiplexServerInvoker.getSocketGroupMap().get(socketGroupId);
187
if (socketGroupInfo != null && socketGroupInfo.getServerInvoker() != null)
189
log.debug("client rule 1");
191
// If we get here, it's because a MultiplexServerInvoker created a SocketGroupInfo with matching
192
// group id. We want to make sure that it didn't get a connect address or connect port different
193
// than the ones passed in through the parameters map.
194
InetAddress socketGroupConnectAddress = socketGroupInfo.getConnectAddress();
195
int socketGroupConnectPort = socketGroupInfo.getConnectPort();
197
if (socketGroupConnectAddress != null && !socketGroupConnectAddress.equals(connectAddress))
199
String message = "socket group connect address (" + socketGroupConnectAddress +
200
") does not match connect address (" + connectAddress + ")";
202
throw new IOException(message);
205
if (socketGroupConnectPort > 0 && socketGroupConnectPort != connectPort)
207
String message = "socket group connect port (" + socketGroupConnectPort +
208
") does not match connect port (" + connectPort + ")";
210
throw new IOException(message);
213
bindAddress = socketGroupInfo.getBindAddress();
214
bindPort = socketGroupInfo.getBindPort();
215
bindSocketAddress = new InetSocketAddress(bindAddress, bindPort);
217
if (socketGroupInfo.getPrimingSocket() == null)
219
String connectHost = connectAddress.getHostName();
220
MultiplexServerInvoker.createPrimingSocket(socketGroupInfo, connectHost, connectPort,
221
bindAddress, bindPort,
222
configuration, timeout);
225
socketGroupInfo.setConnectAddress(connectAddress);
226
socketGroupInfo.setConnectPort(connectPort);
227
socketGroupInfo.addClientInvoker(this);
229
// We got socketGroupInfo by socketGroupId. Make sure it is also stored by AddressPair.
230
bindHost = bindAddress.getHostName();
231
addressPair = new AddressPair(connectHost, connectPort, bindHost, bindPort);
232
MultiplexServerInvoker.getAddressPairMap().put(addressPair, socketGroupInfo);
234
MultiplexServerInvoker serverInvoker = socketGroupInfo.getServerInvoker();
235
if (serverInvoker != null)
236
serverInvoker.finishStart();
242
bindHost = (String) parameters.get(Multiplex.MULTIPLEX_BIND_HOST);
243
bindPortString = (String) parameters.get(Multiplex.MULTIPLEX_BIND_PORT);
245
if (bindHost != null && bindPortString == null)
247
bindPortString = "0";
250
if (bindHost == null && bindPortString != null)
252
bindHost = "localhost";
255
if (bindHost != null)
257
log.debug("client rule 2");
261
bindPort = Integer.parseInt(bindPortString);
263
catch (NumberFormatException e)
265
throw new IOException("number format error for bindPort: " + bindPortString);
270
bindSocketAddress = new InetSocketAddress(bindHost, bindPort);
271
addressPair = new AddressPair(connectHost, connectPort, bindHost, bindPort);
272
socketGroupInfo = (SocketGroupInfo) MultiplexServerInvoker.getAddressPairMap().get(addressPair);
275
// If socketGroupInfo exists, it's because it was created, along with a priming socket, by a
276
// MultiplexServerInvoker. Note that we don't look for a match if the bind port was
278
if (socketGroupInfo != null)
280
socketGroupInfo.setConnectAddress(connectAddress);
281
socketGroupInfo.setConnectPort(connectPort);
282
socketGroupInfo.addClientInvoker(this);
284
// We got socketGroupInfo by AddressPair. Make sure it is stored by socketGroupId, if we have one.
285
if (socketGroupId != null)
287
String socketGroupSocketGroupId = socketGroupInfo.getSocketGroupId();
289
if (socketGroupSocketGroupId != null && !socketGroupSocketGroupId.equals(socketGroupId))
291
String message = "socket group multiplexId (" + socketGroupSocketGroupId +
292
") does not match multiplexId (" + socketGroupId + ")";
294
throw new IOException(message);
297
if (socketGroupSocketGroupId == null)
299
socketGroupInfo.setSocketGroupId(socketGroupId);
300
MultiplexServerInvoker.getSocketGroupMap().put(socketGroupId, socketGroupInfo);
308
if (bindPort == 0 && socketGroupId == null)
310
String message = "Can never be found by any MultiplexServerInvoker: " +
311
"bind port == 0 and socketGroupId == null";
315
// Anonymous bind port
317
bindPort = PortUtil.findFreePort(bindHost);
319
socketGroupInfo = new SocketGroupInfo();
320
socketGroupInfo.setConnectAddress(connectAddress);
321
socketGroupInfo.setConnectPort(connectPort);
322
socketGroupInfo.addClientInvoker(this);
324
// Set bindAddress and bindPort to be able to test for inconsistencies with bind address
325
// and bind port determined by companion MultiplexServerInvoker.
326
bindAddress = InetAddress.getByName(bindHost);
327
socketGroupInfo.setBindAddress(bindAddress);
328
socketGroupInfo.setBindPort(bindPort);
330
String connectHost = connectAddress.getHostName();
331
MultiplexServerInvoker.createPrimingSocket(socketGroupInfo, connectHost, connectPort,
332
bindAddress, bindPort, configuration, timeout);
333
MultiplexServerInvoker.getAddressPairMap().put(addressPair, socketGroupInfo);
335
if (socketGroupId != null)
337
socketGroupInfo.setSocketGroupId(socketGroupId);
338
MultiplexServerInvoker.getSocketGroupMap().put(socketGroupId, socketGroupInfo);
345
if (socketGroupId != null)
347
log.debug("client rule 3");
349
if (socketGroupInfo == null)
351
socketGroupInfo = new SocketGroupInfo();
352
socketGroupInfo.setSocketGroupId(socketGroupId);
353
socketGroupInfo.setConnectAddress(connectAddress);
354
socketGroupInfo.setConnectPort(connectPort);
355
MultiplexServerInvoker.getSocketGroupMap().put(socketGroupId, socketGroupInfo);
358
socketGroupInfo.addClientInvoker(this);
362
log.debug("client rule 4");
363
String connectHost = connectAddress.getHostName();
364
socketGroupInfo = new SocketGroupInfo();
365
MultiplexServerInvoker.createPrimingSocket(socketGroupInfo, connectHost, connectPort,
366
configuration, timeout);
376
* @throws java.io.IOException
377
* @throws org.jboss.remoting.ConnectionFailedException
380
protected Object transport(String sessionId, Object invocation, Map metadata, Marshaller marshaller, UnMarshaller unmarshaller)
381
throws IOException, ConnectionFailedException, ClassNotFoundException
383
log.debug("entering transport()");
385
throw new IOException("connection to server has not been made");
387
return super.transport(sessionId, invocation, metadata, marshaller, unmarshaller);
392
* subclasses must implement this method to provide a hook to disconnect from the remote server, if this applies
393
* to the specific transport. However, in some transport implementations, this may not make must difference since
394
* the connection is not persistent among invocations, such as SOAP. In these cases, the method should
395
* silently return without any processing.
397
protected void handleDisconnect()
399
//TODO: -TME Should this be a no op or need to pool?
401
log.debug("entering handleDisconnect()");
402
super.handleDisconnect();
404
synchronized (MultiplexServerInvoker.SocketGroupInfo.class)
406
if (socketGroupInfo != null)
408
socketGroupInfo.removeClientInvoker(this);
410
if (socketGroupInfo.getClientInvokers().isEmpty() && socketGroupInfo.getServerInvoker() == null)
412
log.debug("invoker group shutting down: " + socketGroupInfo.getSocketGroupId());
414
if (socketGroupInfo.getPrimingSocket() != null)
416
log.debug("MultiplexClientInvoker: closing bind priming socket");
418
VirtualSocket ps = socketGroupInfo.getPrimingSocket();
423
// When the remote virtual MultiplexServerInvoker learns that the
424
// priming socket has closed, it will close its VirtualServerSocket,
425
// rendering unshareable the MultiplexingManager that underlies this
426
// socket group. We mark it as unshareable immediately so that it will
427
// not be reused by any other socket group.
428
ps.getManager().unregisterShareable();
431
catch (IOException e)
433
log.error("Error closing bind priming socket during cleanup upon stopping", e);
438
socketGroupId = socketGroupInfo.getSocketGroupId();
440
if (socketGroupId != null)
442
MultiplexServerInvoker.getSocketGroupMap().remove(socketGroupId);
445
// addressPair is set in finishStart().
446
if (addressPair != null)
448
MultiplexServerInvoker.getAddressPairMap().remove(addressPair);
452
socketGroupInfo = null; // Prevent from occurring a second time in Finalizer thread.
461
protected InetSocketAddress getBindSocketAddress()
463
return bindSocketAddress;
470
protected InetSocketAddress getConnectSocketAddress()
472
return connectSocketAddress;
477
* Each implementation of the remote client invoker should have
478
* a default data type that is uses in the case it is not specified
479
* in the invoker locator uri.
483
protected String getDefaultDataType()
485
return SerializableMarshaller.DATATYPE;
489
protected Socket createSocket(String address, int port, int timeout) throws IOException
491
log.debug("MultiplexClientInvoker.createSocket()");
495
timeout = getTimeout();
500
// If connection has been broken, try to connect to new server.
501
if (socketGroupInfo != null && socketGroupInfo.getPrimingSocket() != null)
503
VirtualSocket primingSocket = socketGroupInfo.getPrimingSocket();
504
if (!primingSocket.isFunctional() || primingSocket.hasReceivedDisconnectMessage())
506
log.info("Current server is inaccessible. Will try to connect to new server");
507
primingSocket.close();
509
// Get new priming socket.
510
if (bindSocketAddress != null)
512
InetAddress bindAddress = bindSocketAddress.getAddress();
513
int bindPort = PortUtil.findFreePort(bindSocketAddress.getHostName());
514
socketGroupInfo.setBindPort(bindPort);
515
bindSocketAddress = new InetSocketAddress(bindAddress, bindPort);
516
MultiplexServerInvoker.createPrimingSocket(socketGroupInfo,
517
connectHost, connectPort,
518
bindAddress, bindPort,
519
configuration, timeout);
522
MultiplexServerInvoker.createPrimingSocket(socketGroupInfo,
523
connectHost, connectPort,
524
configuration, port);
526
MultiplexServerInvoker serverInvoker = socketGroupInfo.getServerInvoker();
527
if (serverInvoker != null)
531
// Restart callback server invoker with new server socket.
532
serverInvoker.stop();
533
socketGroupInfo.setServerInvoker(null);
534
serverInvoker.resetLocator(bindSocketAddress.getPort());
535
serverInvoker.refreshServerSocket();
536
serverInvoker.setup();
537
serverInvoker.start();
541
log.error(e.getMessage(), e);
545
VirtualSocket socket = new VirtualSocket(configuration);
546
for (int i = 0; i < 3; i++)
550
socket.connect(connectSocketAddress, bindSocketAddress, timeout);
559
catch (InterruptedException e1)
567
VirtualSocket socket = new VirtualSocket(configuration);
568
socket.connect(connectSocketAddress, bindSocketAddress, timeout);
b'\\ No newline at end of file'