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 org.jboss.remoting.Home;
26
import org.jboss.remoting.InvocationRequest;
27
import org.jboss.remoting.InvokerLocator;
28
import org.jboss.remoting.Remoting;
29
import org.jboss.remoting.ServerInvoker;
30
import org.jboss.remoting.marshal.MarshalFactory;
31
import org.jboss.remoting.marshal.Marshaller;
32
import org.jboss.remoting.marshal.MarshallerDecorator;
33
import org.jboss.remoting.marshal.UnMarshaller;
34
import org.jboss.remoting.marshal.UnMarshallerDecorator;
35
import org.jboss.remoting.marshal.VersionedMarshaller;
36
import org.jboss.remoting.marshal.VersionedUnMarshaller;
37
import org.jboss.remoting.marshal.rmi.RMIMarshaller;
38
import org.jboss.remoting.marshal.rmi.RMIUnMarshaller;
39
import org.jboss.remoting.marshal.serializable.SerializableMarshaller;
40
import org.jboss.remoting.serialization.SerializationManager;
41
import org.jboss.remoting.serialization.SerializationStreamFactory;
42
import org.jboss.remoting.util.SecurityUtility;
43
import org.jboss.serial.io.JBossObjectOutputStream;
44
import org.jboss.util.propertyeditor.PropertyEditors;
45
import org.jboss.logging.Logger;
47
import javax.net.SocketFactory;
49
import java.beans.IntrospectionException;
50
import java.io.ByteArrayInputStream;
51
import java.io.ByteArrayOutputStream;
52
import java.io.IOException;
53
import java.io.ObjectOutputStream;
54
import java.net.InetAddress;
55
import java.net.UnknownHostException;
56
import java.rmi.AccessException;
57
import java.rmi.NotBoundException;
58
import java.rmi.Remote;
59
import java.rmi.RemoteException;
60
import java.rmi.registry.LocateRegistry;
61
import java.rmi.registry.Registry;
62
import java.rmi.server.ExportException;
63
import java.rmi.server.RMIClientSocketFactory;
64
import java.rmi.server.RMIServerSocketFactory;
65
import java.rmi.server.RemoteServer;
66
import java.rmi.server.ServerNotActiveException;
67
import java.rmi.server.UnicastRemoteObject;
68
import java.security.AccessController;
69
import java.security.PrivilegedAction;
70
import java.security.PrivilegedActionException;
71
import java.security.PrivilegedExceptionAction;
72
import java.util.HashMap;
73
import java.util.HashSet;
74
import java.util.Iterator;
75
import java.util.List;
77
import java.util.Properties;
83
* @author <a href="mailto:jhaynie@vocalocity.net">Jeff Haynie</a>
84
* @author <a href="mailto:tom.elrod@jboss.com">Tom Elrod</a>
85
* @version $Revision: 5255 $
87
public class RMIServerInvoker extends ServerInvoker implements RMIServerInvokerInf, Cloneable
89
public static String RMI_ONEWAY_MARSHALLING = "rmiOnewayMarshalling";
91
private static final Logger log = Logger.getLogger(RMIServerInvoker.class);
93
protected boolean isPrimaryServer = true;
94
protected Set secondaryServers = new HashSet();
95
protected boolean rmiOnewayMarshalling;
98
private RemotingRMIClientSocketFactory csf;
102
* Default for how many connections are queued. Value is 200.
104
public static final int BACKLOG_DEFAULT = 200;
107
* Default port on which rmi registry will be started. Value is 3455.
109
public static final int DEFAULT_REGISTRY_PORT = 3455;
112
* Key for port on which rmi registry should be started on.
114
public static final String REGISTRY_PORT_KEY = "registryPort";
116
private Marshaller marshaller = null;
117
private UnMarshaller unmarshaller = null;
119
public RMIServerInvoker(InvokerLocator locator)
124
public void start() throws IOException
130
List connectHomes = getConnectHomes();
131
List homes = getHomes();
133
if (connectHomes.size() != homes.size())
134
throw new IOException("number of connect homes and bind homes must match in RMI transport");
136
Home bindHome = (Home) homes.get(0);
137
Home connectHome = (Home) connectHomes.get(0);
138
initRMI(bindHome, connectHome);
140
for (int i = 1; i < homes.size(); i++)
142
bindHome = (Home) homes.get(i);
143
connectHome = (Home) connectHomes.get(i);
144
RMIServerInvoker copy = copy();
145
secondaryServers.add(copy);
146
copy.initRMI(bindHome, connectHome);
151
protected void setup() throws Exception
153
Properties props = new Properties();
154
props.putAll(getConfiguration());
155
mapJavaBeanProperties(RMIServerInvoker.this, props, false);
159
protected RMIServerInvoker copy() throws IOException
166
catch (CloneNotSupportedException e)
168
log.error("This should not happen", e);
171
RMIServerInvoker server = (RMIServerInvoker) o;
172
server.locator = locator;
173
server.locator = new InvokerLocator(locator.getLocatorURI());
174
server.locator.setHomeInUse(locator.getHomeInUse());
175
server.isPrimaryServer = false;
180
protected void initRMI(Home bindHome, Home connectHome) throws IOException
182
Registry registry = null;
185
registry = getRegistry();
189
throw new IOException(e.getMessage());
192
String bindHost = bindHome.host;
193
int bindPort = bindHome.port;
194
String clientConnectHost = connectHome.host;
196
if(clientConnectHost == null)
198
clientConnectHost = bindHost;
201
locator.setHomeInUse(bindHome);
202
RMIServerSocketFactory ssf = new RemotingRMIServerSocketFactory(getServerSocketFactory(), BACKLOG_DEFAULT, bindHost, getTimeout());
203
csf = getRMIClientSocketFactory(clientConnectHost);
204
stub = exportObject(this, bindPort, csf, ssf);
206
log.debug("Binding server to \"remoting/RMIServerInvoker/" + bindPort + "\" in registry");
207
rebind(registry, "remoting/RMIServerInvoker/" + bindPort, this);
208
ClassLoader classLoader = getClassLoader(RMIServerInvoker.class);
209
Map map = passConfigMapToMarshalFactory ? configuration : null;
210
unmarshaller = MarshalFactory.getUnMarshaller(getLocator(), classLoader, map);
211
marshaller = MarshalFactory.getMarshaller(getLocator(), classLoader, map);
215
protected RemotingRMIClientSocketFactory getRMIClientSocketFactory(String clientConnectHost)
217
// Remove server side socket creation listeners.
218
HashMap remoteConfig = new HashMap(configuration);
219
remoteConfig.remove(Remoting.CUSTOM_SERVER_SOCKET_FACTORY);
220
remoteConfig.remove(Remoting.SOCKET_CREATION_CLIENT_LISTENER);
221
remoteConfig.remove(Remoting.SOCKET_CREATION_SERVER_LISTENER);
222
return new RemotingRMIClientSocketFactory(locator, clientConnectHost, getTimeout(), remoteConfig);
225
protected SocketFactory getDefaultSocketFactory()
227
// return SocketFactory.getDefault();
229
* Returning null because by default, this socket factory
230
* will be need to be serialized when exported. Since the
231
* default factory implementation returned from SocketFactory.getDefault()
232
* is not serializable, it will not work. Therefore, if return null,
233
* will delay the creation of the socket factory until the RMIClientSocketFactory is
240
public RMIServerInvoker(InvokerLocator locator, Map configuration)
242
super(locator, configuration);
245
private Registry getRegistry() throws Exception
247
Registry registry = null;
249
int port = DEFAULT_REGISTRY_PORT;
251
// See if locator contains a specific registry port
252
Map params = getConfiguration();
255
String value = (String) params.get(REGISTRY_PORT_KEY);
260
port = Integer.parseInt(value);
261
log.debug("Using port " + port + " for rmi registry.");
263
catch(NumberFormatException e)
265
throw new Exception("Can not set the RMIServerInvoker RMI registry to port " + value + ". This is not a valid port number.");
272
log.debug("Creating registry for " + port);
274
registry = createRegistry(port);
276
catch(ExportException exportEx)
278
log.debug("Locating registry for " + port);
280
// Probably means that the registry already exists, so just get it.
281
registry = getRegistry(port);
283
if(log.isTraceEnabled())
285
log.trace("Got registry: " + registry);
290
protected String getDefaultDataType()
292
return SerializableMarshaller.DATATYPE;
296
* destroy the RMI Server Invoker, which will unexport the RMI server
298
public void destroy()
305
log.debug("locator: " + locator + ", home: " + locator.getHomeInUse());
306
log.debug(this + " primary: " + isPrimaryServer + " unbinding " + "remoting/RMIServerInvoker/" + locator.getPort() + " from registry");
307
Registry registry = getRegistry();
308
unbind(registry, "remoting/RMIServerInvoker/" + locator.getPort());
309
log.debug("unbound " + "remoting/RMIServerInvoker/" + locator.getPort() + " from registry");
313
if ("Finalizer".equalsIgnoreCase(Thread.currentThread().getName()))
314
log.debug("thread: " + Thread.currentThread().getName() + " Error unbinding RMIServerInvoker from RMI registry.", e);
316
log.error("thread: " + Thread.currentThread().getName() + " Error unbinding RMIServerInvoker from RMI registry.", e);
319
UnicastRemoteObject.unexportObject(this, true);
322
catch(java.rmi.NoSuchObjectException e)
332
Iterator it = secondaryServers.iterator();
335
RMIServerInvoker server = (RMIServerInvoker) it.next();
342
protected void finalize() throws Throwable
349
* returns true if the transport is bi-directional in nature, for example,
350
* SOAP in unidirectional and SOCKETs are bi-directional (unless behind a firewall
353
public boolean isTransportBiDirectional()
358
public final Remote getStub()
363
public Object transport(Object invocation)
364
throws RemoteException, IOException
367
Object payload = invocation;
368
if(unmarshaller != null && !(unmarshaller instanceof RMIUnMarshaller))
370
if(unmarshaller instanceof UnMarshallerDecorator)
372
payload = ((UnMarshallerDecorator) unmarshaller).removeDecoration(payload);
376
ByteArrayInputStream is = null;
377
if (rmiOnewayMarshalling)
379
// Legacy treatment, pre 2.4.0
380
ByteArrayOutputStream baos = new ByteArrayOutputStream();
381
SerializationManager manager = SerializationStreamFactory.getManagerInstance(getSerializationType());
382
ObjectOutputStream oos = manager.createOutput(baos);
383
writeObject(oos, payload);
386
is = new ByteArrayInputStream(baos.toByteArray());
390
is = new ByteArrayInputStream((byte[]) payload);
395
if (unmarshaller instanceof VersionedUnMarshaller)
397
payload = ((VersionedUnMarshaller) unmarshaller).read(is, null, getVersion());
402
payload = unmarshaller.read(is, null);
406
catch(ClassNotFoundException e)
408
log.debug("Could not unmarshall invocation request" + payload, e);
409
throw new IOException(e.getMessage());
414
if (payload instanceof InvocationRequest)
416
InvocationRequest ir = (InvocationRequest) payload;
417
Map metadata = ir.getRequestPayload();
418
if (metadata == null)
420
metadata = new HashMap();
421
ir.setRequestPayload(metadata);
425
String clientHost = RemoteServer.getClientHost();
426
InetAddress clientAddress = getAddressByName(clientHost);
427
metadata.put(Remoting.CLIENT_ADDRESS, clientAddress);
429
catch (ServerNotActiveException e)
431
throw new RemoteException(e.getMessage());
434
Object response = invoke(payload);
436
if(marshaller != null && !(marshaller instanceof RMIMarshaller) && !rmiOnewayMarshalling)
438
if(marshaller instanceof MarshallerDecorator)
440
response = ((MarshallerDecorator) marshaller).addDecoration(response);
444
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
445
if (marshaller instanceof VersionedMarshaller)
446
((VersionedMarshaller) marshaller).write(response, byteOut, getVersion());
448
marshaller.write(response, byteOut);
451
response = byteOut.toByteArray();
457
public boolean isRmiOnewayMarshalling()
459
return rmiOnewayMarshalling;
462
public void setRmiOnewayMarshalling(boolean rmiOnewayMarshalling)
464
this.rmiOnewayMarshalling = rmiOnewayMarshalling;
467
static private ClassLoader getClassLoader(final Class c)
469
if (SecurityUtility.skipAccessControl())
471
return c.getClassLoader();
474
return (ClassLoader)AccessController.doPrivileged( new PrivilegedAction()
478
return c.getClassLoader();
483
static private void mapJavaBeanProperties(final Object o, final Properties props, final boolean isStrict)
484
throws IntrospectionException
486
if (SecurityUtility.skipAccessControl())
488
PropertyEditors.mapJavaBeanProperties(o, props, isStrict);
494
AccessController.doPrivileged( new PrivilegedExceptionAction()
496
public Object run() throws IntrospectionException
498
PropertyEditors.mapJavaBeanProperties(o, props, isStrict);
503
catch (PrivilegedActionException e)
505
throw (IntrospectionException) e.getCause();
509
static private void writeObject(final ObjectOutputStream oos, final Object o)
512
if (SecurityUtility.skipAccessControl() || !(oos instanceof JBossObjectOutputStream))
520
AccessController.doPrivileged( new PrivilegedExceptionAction()
522
public Object run() throws IOException
529
catch (PrivilegedActionException e)
531
Throwable cause = e.getCause();
532
if (cause instanceof IOException)
533
throw (IOException) cause;
535
throw (RuntimeException) cause;
539
static private InetAddress getAddressByName(final String host) throws UnknownHostException
541
if (SecurityUtility.skipAccessControl())
543
return InetAddress.getByName(host);
548
return (InetAddress)AccessController.doPrivileged( new PrivilegedExceptionAction()
550
public Object run() throws IOException
552
return InetAddress.getByName(host);
556
catch (PrivilegedActionException e)
558
throw (UnknownHostException) e.getCause();
562
static private Registry createRegistry(final int port) throws RemoteException
564
if (SecurityUtility.skipAccessControl())
566
return LocateRegistry.createRegistry(port);
571
return (Registry) AccessController.doPrivileged( new PrivilegedExceptionAction()
573
public Object run() throws RemoteException
575
return LocateRegistry.createRegistry(port);
579
catch (PrivilegedActionException e)
581
throw (RemoteException) e.getCause();
585
static private Remote exportObject(final Remote object,
587
final RMIClientSocketFactory csf,
588
final RMIServerSocketFactory ssf)
589
throws RemoteException
591
if (SecurityUtility.skipAccessControl())
593
return UnicastRemoteObject.exportObject(object, port, csf, ssf);
598
return (Remote) AccessController.doPrivileged( new PrivilegedExceptionAction()
600
public Object run() throws RemoteException
602
return UnicastRemoteObject.exportObject(object, port, csf, ssf);
606
catch (PrivilegedActionException e)
608
throw (RemoteException) e.getCause();
612
static private Registry getRegistry(final int port) throws RemoteException
614
if (SecurityUtility.skipAccessControl())
616
return LocateRegistry.getRegistry(port);
621
return (Registry) AccessController.doPrivileged( new PrivilegedExceptionAction()
623
public Object run() throws RemoteException
625
return LocateRegistry.getRegistry(port);
629
catch (PrivilegedActionException e)
631
throw (RemoteException) e.getCause();
635
static private void rebind(final Registry registry, final String name, final Remote object)
638
if (SecurityUtility.skipAccessControl())
640
registry.rebind(name, object);
646
AccessController.doPrivileged( new PrivilegedExceptionAction()
648
public Object run() throws IOException
650
registry.rebind(name, object);
655
catch (PrivilegedActionException e)
657
throw (IOException) e.getCause();
661
static private void unbind(final Registry registry, final String name)
662
throws AccessException, RemoteException, NotBoundException
664
if (SecurityUtility.skipAccessControl())
666
registry.unbind(name);
672
AccessController.doPrivileged( new PrivilegedExceptionAction()
674
public Object run() throws AccessException, RemoteException, NotBoundException
676
registry.unbind(name);
681
catch (PrivilegedActionException e)
683
Throwable cause = e.getCause();
684
if (cause instanceof AccessException)
685
throw (AccessException) cause;
686
else if (cause instanceof RemoteException)
687
throw (RemoteException) cause;
689
throw (NotBoundException) cause;