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.rmi;
25
import java.io.IOException;
26
import java.io.Serializable;
27
import java.net.InetAddress;
28
import java.net.Socket;
29
import java.net.UnknownHostException;
30
import java.rmi.server.RMIClientSocketFactory;
31
import java.security.AccessController;
32
import java.security.PrivilegedActionException;
33
import java.security.PrivilegedExceptionAction;
34
import java.util.Collections;
35
import java.util.HashMap;
38
import javax.net.SocketFactory;
40
import org.jboss.logging.Logger;
41
import org.jboss.remoting.AbstractInvoker;
42
import org.jboss.remoting.InvokerLocator;
43
import org.jboss.remoting.Remoting;
44
import org.jboss.remoting.Version;
45
import org.jboss.remoting.util.SecurityUtility;
49
* <code>RemotingRMIClientSocketFactory</code> provides two services to <code>RMIServerInvoker</code>.
51
* <li>It can be parameterized by a host name, allowing <code>RMIServerInvoker</code> to supply RMI
52
* with a factory which creates sockets connected to a specified host name.
54
* <li>It can be parameterized by a <code>SocketFactory</code> allowing <code>RMIServerInvoker</code>
55
* to supply RMI with a factory facility which creates specialized sockets.
58
* if the <code>SocketFactory</code> parameter is specified, then the <code>RemotingRMIClientSocketFactory</code>
59
* should be used with a matching instance of <code>RemotingRMIServerSocketFactory</code> with a compatible
60
* <code>ServerSocketFactory</code>.
62
* If the <code>SocketFactory</code> parameter is not specified, an instance of <code>java.net.Socket</code>
63
* will be created by default.
65
* Although there is no apparent need for the host name parameter, since the <code>createSocket()</code>
66
* method receives a host name, it seems that for a server object bound to localhost, the RMI runtime will
67
* pass to <code>createSocket()</code> one of the IP addresses for which the host is configured (other than
68
* 127.0.0.1), resulting in a failure to retrieve the object from the Registry. If a host name is passed to
69
* a <code>RemotingRMIClientFactory</code> constructor, it will override the host name passed to
70
* <code>createSocket()</code> In particular, parameterizing <code>RemotingRMIClientSocketFactory</code>
71
* with localhost will allow the retrieval of objects bound to localhost.
73
* @author <a href="mailto:r.sigal@computer.org">Ron Sigal</a>
74
* @version $Revision: 5017 $
80
public class RemotingRMIClientSocketFactory implements RMIClientSocketFactory, Serializable
82
static final long serialVersionUID;
84
protected static Logger log = Logger.getLogger(RemotingRMIClientSocketFactory.class);
85
protected static Map configMaps = Collections.synchronizedMap(new HashMap());
86
protected static Map socketFactories = Collections.synchronizedMap(new HashMap());
88
protected Map configuration;
89
protected InvokerLocator invokerLocator;
91
transient protected SocketFactory socketFactory;
92
private int timeout = 60000;
94
// The commented code below is from an attempt to incorporate a <code>java.lang.reflect.Constructor</code>
95
// parameter to provide a very general way to create sockets. The problem is that
96
// <code>Constructor</code> does not implement <code>Serializable</code>, which is necessary to
97
// allow the <code>RemotingRMIClientSocketFactory</code> to be transmitted to the client. The
98
// code is left in place because it could be resurrected by passing in a class name and parameter
99
// types to specify a constructor. Fortunately, <code>java.lang.Class</code> does implement
100
// <code>Serializable</code>.
102
// private Constructor constructor;
103
// private Object[] args;
104
// private int hostPosition;
105
// private int portPosition;
107
protected String hostName;
111
if(Version.getDefaultVersion() == Version.VERSION_1)
113
serialVersionUID = -7491556589517716155L;
117
serialVersionUID = -3039839695840773968L;
122
public static void addLocalConfiguration(InvokerLocator invokerLocator, Map localConfig)
124
log.debug("adding local configuration for: " + invokerLocator);
125
configMaps.put(new ComparableHolder(invokerLocator), localConfig);
129
public static void removeLocalConfiguration(InvokerLocator invokerLocator)
131
log.debug("removing local configuration for: " + invokerLocator);
132
Object o = configMaps.remove(new ComparableHolder(invokerLocator));
133
if (o == null) log.warn("trying to delete unknown key: " + invokerLocator);
134
ComparableHolder holder = new ComparableHolder(invokerLocator);
135
socketFactories.remove(holder);
145
public RemotingRMIClientSocketFactory(InvokerLocator locator,
150
this.invokerLocator = locator;
151
this.hostName = hostName;
152
this.timeout = timeout;
153
this.configuration = new HashMap(config);
157
// public RemotingRMISocketFactory(Constructor constructor, Object[] args, int hostPosition, int portPosition)
158
// throws ClassNotFoundException, NoSuchMethodException
160
// this.constructor = constructor;
162
// this.portPosition = portPosition;
167
* Creates a new socket. If a <code>SocketFactory</code> was passed to the constructor, it will be used.
168
* Otherwise, a <code>java.net.Socket</code> will be created by default.
170
* @param host host to which socket should be connected
171
* @param port port to which socket should be connected
173
* @throws IOException if there is a problem creating a socket
175
public Socket createSocket(String host, final int port) throws IOException
177
// If invokerLocator isn't in configMaps, an RMICLientInvoker has not been created
178
// yet. This call was probably made by an RMI thread, and is premature. Best attempt
179
// is to return a vanilla socket.
181
final String effectiveHost = hostName != null ? hostName : host;
182
if (log.isTraceEnabled())
183
log.trace("host: " + host + ", effective host: " + effectiveHost + ", port: " + port);
185
if (invokerLocator != null)
187
ComparableHolder holder = new ComparableHolder(invokerLocator);
188
if (!configMaps.containsKey(holder))
190
if (Thread.currentThread().getName().indexOf("RMI") >= 0)
192
log.debug("unrecognized invoker locator: " + invokerLocator);
193
log.debug("unable to retrieve socket factory: returning plain socket");
197
log.warn(Thread.currentThread().getName() + " unrecognized invoker locator: " + invokerLocator);
198
log.warn("unable to retrieve socket factory: returning plain socket");
201
return createSocketPrivate(effectiveHost, port);
204
socketFactory = retrieveSocketFactory(holder);
207
Socket socket = null;
208
if(socketFactory != null)
210
socket = createSocketPrivate(socketFactory, effectiveHost, port);
214
socket = createSocketPrivate(effectiveHost, port);
217
socket.setSoTimeout(timeout);
218
socketFactory = null;
223
public SocketFactory retrieveSocketFactory(ComparableHolder holder)
226
SocketFactory sf = (SocketFactory) socketFactories.get(holder);
229
// We want to keep the local configuration map, which might contain a
230
// SocketFactory, separate from the configuration map, which is meant
231
// to contain only serializable objects.
232
Map tempConfig = new HashMap(configuration);
233
Map localConfig = (Map) configMaps.get(holder);
234
if (localConfig != null)
235
tempConfig.putAll(localConfig);
237
if (tempConfig.containsKey(Remoting.CUSTOM_SOCKET_FACTORY))
239
sf = (SocketFactory) tempConfig.get(Remoting.CUSTOM_SOCKET_FACTORY);
244
sf = SocketFactory.getDefault();
245
sf = AbstractInvoker.wrapSocketFactory(sf, tempConfig);
248
socketFactories.put(holder, sf);
257
configuration = null;
258
invokerLocator = null;
259
socketFactory = null;
263
protected static class ComparableHolder
265
private String protocol;
266
private InetAddress host;
268
private int hashCode;
270
public ComparableHolder(final InvokerLocator invokerLocator)
272
protocol = invokerLocator.getProtocol().toLowerCase();
276
host = getAddressByName(invokerLocator.getHost());
278
catch (UnknownHostException e)
280
log.error("unable to resolve host: " + invokerLocator.getHost(), e);
283
port = invokerLocator.getPort();
284
hashCode = protocol.hashCode() * host.hashCode() * port;
287
public boolean equals(Object obj)
289
if (obj == null || !(obj instanceof ComparableHolder))
292
ComparableHolder holder = (ComparableHolder) obj;
294
return protocol.equals(holder.protocol.toLowerCase())
295
&& host.equals(holder.host)
296
&& port == holder.port;
299
public int hashCode()
305
static private Socket createSocketPrivate(final String host, final int port) throws IOException
307
if (SecurityUtility.skipAccessControl())
309
return new Socket(host, port);
314
return (Socket)AccessController.doPrivileged( new PrivilegedExceptionAction()
316
public Object run() throws IOException
318
return new Socket(host, port);
322
catch (PrivilegedActionException e)
324
throw (IOException) e.getCause();
328
static private Socket createSocketPrivate(final SocketFactory sf, final String host, final int port)
331
if (SecurityUtility.skipAccessControl())
333
return sf.createSocket(host, port);
338
return (Socket)AccessController.doPrivileged( new PrivilegedExceptionAction()
340
public Object run() throws IOException
342
return sf.createSocket(host, port);
346
catch (PrivilegedActionException e)
348
throw (IOException) e.getCause();
352
static private InetAddress getAddressByName(final String host) throws UnknownHostException
354
if (SecurityUtility.skipAccessControl())
356
return InetAddress.getByName(host);
361
return (InetAddress)AccessController.doPrivileged( new PrivilegedExceptionAction()
363
public Object run() throws IOException
365
return InetAddress.getByName(host);
369
catch (PrivilegedActionException e)
371
throw (UnknownHostException) e.getCause();
b'\\ No newline at end of file'