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;
26
import org.jboss.logging.Logger;
27
import org.jboss.remoting.serialization.ClassLoaderUtility;
28
import org.jboss.remoting.transport.ClientFactory;
29
import org.jboss.remoting.transport.ClientInvoker;
30
import org.jboss.remoting.transport.ServerFactory;
31
import org.jboss.remoting.transport.local.LocalClientInvoker;
32
import org.jboss.remoting.util.SecurityUtility;
34
import java.lang.reflect.InvocationTargetException;
35
import java.lang.reflect.Method;
36
import java.security.AccessController;
37
import java.security.PrivilegedActionException;
38
import java.security.PrivilegedExceptionAction;
39
import java.util.ArrayList;
40
import java.util.Collection;
41
import java.util.HashMap;
42
import java.util.HashSet;
43
import java.util.Iterator;
44
import java.util.List;
49
* InvokerRegistry is a simple registery for creating client and server side Invoker implementations,
50
* getting information about the invokers and register as a invoker creator for one or more specific
53
* @author <a href="mailto:jhaynie@vocalocity.net">Jeff Haynie</a>
54
* @author <a href="mailto:telrod@e2technologies.net">Tom Elrod</a>
55
* @version $Revision: 4994 $
57
public class InvokerRegistry
59
private static final Logger log = Logger.getLogger(InvokerRegistry.class);
61
private static boolean trace = log.isTraceEnabled();
63
private static final Map clientLocators = new HashMap();
64
private static final Map serverLocators = new HashMap();
66
private static final Set registeredLocators = new HashSet();
67
private static final Object serverLock = new Object();
68
private static final Object clientLock = new Object();
70
private static final Map transportClientFactoryClasses = new HashMap();
71
private static final Map transportServerFactoryClasses = new HashMap();
74
* return an array of InvokerLocators that are local to this VM (server invokers)
76
public static final InvokerLocator[] getRegisteredServerLocators()
78
synchronized (serverLock)
80
return (InvokerLocator[]) registeredLocators.toArray(new InvokerLocator[registeredLocators.size()]);
85
* return a suitable local server invoker that can service the remote invoker locator based on
86
* a compatible transport
90
public static InvokerLocator getSuitableServerLocatorForRemote(InvokerLocator remote)
92
synchronized (serverLock)
94
Iterator iter = registeredLocators.iterator();
97
InvokerLocator l = (InvokerLocator) iter.next();
98
if(l.getProtocol().equals(remote.getProtocol()))
100
// we found a valid transport match
109
* return an array of String of the registered transports
111
public static final String[] getRegisteredInvokerTransports()
113
synchronized(clientLock)
115
Set set = transportClientFactoryClasses.keySet();
116
String transports[] = new String[set.size()];
117
return (String[]) set.toArray(transports);
122
* return an array of ClientInvokers that are connected
124
public static final ClientInvoker[] getClientInvokers()
126
synchronized(clientLock)
128
if(clientLocators.isEmpty())
130
return new ClientInvoker[0];
132
List clientInvokerList = new ArrayList();
133
Collection collection = clientLocators.values();
134
Iterator itr = collection.iterator();
137
List holderList = (List)itr.next();
138
if(holderList != null)
140
for(int x = 0; x < holderList.size(); x++)
142
ClientInvokerHolder holder = (ClientInvokerHolder)holderList.get(x);
143
clientInvokerList.add(holder.getClientInvoker());
148
return (ClientInvoker[]) clientInvokerList.toArray(new ClientInvoker[clientInvokerList.size()]);
153
* return an array of ServerInvokers that are connected
155
public static final ServerInvoker[] getServerInvokers()
157
synchronized(serverLock)
159
if(serverLocators.isEmpty())
161
return new ServerInvoker[0];
163
Collection collection = serverLocators.values();
164
return (ServerInvoker[]) collection.toArray(new ServerInvoker[collection.size()]);
169
* register a client/server invoker factory Class pair for a given transport
172
* @param clientFactory implementation of org.jboss.remoting.transport.ClientFactory
173
* @param serverFactory implementation of org.jboss.remoting.transport.ServerFactory
175
public static void registerInvokerFactories(String transport, Class clientFactory, Class serverFactory)
177
synchronized (clientLock)
179
transportClientFactoryClasses.put(transport, clientFactory);
181
synchronized (serverLock)
183
transportServerFactoryClasses.put(transport, serverFactory);
188
* unregister a client/server invoker factory pair for the given transport
192
public static void unregisterInvokerFactories(String transport)
194
synchronized (clientLock)
196
transportClientFactoryClasses.remove(transport);
198
synchronized (serverLock)
200
transportServerFactoryClasses.remove(transport);
204
public static void unregisterLocator(InvokerLocator locator)
206
synchronized (serverLock)
208
serverLocators.remove(locator);
209
registeredLocators.remove(locator);
214
* returns true if the client invoker is registered in the local JVM for a given locator
218
public static boolean isClientInvokerRegistered(InvokerLocator locator)
220
synchronized(clientLock)
222
return clientLocators.containsKey(locator);
227
* Called to destroy any cached RemoteClientInvoker copies inside the registry. This method
228
* must be called when it is determined that a remote server (via the locator) is no
231
public static void destroyClientInvoker(InvokerLocator locator, Map configuration)
233
synchronized(clientLock)
237
log.trace("destroying client invoker " + locator + ", config " + configuration);
240
ClientInvoker invoker = decrementClientInvokerCounter(locator, configuration);
246
log.trace("disconnecting " + invoker);
248
invoker.disconnect();
255
* create a ClientInvoker instance, using the specific InvokerLocator, which is just a client-side
256
* invoker to a remote server. Will use the default configuration values for the transport.
262
public static ClientInvoker createClientInvoker(InvokerLocator locator)
265
return createClientInvoker(locator, null);
269
* create a ClientInvoker instance, using the specific InvokerLocator, which is just a client-side
270
* invoker to a remote server
276
public static ClientInvoker createClientInvoker(InvokerLocator locator, Map configuration)
281
throw new NullPointerException("locator cannot be null");
283
synchronized(clientLock)
285
ClientInvoker invoker = getRegisteredClientInvoker(locator, configuration);
288
if(trace) { log.trace("Found and returning cached client invoker (" + invoker + ")"); }
292
boolean isForceRemote = false;
293
boolean isPassByValue = false;
294
Map parameters = locator.getParameters();
295
if(parameters != null)
297
String value = (String) parameters.get(InvokerLocator.BYVALUE);
298
if(value != null && Boolean.valueOf(value).booleanValue())
300
isPassByValue = true;
302
value = (String) parameters.get(InvokerLocator.FORCE_REMOTE);
303
if(value != null && Boolean.valueOf(value).booleanValue())
305
isForceRemote = true;
308
// configuration map will override locator params
309
if(configuration != null)
311
String value = (String) configuration.get(InvokerLocator.BYVALUE);
312
if(value != null && Boolean.valueOf(value).booleanValue())
314
isPassByValue = true;
316
value = (String) configuration.get(InvokerLocator.FORCE_REMOTE);
317
if(value != null && Boolean.valueOf(value).booleanValue())
319
isForceRemote = true;
323
// Check to see if server invoker is local
324
// If in server locators map, then created locally by this class
325
ServerInvoker svrInvoker = null;
328
synchronized (serverLock)
330
svrInvoker = (ServerInvoker) serverLocators.get(locator);
332
if(svrInvoker != null)
334
LocalClientInvoker localInvoker = new LocalClientInvoker(locator, configuration, isPassByValue);
335
// have to set reference to local server invoker so client in invoke directly
336
localInvoker.setServerInvoker(svrInvoker);
337
invoker = localInvoker;
338
InvokerLocator l = invoker.getLocator();
340
addRegisteredClientInvoker(invoker, l, configuration);
344
if (svrInvoker == null) //not local
346
String protocol = locator.getProtocol();
349
throw new NullPointerException("protocol cannot be null for the locator");
352
invoker = loadClientInvoker(protocol, locator, configuration);
354
InvokerLocator l = invoker.getLocator();
356
addRegisteredClientInvoker(invoker, l, configuration);
362
private static void addRegisteredClientInvoker(ClientInvoker invoker, InvokerLocator locator, Map configuration)
364
ClientInvokerHolder holder = new ClientInvokerHolder(invoker, configuration);
365
List holderList = (List) clientLocators.get(locator);
366
if (holderList != null)
368
if(holderList.contains(holder))
370
throw new RuntimeException("Registering new ClientInvoker (" + invoker + "), but it already exists.");
374
holderList.add(holder);
379
holderList = new ArrayList();
380
holderList.add(holder);
381
clientLocators.put(locator, holderList);
384
incrementClientInvokerCounter(holder);
389
* This will check the internal client invoker registry to see if there is a client invoker for
390
* the specified locator that also has the same config map entries. Will return it if found, null otherwise.
391
* Note, this will also increment the internal reference count for the invoker
393
* @param configuration
395
private static ClientInvoker getRegisteredClientInvoker(InvokerLocator locator, Map configuration)
397
ClientInvoker invoker = null;
399
List holderList = (List) clientLocators.get(locator);
400
if (holderList != null)
402
for (int x = 0; x < holderList.size(); x++)
404
ClientInvokerHolder holder = (ClientInvokerHolder) holderList.get(x);
405
if (sameInvoker(holder, configuration))
407
incrementClientInvokerCounter(holder);
408
invoker = holder.getClientInvoker();
417
private static boolean sameInvoker(ClientInvokerHolder holder, Map configuration)
419
boolean isSame = false;
421
if(holder != null && holder.getClientInvoker() != null)
423
Map config = holder.getConfig();
424
if(config == null && configuration == null)
428
else if(config != null && configuration != null)
430
isSame = config.equals(configuration);
437
private static void incrementClientInvokerCounter(ClientInvokerHolder holder)
439
holder.incrementCount();
442
private static ClientInvoker loadClientInvoker(String protocol, InvokerLocator locator, Map configuration) throws Exception
444
ClientInvoker clientInvoker = null;
446
Class transportFactoryClass = getTransportClientFactory(protocol);
447
if(transportFactoryClass != null)
449
ClientFactory transportFactory = (ClientFactory)transportFactoryClass.newInstance();
450
Method getClientInvokerMethod = getMethod(transportFactoryClass,
451
"createClientInvoker",
452
new Class[] {InvokerLocator.class, Map.class});
453
clientInvoker = (ClientInvoker)getClientInvokerMethod.invoke(transportFactory, new Object[] {locator, configuration});
457
throw new ClassNotFoundException("Could not find class " + transportFactoryClass);
460
return clientInvoker;
463
private static ServerInvoker loadServerInvoker(String protocol, InvokerLocator locator, Map configuration) throws Exception
465
ServerInvoker serverInvoker = null;
467
Class transportFactoryClass = getTransportServerFactory(protocol);
468
if(transportFactoryClass != null)
470
ServerFactory transportFactory = (ServerFactory)transportFactoryClass.newInstance();
471
Method getServerInvokerMethod = getMethod(transportFactoryClass,
472
"createServerInvoker",
473
new Class[] {InvokerLocator.class, Map.class});
474
serverInvoker = (ServerInvoker)getServerInvokerMethod.invoke(transportFactory, new Object[] {locator, configuration});
478
throw new ClassNotFoundException("Could not find class " + transportFactoryClass);
481
return serverInvoker;
484
private static Class getTransportClientFactory(String protocol)
485
throws ClassNotFoundException
487
Class transportFactoryClass = (Class)transportClientFactoryClasses.get(protocol);
488
if(transportFactoryClass == null)
490
String transportFactoryClassName = "org.jboss.remoting.transport." + protocol + ".TransportClientFactory";
491
transportFactoryClass = ClassLoaderUtility.loadClass(InvokerRegistry.class, transportFactoryClassName);
492
transportClientFactoryClasses.put(protocol, transportFactoryClass);
494
return transportFactoryClass;
497
private static Class getTransportServerFactory(String protocol)
498
throws ClassNotFoundException
500
Class transportFactoryClass = (Class)transportServerFactoryClasses.get(protocol);
501
if(transportFactoryClass == null)
503
String transportFactoryClassName = "org.jboss.remoting.transport." + protocol + ".TransportServerFactory";
504
transportFactoryClass = ClassLoaderUtility.loadClass(transportFactoryClassName, InvokerRegistry.class);
505
transportServerFactoryClasses.put(protocol, transportFactoryClass);
507
return transportFactoryClass;
511
* returns true if the server invoker is registered in the local JVM for a given locator/handler pair
515
public static boolean isServerInvokerRegistered(InvokerLocator locator)
517
synchronized(serverLock)
519
return serverLocators.containsKey(locator);
524
* create a ServerInvoker instance, using the specific Invoker locator data and an implementation of the
525
* ServerInvocationHandler interface. Will use the default configuration values for the transport.
531
public static ServerInvoker createServerInvoker(InvokerLocator locator)
534
return createServerInvoker(locator, null);
538
* create a ServerInvoker instance, using the specific Invoker locator data and an implementation of the
539
* ServerInvocationHandler interface along with
545
public static ServerInvoker createServerInvoker(InvokerLocator locator, Map configuration)
549
ServerInvoker invoker = null;
550
synchronized(serverLock)
552
invoker = (ServerInvoker) serverLocators.get(locator);
555
throw new InvalidConfigurationException("The invoker for locator (" + locator + ") is already " +
556
"in use by another Connector. Either change the locator or " +
557
"add new handlers to existing Connector.");
559
String protocol = locator.getProtocol();
561
invoker = loadServerInvoker(protocol, locator, configuration);
563
serverLocators.put(locator, invoker);
564
registeredLocators.add(invoker.getLocator());
569
public static void destroyServerInvoker(ServerInvoker invoker)
573
InvokerLocator locator = invoker.getLocator();
574
unregisterLocator(locator);
578
private static ClientInvoker decrementClientInvokerCounter(InvokerLocator locator, Map configuration)
580
List holderList = (List)clientLocators.get(locator);
582
if (holderList == null)
584
log.debug("Could not decrement client invoker counter for locator " + locator +
585
" as does not exist in invoker registry.");
589
ClientInvokerHolder holder = null;
591
// now look for specific invoker by configuration map
592
for(int x = 0; x < holderList.size(); x++)
594
holder = (ClientInvokerHolder)holderList.get(x);
597
Map config = holder.getConfig();
598
if(config == null && configuration == null)
602
else if(config != null && configuration != null)
604
if(config.equals(configuration))
614
log.debug("Could not decrement client invoker counter for locator " + locator +
615
"as does not exist in invoker registry with matching configuraion map.");
619
ClientInvoker clientInvoker = null;
620
holder.decrementCount();
622
if(holder.getCount() == 0)
624
clientInvoker = holder.getClientInvoker();
625
holderList.remove(holder);
626
if(holderList.isEmpty())
628
clientLocators.remove(locator);
631
log.debug("removed " + clientInvoker + " from registry");
635
log.debug("decremented " + holder.getClientInvoker() +
636
"'s count, current count " + holder.getCount());
639
return clientInvoker;
643
* This is needed by the ServerInvoker since it may change the port being used (if port specified was <= 0) to
644
* next available port.
649
public static void updateServerInvokerLocator(InvokerLocator locator, InvokerLocator newLocator)
651
synchronized (serverLock)
653
Object si = serverLocators.get(locator);
654
serverLocators.remove(locator);
655
registeredLocators.remove(locator);
656
serverLocators.put(newLocator, si);
657
registeredLocators.add(newLocator);
662
* Indicates if a specific transport protocol type (e.g. socket, sslsocket, rmi, https)
663
* supports ssl. Note: almost all transports are able to support ssl if socket/serversocket
664
* factory is set with an ssl version, so this is really just a hint from the invoker implementation.
670
public static boolean isSSLSupported(String transport) throws Exception
672
boolean isSSLSupported = false;
673
Class transportFactoryClass = null;
676
synchronized (clientLock)
678
transportFactoryClass = getTransportClientFactory(transport);
680
ClientFactory clientFactory = (ClientFactory)transportFactoryClass.newInstance();
681
Method meth = getMethod(transportFactoryClass, "supportsSSL", new Class[]{});
682
Boolean boolVal = (Boolean)meth.invoke(clientFactory, null);
683
isSSLSupported = boolVal.booleanValue();
685
catch (ClassNotFoundException e)
687
Exception ex = new Exception("Can not verify transport (" + transport + ") supports SSL because can not find invoker implementation matching transport.");
691
catch (NoSuchMethodException e)
693
Exception ex = new Exception("Can not call supportsSSL method on client factory class (" + transportFactoryClass + ") as there is no such method.");
697
catch (IllegalAccessException e)
699
Exception ex = new Exception("Can not call create instance of client factory class (" + transportFactoryClass + ").");
703
catch (InvocationTargetException e)
705
Exception ex = new Exception("Can not call supportsSSL method on client factory class (" + transportFactoryClass + ").");
709
catch (InstantiationException e)
711
Exception ex = new Exception("Can not call supportsSSL method on client factory class (" + transportFactoryClass + ").");
716
return isSSLSupported;
719
public String toString()
721
return "InvokerRegistry[" + Integer.toHexString(hashCode()) + "]";
724
private static class ClientInvokerHolder
726
private ClientInvoker invoker = null;
727
private Map config = null;
728
private int counter = 0;
730
public ClientInvokerHolder(ClientInvoker invoker, Map config)
732
this.invoker = invoker;
733
this.config = config;
736
public void incrementCount()
741
public void decrementCount()
746
throw new RuntimeException("ClientInvokerHolder decremented to negative number for client invoker " + invoker);
750
public int getCount()
755
public ClientInvoker getClientInvoker()
760
public Map getConfig()
765
public boolean equals(Object o)
767
boolean isEqual = false;
769
if(o instanceof ClientInvokerHolder)
771
ClientInvokerHolder h = (ClientInvokerHolder)o;
772
if(invoker.equals(h.getClientInvoker()))
774
Map configuration = h.getConfig();
775
if(config == null && configuration == null)
779
else if(config != null && configuration != null)
781
isEqual = config.equals(configuration);
790
static private Method getMethod(final Class c, final String name, final Class[] parameterTypes)
791
throws NoSuchMethodException
793
if (SecurityUtility.skipAccessControl())
795
return c.getMethod(name, parameterTypes);
800
return (Method) AccessController.doPrivileged( new PrivilegedExceptionAction()
802
public Object run() throws NoSuchMethodException
804
return c.getMethod(name, parameterTypes);
808
catch (PrivilegedActionException e)
810
throw (NoSuchMethodException) e.getCause();