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;
25
import org.jboss.logging.Logger;
26
import org.jboss.remoting.serialization.ClassLoaderUtility;
27
import org.jboss.remoting.transport.ClientFactory;
28
import org.jboss.remoting.transport.ClientInvoker;
29
import org.jboss.remoting.transport.ServerFactory;
30
import org.jboss.remoting.transport.local.LocalClientInvoker;
31
import org.jboss.remoting.util.SecurityUtility;
33
import java.lang.reflect.InvocationTargetException;
34
import java.lang.reflect.Method;
35
import java.security.AccessController;
36
import java.security.PrivilegedActionException;
37
import java.security.PrivilegedExceptionAction;
38
import java.util.ArrayList;
39
import java.util.Collection;
40
import java.util.HashMap;
41
import java.util.HashSet;
42
import java.util.Iterator;
43
import java.util.List;
48
* InvokerRegistry is a simple registery for creating client and server side Invoker implementations,
49
* getting information about the invokers and register as a invoker creator for one or more specific
52
* @author <a href="mailto:jhaynie@vocalocity.net">Jeff Haynie</a>
53
* @author <a href="mailto:telrod@e2technologies.net">Tom Elrod</a>
54
* @version $Revision: 5886 $
56
public class InvokerRegistry
58
private static final Logger log = Logger.getLogger(InvokerRegistry.class);
60
private static boolean trace = log.isTraceEnabled();
62
private static final Map clientLocators = new HashMap();
63
private static final Map serverLocators = new HashMap();
65
private static final Set registeredLocators = new HashSet();
66
private static final Object serverLock = new Object();
67
private static final Object clientLock = new Object();
69
private static final Map transportClientFactoryClasses = new HashMap();
70
private static final Map transportServerFactoryClasses = new HashMap();
72
private static final RuntimePermission INVOKER_REGISTRY_UPDATE_PERMISSION = new RuntimePermission("invokerRegistryUpdate");
75
* return an array of InvokerLocators that are local to this VM (server invokers)
77
public static final InvokerLocator[] getRegisteredServerLocators()
79
synchronized (serverLock)
81
return (InvokerLocator[]) registeredLocators.toArray(new InvokerLocator[registeredLocators.size()]);
86
* return a suitable local server invoker that can service the remote invoker locator based on
87
* a compatible transport
91
public static InvokerLocator getSuitableServerLocatorForRemote(InvokerLocator remote)
93
synchronized (serverLock)
95
Iterator iter = registeredLocators.iterator();
98
InvokerLocator l = (InvokerLocator) iter.next();
99
if(l.getProtocol().equals(remote.getProtocol()))
101
// we found a valid transport match
110
* return an array of String of the registered transports
112
public static final String[] getRegisteredInvokerTransports()
114
synchronized(clientLock)
116
Set set = transportClientFactoryClasses.keySet();
117
String transports[] = new String[set.size()];
118
return (String[]) set.toArray(transports);
123
* return an array of ClientInvokers that are connected
125
public static final ClientInvoker[] getClientInvokers()
127
synchronized(clientLock)
129
if(clientLocators.isEmpty())
131
return new ClientInvoker[0];
133
List clientInvokerList = new ArrayList();
134
Collection collection = clientLocators.values();
135
Iterator itr = collection.iterator();
138
List holderList = (List)itr.next();
139
if(holderList != null)
141
for(int x = 0; x < holderList.size(); x++)
143
ClientInvokerHolder holder = (ClientInvokerHolder)holderList.get(x);
144
clientInvokerList.add(holder.getClientInvoker());
149
return (ClientInvoker[]) clientInvokerList.toArray(new ClientInvoker[clientInvokerList.size()]);
154
* return an array of ServerInvokers that are connected
156
public static final ServerInvoker[] getServerInvokers()
158
synchronized(serverLock)
160
if(serverLocators.isEmpty())
162
return new ServerInvoker[0];
164
Collection collection = serverLocators.values();
165
return (ServerInvoker[]) collection.toArray(new ServerInvoker[collection.size()]);
170
* register a client/server invoker factory Class pair for a given transport
173
* @param clientFactory implementation of org.jboss.remoting.transport.ClientFactory
174
* @param serverFactory implementation of org.jboss.remoting.transport.ServerFactory
176
public static void registerInvokerFactories(String transport, Class clientFactory, Class serverFactory)
179
synchronized (clientLock)
181
transportClientFactoryClasses.put(transport, clientFactory);
183
synchronized (serverLock)
185
transportServerFactoryClasses.put(transport, serverFactory);
190
* unregister a client/server invoker factory pair for the given transport
194
public static void unregisterInvokerFactories(String transport)
197
synchronized (clientLock)
199
transportClientFactoryClasses.remove(transport);
201
synchronized (serverLock)
203
transportServerFactoryClasses.remove(transport);
207
public static void unregisterLocator(InvokerLocator locator)
210
synchronized (serverLock)
212
serverLocators.remove(locator);
213
registeredLocators.remove(locator);
218
* returns true if the client invoker is registered in the local JVM for a given locator
222
public static boolean isClientInvokerRegistered(InvokerLocator locator)
224
synchronized(clientLock)
226
return clientLocators.containsKey(locator);
231
* Called to destroy any cached RemoteClientInvoker copies inside the registry. This method
232
* must be called when it is determined that a remote server (via the locator) is no
235
public static void destroyClientInvoker(InvokerLocator locator, Map configuration)
238
synchronized(clientLock)
242
log.trace("destroying client invoker " + locator + ", config " + configuration);
245
ClientInvoker invoker = decrementClientInvokerCounter(locator, configuration);
251
log.trace("disconnecting " + invoker);
253
invoker.disconnect();
260
* create a ClientInvoker instance, using the specific InvokerLocator, which is just a client-side
261
* invoker to a remote server. Will use the default configuration values for the transport.
267
public static ClientInvoker createClientInvoker(InvokerLocator locator)
270
return createClientInvoker(locator, null);
274
* create a ClientInvoker instance, using the specific InvokerLocator, which is just a client-side
275
* invoker to a remote server
281
public static ClientInvoker createClientInvoker(InvokerLocator locator, Map configuration)
288
throw new NullPointerException("locator cannot be null");
290
synchronized(clientLock)
292
ClientInvoker invoker = getRegisteredClientInvoker(locator, configuration);
295
if(trace) { log.trace("Found and returning cached client invoker (" + invoker + ")"); }
299
boolean isForceRemote = false;
300
boolean isPassByValue = false;
301
Map parameters = locator.getParameters();
302
if(parameters != null)
304
String value = (String) parameters.get(InvokerLocator.BYVALUE);
305
if(value != null && Boolean.valueOf(value).booleanValue())
307
isPassByValue = true;
309
value = (String) parameters.get(InvokerLocator.FORCE_REMOTE);
310
if(value != null && Boolean.valueOf(value).booleanValue())
312
isForceRemote = true;
315
// configuration map will override locator params
316
if(configuration != null)
318
String value = (String) configuration.get(InvokerLocator.BYVALUE);
319
if(value != null && Boolean.valueOf(value).booleanValue())
321
isPassByValue = true;
323
value = (String) configuration.get(InvokerLocator.FORCE_REMOTE);
324
if(value != null && Boolean.valueOf(value).booleanValue())
326
isForceRemote = true;
330
// Check to see if server invoker is local
331
// If in server locators map, then created locally by this class
332
ServerInvoker svrInvoker = null;
335
synchronized (serverLock)
337
svrInvoker = (ServerInvoker) serverLocators.get(locator);
339
if(svrInvoker != null)
341
LocalClientInvoker localInvoker = new LocalClientInvoker(locator, configuration, isPassByValue);
342
// have to set reference to local server invoker so client in invoke directly
343
localInvoker.setServerInvoker(svrInvoker);
344
invoker = localInvoker;
345
InvokerLocator l = invoker.getLocator();
347
addRegisteredClientInvoker(invoker, l, configuration);
351
if (svrInvoker == null) //not local
353
String protocol = locator.getProtocol();
356
throw new NullPointerException("protocol cannot be null for the locator");
359
invoker = loadClientInvoker(protocol, locator, configuration);
361
InvokerLocator l = invoker.getLocator();
363
addRegisteredClientInvoker(invoker, l, configuration);
369
private static void addRegisteredClientInvoker(ClientInvoker invoker, InvokerLocator locator, Map configuration)
371
ClientInvokerHolder holder = new ClientInvokerHolder(invoker, configuration);
372
List holderList = (List) clientLocators.get(locator);
373
if (holderList != null)
375
if(holderList.contains(holder))
377
throw new RuntimeException("Registering new ClientInvoker (" + invoker + "), but it already exists.");
381
holderList.add(holder);
386
holderList = new ArrayList();
387
holderList.add(holder);
388
clientLocators.put(locator, holderList);
391
incrementClientInvokerCounter(holder);
396
* This will check the internal client invoker registry to see if there is a client invoker for
397
* the specified locator that also has the same config map entries. Will return it if found, null otherwise.
398
* Note, this will also increment the internal reference count for the invoker
400
* @param configuration
402
private static ClientInvoker getRegisteredClientInvoker(InvokerLocator locator, Map configuration)
404
ClientInvoker invoker = null;
406
List holderList = (List) clientLocators.get(locator);
407
if (holderList != null)
409
for (int x = 0; x < holderList.size(); x++)
411
ClientInvokerHolder holder = (ClientInvokerHolder) holderList.get(x);
412
if (sameInvoker(holder, configuration))
414
incrementClientInvokerCounter(holder);
415
invoker = holder.getClientInvoker();
424
private static boolean sameInvoker(ClientInvokerHolder holder, Map configuration)
426
boolean isSame = false;
428
if(holder != null && holder.getClientInvoker() != null)
430
Map config = holder.getConfig();
431
if(config == null && configuration == null)
435
else if(config != null && configuration != null)
437
isSame = config.equals(configuration);
444
private static void incrementClientInvokerCounter(ClientInvokerHolder holder)
446
holder.incrementCount();
449
private static ClientInvoker loadClientInvoker(String protocol, InvokerLocator locator, Map configuration) throws Exception
451
ClientInvoker clientInvoker = null;
453
Class transportFactoryClass = getTransportClientFactory(protocol);
454
if(transportFactoryClass != null)
456
ClientFactory transportFactory = (ClientFactory)transportFactoryClass.newInstance();
457
Method getClientInvokerMethod = getMethod(transportFactoryClass,
458
"createClientInvoker",
459
new Class[] {InvokerLocator.class, Map.class});
460
clientInvoker = (ClientInvoker)getClientInvokerMethod.invoke(transportFactory, new Object[] {locator, configuration});
464
throw new ClassNotFoundException("Could not find class " + transportFactoryClass);
467
return clientInvoker;
470
private static ServerInvoker loadServerInvoker(String protocol, InvokerLocator locator, Map configuration) throws Exception
472
ServerInvoker serverInvoker = null;
474
Class transportFactoryClass = getTransportServerFactory(protocol);
475
if(transportFactoryClass != null)
477
ServerFactory transportFactory = (ServerFactory)transportFactoryClass.newInstance();
478
Method getServerInvokerMethod = getMethod(transportFactoryClass,
479
"createServerInvoker",
480
new Class[] {InvokerLocator.class, Map.class});
481
serverInvoker = (ServerInvoker)getServerInvokerMethod.invoke(transportFactory, new Object[] {locator, configuration});
485
throw new ClassNotFoundException("Could not find class " + transportFactoryClass);
488
return serverInvoker;
491
private static Class getTransportClientFactory(String protocol)
492
throws ClassNotFoundException
494
Class transportFactoryClass = (Class)transportClientFactoryClasses.get(protocol);
495
if(transportFactoryClass == null)
497
String transportFactoryClassName = "org.jboss.remoting.transport." + protocol + ".TransportClientFactory";
498
transportFactoryClass = ClassLoaderUtility.loadClass(InvokerRegistry.class, transportFactoryClassName);
499
transportClientFactoryClasses.put(protocol, transportFactoryClass);
501
return transportFactoryClass;
504
private static Class getTransportServerFactory(String protocol)
505
throws ClassNotFoundException
507
Class transportFactoryClass = (Class)transportServerFactoryClasses.get(protocol);
508
if(transportFactoryClass == null)
510
String transportFactoryClassName = "org.jboss.remoting.transport." + protocol + ".TransportServerFactory";
511
transportFactoryClass = ClassLoaderUtility.loadClass(transportFactoryClassName, InvokerRegistry.class);
512
transportServerFactoryClasses.put(protocol, transportFactoryClass);
514
return transportFactoryClass;
518
* returns true if the server invoker is registered in the local JVM for a given locator/handler pair
522
public static boolean isServerInvokerRegistered(InvokerLocator locator)
524
synchronized(serverLock)
526
return serverLocators.containsKey(locator);
531
* create a ServerInvoker instance, using the specific Invoker locator data and an implementation of the
532
* ServerInvocationHandler interface. Will use the default configuration values for the transport.
538
public static ServerInvoker createServerInvoker(InvokerLocator locator)
541
return createServerInvoker(locator, null);
545
* create a ServerInvoker instance, using the specific Invoker locator data and an implementation of the
546
* ServerInvocationHandler interface along with
552
public static ServerInvoker createServerInvoker(InvokerLocator locator, Map configuration)
556
ServerInvoker invoker = null;
557
synchronized(serverLock)
559
invoker = (ServerInvoker) serverLocators.get(locator);
562
throw new InvalidConfigurationException("The invoker for locator (" + locator + ") is already " +
563
"in use by another Connector. Either change the locator or " +
564
"add new handlers to existing Connector.");
566
String protocol = locator.getProtocol();
568
invoker = loadServerInvoker(protocol, locator, configuration);
570
serverLocators.put(locator, invoker);
571
registeredLocators.add(invoker.getLocator());
576
public static void destroyServerInvoker(ServerInvoker invoker)
581
InvokerLocator locator = invoker.getLocator();
582
unregisterLocator(locator);
586
private static ClientInvoker decrementClientInvokerCounter(InvokerLocator locator, Map configuration)
588
List holderList = (List)clientLocators.get(locator);
590
if (holderList == null)
592
log.debug("Could not decrement client invoker counter for locator " + locator +
593
" as does not exist in invoker registry.");
597
ClientInvokerHolder holder = null;
599
// now look for specific invoker by configuration map
600
for(int x = 0; x < holderList.size(); x++)
602
holder = (ClientInvokerHolder)holderList.get(x);
605
Map config = holder.getConfig();
606
if(config == null && configuration == null)
610
else if(config != null && configuration != null)
612
if(config.equals(configuration))
622
log.debug("Could not decrement client invoker counter for locator " + locator +
623
"as does not exist in invoker registry with matching configuraion map.");
627
ClientInvoker clientInvoker = null;
628
holder.decrementCount();
630
if(holder.getCount() == 0)
632
clientInvoker = holder.getClientInvoker();
633
holderList.remove(holder);
634
if(holderList.isEmpty())
636
clientLocators.remove(locator);
639
log.debug("removed " + clientInvoker + " from registry");
643
log.debug("decremented " + holder.getClientInvoker() +
644
"'s count, current count " + holder.getCount());
647
return clientInvoker;
651
* This is needed by the ServerInvoker since it may change the port being used (if port specified was <= 0) to
652
* next available port.
657
public static void updateServerInvokerLocator(InvokerLocator locator, InvokerLocator newLocator)
660
synchronized (serverLock)
662
Object si = serverLocators.get(locator);
663
serverLocators.remove(locator);
664
registeredLocators.remove(locator);
665
serverLocators.put(newLocator, si);
666
registeredLocators.add(newLocator);
671
* Indicates if a specific transport protocol type (e.g. socket, sslsocket, rmi, https)
672
* supports ssl. Note: almost all transports are able to support ssl if socket/serversocket
673
* factory is set with an ssl version, so this is really just a hint from the invoker implementation.
679
public static boolean isSSLSupported(String transport) throws Exception
682
boolean isSSLSupported = false;
683
Class transportFactoryClass = null;
686
synchronized (clientLock)
688
transportFactoryClass = getTransportClientFactory(transport);
690
ClientFactory clientFactory = (ClientFactory)transportFactoryClass.newInstance();
691
Method meth = getMethod(transportFactoryClass, "supportsSSL", new Class[]{});
692
Boolean boolVal = (Boolean)meth.invoke(clientFactory, null);
693
isSSLSupported = boolVal.booleanValue();
695
catch (ClassNotFoundException e)
697
Exception ex = new Exception("Can not verify transport (" + transport + ") supports SSL because can not find invoker implementation matching transport.");
701
catch (NoSuchMethodException e)
703
Exception ex = new Exception("Can not call supportsSSL method on client factory class (" + transportFactoryClass + ") as there is no such method.");
707
catch (IllegalAccessException e)
709
Exception ex = new Exception("Can not call create instance of client factory class (" + transportFactoryClass + ").");
713
catch (InvocationTargetException e)
715
Exception ex = new Exception("Can not call supportsSSL method on client factory class (" + transportFactoryClass + ").");
719
catch (InstantiationException e)
721
Exception ex = new Exception("Can not call supportsSSL method on client factory class (" + transportFactoryClass + ").");
726
return isSSLSupported;
729
public String toString()
731
return "InvokerRegistry[" + Integer.toHexString(hashCode()) + "]";
734
private static class ClientInvokerHolder
736
private ClientInvoker invoker = null;
737
private Map config = null;
738
private int counter = 0;
740
public ClientInvokerHolder(ClientInvoker invoker, Map config)
742
this.invoker = invoker;
743
this.config = config;
746
public void incrementCount()
751
public void decrementCount()
756
throw new RuntimeException("ClientInvokerHolder decremented to negative number for client invoker " + invoker);
760
public int getCount()
765
public ClientInvoker getClientInvoker()
770
public Map getConfig()
775
public boolean equals(Object o)
777
boolean isEqual = false;
779
if(o instanceof ClientInvokerHolder)
781
ClientInvokerHolder h = (ClientInvokerHolder)o;
782
if(invoker.equals(h.getClientInvoker()))
784
Map configuration = h.getConfig();
785
if(config == null && configuration == null)
789
else if(config != null && configuration != null)
791
isEqual = config.equals(configuration);
800
static private Method getMethod(final Class c, final String name, final Class[] parameterTypes)
801
throws NoSuchMethodException
803
if (SecurityUtility.skipAccessControl())
805
return c.getMethod(name, parameterTypes);
810
return (Method) AccessController.doPrivileged( new PrivilegedExceptionAction()
812
public Object run() throws NoSuchMethodException
814
return c.getMethod(name, parameterTypes);
818
catch (PrivilegedActionException e)
820
throw (NoSuchMethodException) e.getCause();
824
static private void doSecurityCheck()
826
// If there is no Security Manager, the issue is moot.
827
final SecurityManager sm = System.getSecurityManager();
833
// If the calling code is not verifiably in Remoting, then require it to have InvokerRegistryUpdatePermission.
834
sm.checkPermission(INVOKER_REGISTRY_UPDATE_PERMISSION);