~ubuntu-branches/ubuntu/raring/libjboss-remoting-java/raring

« back to all changes in this revision

Viewing changes to src/main/org/jboss/remoting/InvokerLocator.java

  • Committer: Package Import Robot
  • Author(s): Torsten Werner
  • Date: 2011-09-09 14:01:03 UTC
  • mto: This revision was merged to the branch mainline in revision 9.
  • Revision ID: package-import@ubuntu.com-20110909140103-o8ucrolqt5g25k57
Tags: upstream-2.5.3.SP1
ImportĀ upstreamĀ versionĀ 2.5.3.SP1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
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.
 
6
*
 
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.
 
11
*
 
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.
 
16
*
 
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.
 
21
*/
 
22
 
 
23
package org.jboss.remoting;
 
24
 
 
25
import java.io.Serializable;
 
26
import java.net.InetAddress;
 
27
import java.net.MalformedURLException;
 
28
import java.net.URI;
 
29
import java.net.URISyntaxException;
 
30
import java.net.UnknownHostException;
 
31
import java.security.AccessController;
 
32
import java.security.PrivilegedActionException;
 
33
import java.security.PrivilegedExceptionAction;
 
34
import java.util.ArrayList;
 
35
import java.util.Collection;
 
36
import java.util.Iterator;
 
37
import java.util.List;
 
38
import java.util.Map;
 
39
import java.util.StringTokenizer;
 
40
import java.util.TreeMap;
 
41
 
 
42
import org.jboss.logging.Logger;
 
43
import org.jboss.remoting.serialization.SerializationStreamFactory;
 
44
import org.jboss.remoting.transport.ClientInvoker;
 
45
import org.jboss.remoting.util.SecurityUtility;
 
46
 
 
47
/**
 
48
 * InvokerLocator is an object that indentifies a specific Invoker on the network, via a unique
 
49
 * locator URI. The locator URI is in the format: <P>
 
50
 * <p/>
 
51
 * <tt>protocol://host[:port][/path[?param=value&param2=value2]]</tt>     <P>
 
52
 * <p/>
 
53
 * For example, a http based locator might be: <P>
 
54
 * <p/>
 
55
 * <tt>http://192.168.10.1:8081</tt>  <P>
 
56
 * <p/>
 
57
 * An example Socket based locator might be: <P>
 
58
 * <p/>
 
59
 * <tt>socket://192.168.10.1:9999</tt>  <P>
 
60
 * <p/>
 
61
 * An example RMI based locator might be: <P>
 
62
 * <p/>
 
63
 * <tt>rmi://localhost</tt>  <P>
 
64
 * <p/>
 
65
 * NOTE: If no hostname is given (e.g., "socket://:5555"), then the hostname will
 
66
 * automatically be resolved to the outside IP address of the local machine.  
 
67
 * If the given hostname is 0.0.0.0 and the system
 
68
 * property "jboss.bind.address" is set, then the hostname will be replaced by the value
 
69
 * associated with 'jboss.bind.address".
 
70
 *
 
71
 * @author <a href="mailto:jhaynie@vocalocity.net">Jeff Haynie</a>
 
72
 * @author <a href="mailto:telrod@e2technologies.net">Tom Elrod</a>
 
73
 * @version $Revision: 5918 $
 
74
 */
 
75
public class InvokerLocator implements Serializable
 
76
{
 
77
   static final long serialVersionUID;
 
78
   protected static Logger log = Logger.getLogger(InvokerLocator.class); 
 
79
   protected static Boolean legacyParsingFlag;
 
80
 
 
81
   protected String protocol;
 
82
   protected String host;
 
83
   protected ArrayList connectHomes = new ArrayList();
 
84
   protected ArrayList homes = new ArrayList();
 
85
   protected int port;
 
86
   protected String path;
 
87
   protected String query;
 
88
   protected Map parameters;
 
89
   private String uri;
 
90
   private String originalURL;
 
91
   private Home homeInUse;
 
92
 
 
93
 
 
94
   static
 
95
   {
 
96
      if(Version.getDefaultVersion() == Version.VERSION_1)
 
97
      {
 
98
         serialVersionUID = -2909329895029296248L;
 
99
      }
 
100
      else
 
101
      {
 
102
         serialVersionUID = -4977622166779282521L;
 
103
      }
 
104
   }
 
105
   
 
106
   public static boolean getUseLegacyParsing()
 
107
   {
 
108
      if (legacyParsingFlag == null)
 
109
         return false;
 
110
      return legacyParsingFlag.booleanValue();
 
111
   }
 
112
   
 
113
   public static void setUseLegacyParsing(boolean flag)
 
114
   {
 
115
      legacyParsingFlag = new Boolean(flag);
 
116
   }
 
117
 
 
118
   /**
 
119
    * Indicates should address binding to all network interfaces (i.e. 0.0.0.0)
 
120
    */
 
121
   public static final String ANY = "0.0.0.0";
 
122
   /**
 
123
    * Constant value for server bind address system property.  Value is 'jboss.bind.address'.
 
124
    */
 
125
   private static final String SERVER_BIND_ADDRESS = "jboss.bind.address";
 
126
 
 
127
   /**
 
128
    * Public key to use when want to specify that locator look up local address by
 
129
    * IP or host name.
 
130
    */
 
131
   public static final String BIND_BY_HOST = "remoting.bind_by_host";
 
132
 
 
133
 
 
134
   /**
 
135
    * Constant to define the param name to be used when defining the data type.
 
136
    */
 
137
   public static final String DATATYPE = "datatype";
 
138
   public static final String DATATYPE_CASED = "dataType";
 
139
 
 
140
   /**
 
141
    * Constant to define the param name to be used when defining the serialization type.
 
142
    */
 
143
   public static final String SERIALIZATIONTYPE = "serializationtype";
 
144
   public static final String SERIALIZATIONTYPE_CASED = "serializationType";
 
145
 
 
146
   /**
 
147
    * Constant to define the param name to be used when defining the marshaller fully qualified classname
 
148
    */
 
149
   public static final String MARSHALLER = "marshaller";
 
150
   /**
 
151
    * Constant to define the param name to be used when defining the unmarshaller fully qualified classname
 
152
    */
 
153
   public static final String UNMARSHALLER = "unmarshaller";
 
154
 
 
155
   /**
 
156
    * Constant to define what port the marshalling loader port resides on.
 
157
    */
 
158
   public static final String LOADER_PORT = "loaderport";
 
159
 
 
160
   /**
 
161
    * Constant to define the param name to be used when defining if marshalling should be by value,
 
162
    * which means will be using local client invoker with cloning of payload value.
 
163
    */
 
164
   public static final String BYVALUE = "byvalue";
 
165
 
 
166
   /**
 
167
    * Constant to define the param name to be used when defining if marshalling should use
 
168
    * remote client invoker instead of using local client invoker (even though both client and
 
169
    * server invokers are within same JVM).
 
170
    */
 
171
   public static final String FORCE_REMOTE = "force_remote";   
 
172
 
 
173
   /**
 
174
    * Constant to define if client should try to automatically establish a
 
175
    * lease with the server.  Value for this parameter key should be either 'true' or 'false'.
 
176
    */
 
177
   public static final String CLIENT_LEASE = "leasing";
 
178
 
 
179
   /**
 
180
    * Constant to define what the client lease period should be in the case that
 
181
    * server side leasing is turned on.  Value for this parameter key should be the number
 
182
    * of milliseconds to wait before each client lease renewal and must be greater than zero
 
183
    * in order to be recognized.
 
184
    */
 
185
   public static final String CLIENT_LEASE_PERIOD = "lease_period";
 
186
 
 
187
   
 
188
   /**
 
189
    * Constant to define if InvokerLocator should use the old (ad hoc) parsing
 
190
    * algorithm instead of the new, URI based, parsing algorithm.
 
191
    */
 
192
   public static final String LEGACY_PARSING = "legacyParsing";
 
193
   
 
194
   /**
 
195
    * Serves as placeholder in host position when multiple hosts are given in the
 
196
    * query part by way of the parameter "hosts".  E.g.
 
197
    * <p>
 
198
    * socket://multihome:8888/?hosts=host1.jboss.org:host2.jboss.org
 
199
    */
 
200
   public static final String MULTIHOME = "multihome";
 
201
   
 
202
   /**
 
203
    * Parameter key used for specifying multiple homes to connect to.  E.g.
 
204
    * <p>
 
205
    * socket://multihome/?connecthomes=host1.jboss.org:7777!host2.jboss.org:8888
 
206
    */
 
207
   public static final String CONNECT_HOMES_KEY = "connecthomes";
 
208
   
 
209
   /**
 
210
    * Parameter key used for specifying multiple binding homes.  E.g.
 
211
    * <p>
 
212
    * socket://multihome/?homes=a.org:66!b.org:77&homes=c.org:88!d.org:99
 
213
    */
 
214
   public static final String HOMES_KEY = "homes";
 
215
   
 
216
   /**
 
217
    * Parameter key used for specifying default connecting port for
 
218
    * multihome InvokerLocator.
 
219
    */
 
220
   public static final String DEFAULT_CONNECT_PORT = "defaultConnectPort";
 
221
   
 
222
   /**
 
223
    * Parameter key used for specifying default server bind port for
 
224
    * multihme InvokerLocator.
 
225
    */
 
226
   public static final String DEFAULT_PORT = "defaultPort";
 
227
   
 
228
   /**
 
229
    * Constant to determine if warning about null host should be logged.
 
230
    */
 
231
   public static final String SUPPRESS_HOST_WARNING = "suppressHostWarning";
 
232
   
 
233
   /**
 
234
    * InvokerLocator leaves address 0.0.0.0 unchanged.  Once serverBindAddress has been
 
235
    * extracted from the InvokerLocator, it is necessary to transform 0.0.0.0 into an
 
236
    * address that contacted over the network.  See JBREM-687.
 
237
    */
 
238
   public static InvokerLocator validateLocator(InvokerLocator locator) throws MalformedURLException
 
239
   {
 
240
      InvokerLocator externalLocator = locator;
 
241
 
 
242
      String host = locator.getHost();
 
243
      String newHost = null;
 
244
      if(host == null || InvokerLocator.ANY.equals(host))
 
245
      {
 
246
         // now need to get some external bindable address
 
247
         try
 
248
         {
 
249
            newHost = (String)AccessController.doPrivileged( new PrivilegedExceptionAction()
 
250
            {
 
251
               public Object run() throws Exception
 
252
               {
 
253
                  String bindByHost = System.getProperty(InvokerLocator.BIND_BY_HOST, "True");
 
254
                  boolean byHost = Boolean.valueOf(bindByHost).booleanValue();
 
255
                  if(byHost)
 
256
                  {
 
257
                     return getLocalHost().getHostName();
 
258
                  }
 
259
                  else
 
260
                  {
 
261
                     return getLocalHost().getHostAddress();
 
262
                  }
 
263
               }
 
264
            });
 
265
         }
 
266
         catch (PrivilegedActionException e)
 
267
         {
 
268
            log.debug("Could not get host by name or address.", e.getCause());
 
269
         }
 
270
 
 
271
         if(newHost == null)
 
272
         {
 
273
            // now what?  step through network interfaces?
 
274
            throw new RuntimeException("Can not determine bindable address for locator (" + locator + ")");
 
275
         }
 
276
         
 
277
         externalLocator = new InvokerLocator(locator.protocol, newHost, locator.port,
 
278
                                              locator.getPath(), locator.getParameters());
 
279
      }
 
280
 
 
281
      return externalLocator;
 
282
   }
 
283
   
 
284
   
 
285
   public static void extractHomes(String homeList, List list, int defaultPort)
 
286
   {
 
287
      StringTokenizer tok = new StringTokenizer(homeList, "!");  
 
288
      while(tok.hasMoreTokens())
 
289
      {
 
290
         String h = null;
 
291
         int p = -1;
 
292
         String token = tok.nextToken();
 
293
         boolean isIPv6 = token.indexOf('[') >= 0;
 
294
         int boundary;
 
295
 
 
296
         if (isIPv6)
 
297
         {
 
298
            int pos = token.indexOf(']');
 
299
            if (pos + 1 == token.length())
 
300
               boundary = -1;
 
301
            else
 
302
               boundary = token.indexOf(']') + 1;
 
303
            
 
304
         }
 
305
         else
 
306
         {
 
307
            boundary = token.lastIndexOf(':');
 
308
         }
 
309
 
 
310
         if (boundary > -1)
 
311
         {
 
312
            h = token.substring(0, boundary);
 
313
 
 
314
            try
 
315
            {
 
316
               p = Integer.valueOf(token.substring(boundary + 1)).intValue();
 
317
            }
 
318
            catch (NumberFormatException  e)
 
319
            {
 
320
               log.warn("invalid port value: " + token.substring(boundary + 1));
 
321
            }
 
322
         }
 
323
         else
 
324
         {
 
325
            h = token;
 
326
         }
 
327
 
 
328
         if (p == -1)
 
329
            p = defaultPort;
 
330
 
 
331
         list.add(new Home(h, p));
 
332
      }
 
333
   }
 
334
   
 
335
   
 
336
   public static String convertHomesListToString(List homes)
 
337
   {
 
338
      if (homes == null || homes.size() == 0)
 
339
         return "";
 
340
      
 
341
      Iterator it = homes.iterator();
 
342
      StringBuffer b = new StringBuffer(((Home) it.next()).toString());
 
343
      while (it.hasNext())
 
344
      {
 
345
         b.append("!").append(it.next());
 
346
      }
 
347
      return b.toString();
 
348
   }
 
349
   
 
350
   private static final InetAddress LOCAL_HOST;
 
351
 
 
352
   static
 
353
   {
 
354
      try
 
355
      {
 
356
         LOCAL_HOST = (InetAddress) AccessController.doPrivileged( new PrivilegedExceptionAction()
 
357
         {
 
358
            public Object run() throws UnknownHostException
 
359
            {
 
360
               try
 
361
               {
 
362
                  return InetAddress.getLocalHost();
 
363
               }
 
364
               catch (UnknownHostException e)
 
365
               {
 
366
                  return InetAddress.getByName("127.0.0.1");
 
367
               }
 
368
            }
 
369
         });
 
370
      }
 
371
      catch (PrivilegedActionException e)
 
372
      {
 
373
         log.debug(InvokerLocator.class.getName() + " unable to get local host address", e.getCause());
 
374
         throw new ExceptionInInitializerError(e.getCause());
 
375
      }
 
376
      catch (SecurityException e)
 
377
      {
 
378
         log.debug(InvokerLocator.class.getName() + " unable to get local host address", e);
 
379
         throw e;
 
380
      }
 
381
   }
 
382
   
 
383
   private static InetAddress getLocalHost() throws UnknownHostException
 
384
   {
 
385
      if (LOCAL_HOST != null)
 
386
      {
 
387
         return LOCAL_HOST;
 
388
      }
 
389
 
 
390
      try
 
391
      {
 
392
         return InetAddress.getLocalHost();
 
393
      }
 
394
      catch (UnknownHostException e)
 
395
      {
 
396
         return InetAddress.getByName("127.0.0.1");
 
397
      }
 
398
   }
 
399
   
 
400
   /**
 
401
    * Constructs the object used to identify a remoting server via simple uri format string (e.g. socket://myhost:7000).
 
402
    * Note: the uri passed may not always be the one returned via call to getLocatorURI() as may need to change if
 
403
    * port not specified, host is 0.0.0.0, etc.  If need original uri that is passed to this constructor, need to
 
404
    * call getOriginalURI().
 
405
    * @param uri
 
406
    * @throws MalformedURLException
 
407
    */
 
408
   public InvokerLocator(String uri)
 
409
         throws MalformedURLException
 
410
   {
 
411
      originalURL = uri;
 
412
      parse(originalURL);
 
413
   }
 
414
   
 
415
   
 
416
   private void parse(String uriString) throws MalformedURLException
 
417
   {
 
418
      boolean doLegacyParsing = false;
 
419
      if (legacyParsingFlag != null)
 
420
      {
 
421
         doLegacyParsing = legacyParsingFlag.booleanValue();
 
422
      }
 
423
      else 
 
424
      {
 
425
         String s = getSystemProperty(LEGACY_PARSING);
 
426
         doLegacyParsing = "true".equalsIgnoreCase(s);
 
427
      }
 
428
 
 
429
      if (doLegacyParsing)
 
430
      {
 
431
         log.warn("using deprecated legacy URL parsing routine");
 
432
         legacyParse(uriString);
 
433
      }
 
434
      else
 
435
      {
 
436
         URIParse(uriString);
 
437
      }
 
438
      
 
439
      if (query != null)
 
440
      {
 
441
         StringTokenizer tok = new StringTokenizer(query, "&");
 
442
         parameters = new TreeMap();
 
443
         while(tok.hasMoreTokens())
 
444
         {
 
445
            String token = tok.nextToken();
 
446
            int eq = token.indexOf("=");
 
447
            String name = (eq > -1) ? token.substring(0, eq) : token;
 
448
            String value = (eq > -1) ? token.substring(eq + 1) : "";
 
449
            parameters.put(name, value);
 
450
         }
 
451
      }
 
452
 
 
453
      if (!MULTIHOME.equals(host) && parameters != null)
 
454
      {
 
455
         // Use "host:port" to connect.
 
456
         String s = (String) parameters.remove(CONNECT_HOMES_KEY);
 
457
         if (s != null) log.warn("host != " + MULTIHOME + ": " + CONNECT_HOMES_KEY + " will be ignored");
 
458
      }
 
459
 
 
460
      if (parameters != null)
 
461
      {
 
462
         String homesString = (String) parameters.remove(HOMES_KEY);
 
463
         String connectHomesString = (String) parameters.remove(CONNECT_HOMES_KEY);
 
464
         createHomeLists(parameters, homesString, connectHomesString);
 
465
      }
 
466
 
 
467
//    rebuild it, since the host probably got resolved and the port changed
 
468
      rebuildLocatorURI();
 
469
      
 
470
      if (!MULTIHOME.equals(host))
 
471
      {
 
472
         homeInUse = new Home(host, port);
 
473
         connectHomes.add(homeInUse);
 
474
         if (homes.isEmpty())
 
475
            homes.add(homeInUse);
 
476
      }
 
477
   }
 
478
 
 
479
   private void URIParse(String uriString) throws MalformedURLException
 
480
   {
 
481
      try
 
482
      {
 
483
         URI uri = new URI(encodePercent(uriString));
 
484
         protocol = uri.getScheme();
 
485
         checkHost(originalURL, uri.getHost());
 
486
         host = decodePercent(resolveHost(uri.getHost()));
 
487
         port = uri.getPort();
 
488
         path = uri.getPath();
 
489
         query = decodePercent(uri.getQuery());
 
490
      }
 
491
      catch (URISyntaxException e)
 
492
      {
 
493
         throw new MalformedURLException(e.getMessage());
 
494
      }
 
495
   }
 
496
   
 
497
   private void legacyParse(String uri) throws MalformedURLException
 
498
   {
 
499
      log.warn("Legacy InvokerLocator parsing is deprecated");
 
500
      int i = uri.indexOf("://");
 
501
      if(i < 0)
 
502
      {
 
503
         throw new MalformedURLException("Invalid url " + uri);
 
504
      }
 
505
      String tmp = uri.substring(i + 3);
 
506
      this.protocol = uri.substring(0, i);
 
507
      i = tmp.indexOf("/");
 
508
      int p = tmp.indexOf(":");
 
509
      if(i != -1)
 
510
      {
 
511
         p = (p < i ? p : -1);
 
512
      }
 
513
      if(p != -1)
 
514
      {
 
515
         host = resolveHost(tmp.substring(0, p).trim());
 
516
         if(i > -1)
 
517
         {
 
518
            port = Integer.parseInt(tmp.substring(p + 1, i));
 
519
         }
 
520
         else
 
521
         {
 
522
            port = Integer.parseInt(tmp.substring(p + 1));
 
523
         }
 
524
      }
 
525
      else
 
526
      {
 
527
         if(i > -1)
 
528
         {
 
529
            host = resolveHost(tmp.substring(0, i).trim());
 
530
         }
 
531
         else
 
532
         {
 
533
            host = resolveHost(tmp.substring(0).trim());
 
534
         }
 
535
         port = -1;
 
536
      }
 
537
 
 
538
      // now look for any path
 
539
      p = tmp.indexOf("?");
 
540
      if(p != -1)
 
541
      {
 
542
         path = tmp.substring(i + 1, p);
 
543
         query = tmp.substring(p + 1);
 
544
      }
 
545
      else
 
546
      {
 
547
         p = tmp.indexOf("/");
 
548
         if(p != -1)
 
549
         {
 
550
            path = tmp.substring(p + 1);
 
551
         }
 
552
         else
 
553
         {
 
554
            path = "";
 
555
         }
 
556
         query = null;
 
557
      }
 
558
   }
 
559
 
 
560
   private static void checkHost(String uri, String host)
 
561
   {
 
562
      if (host == null && !getBoolean(SUPPRESS_HOST_WARNING))
 
563
      {
 
564
         StringBuffer sb = new StringBuffer("Host resolves to null in ");
 
565
         sb.append(uri).append(". Perhaps the host contains an invalid character.  ");
 
566
         sb.append("See http://www.ietf.org/rfc/rfc2396.txt.");
 
567
         log.warn(sb.toString());
 
568
      }
 
569
   }
 
570
   
 
571
   private static final String resolveHost(String host)
 
572
   {
 
573
      if (host == null)
 
574
      {
 
575
         host = fixRemoteAddress(host);
 
576
      }
 
577
      else if(host.indexOf("0.0.0.0") != -1)
 
578
      {
 
579
         String bindAddress = getSystemProperty(SERVER_BIND_ADDRESS, "0.0.0.0");         
 
580
         if(bindAddress.equals("0.0.0.0"))
 
581
         {
 
582
            host = fixRemoteAddress(host);
 
583
         }
 
584
         else
 
585
         {
 
586
            host = host.replaceAll("0\\.0\\.0\\.0", getSystemProperty(SERVER_BIND_ADDRESS));
 
587
         }
 
588
      }
 
589
      return host;
 
590
   }
 
591
 
 
592
   private static String fixRemoteAddress(String address)
 
593
   {
 
594
      if(address == null)
 
595
      {
 
596
         try
 
597
         {
 
598
            address = (String)AccessController.doPrivileged( new PrivilegedExceptionAction()
 
599
            {
 
600
               public Object run() throws UnknownHostException
 
601
               {
 
602
                  String bindByHost = System.getProperty(BIND_BY_HOST, "True");
 
603
                  boolean byHost = Boolean.valueOf(bindByHost).booleanValue();
 
604
 
 
605
                  if(byHost)
 
606
                  {
 
607
                     return getLocalHost().getHostName();
 
608
                  }
 
609
                  else
 
610
                  {
 
611
                     return getLocalHost().getHostAddress();
 
612
                  }
 
613
               }
 
614
            });
 
615
         }
 
616
         catch (PrivilegedActionException e)
 
617
         {
 
618
            log.debug("error", e.getCause());
 
619
         }
 
620
      }
 
621
 
 
622
      return address;
 
623
   }
 
624
  
 
625
 
 
626
   private void createHomeLists(Map parameters, String homesString, String connectHomesString)
 
627
   {
 
628
      // DEFAULT_PORT value takes precedence, followed by port value.
 
629
      int defaultPort = port; 
 
630
      String s = (String) parameters.get(DEFAULT_PORT);
 
631
      if (s != null && s != "")
 
632
      {
 
633
         try
 
634
         {
 
635
            defaultPort = Integer.parseInt(s);
 
636
         }
 
637
         catch (Exception e)
 
638
         {
 
639
            log.warn("invalid value for " + DEFAULT_PORT + ": " + s);
 
640
         }
 
641
      }
 
642
      
 
643
      if (homesString != null)
 
644
      {
 
645
         extractHomes(homesString, homes, defaultPort);
 
646
      }
 
647
      
 
648
      // DEFAULT_CONNECT_PORT value takes precedence, followed by 
 
649
      // DEFAULT_PORT value and then port value.
 
650
      s = (String) parameters.get(DEFAULT_CONNECT_PORT);
 
651
      if (s != null && s != "")
 
652
      {
 
653
         try
 
654
         {
 
655
            defaultPort = Integer.parseInt(s);
 
656
         }
 
657
         catch (Exception e)
 
658
         {
 
659
            log.warn("invalid value for " + DEFAULT_CONNECT_PORT + ": " + s);
 
660
         }
 
661
      }
 
662
 
 
663
      if (connectHomesString != null)
 
664
      {
 
665
         extractHomes(connectHomesString, connectHomes, defaultPort);
 
666
      }
 
667
   }
 
668
   
 
669
   
 
670
   /**
 
671
    * Constructs the object used to identify a remoting server.
 
672
    * @param protocol
 
673
    * @param host
 
674
    * @param port
 
675
    * @param path
 
676
    * @param parameters
 
677
    */
 
678
   public InvokerLocator(String protocol, String host, int port, String path, Map parameters)
 
679
   {
 
680
      this.protocol = protocol;
 
681
      this.host = resolveHost(host);
 
682
      this.port = port;
 
683
      this.path = path == null ? "" : path;
 
684
      this.parameters = parameters == null ? new TreeMap() : new TreeMap(parameters);
 
685
     
 
686
      if (this.parameters != null)
 
687
      {
 
688
         String homesString = (String) this.parameters.remove(HOMES_KEY);
 
689
         String connectHomesString = (String) this.parameters.remove(CONNECT_HOMES_KEY);
 
690
         createHomeLists(this.parameters, homesString, connectHomesString);
 
691
      }
 
692
      
 
693
      // Test for IPv6 host address.
 
694
      if (this.host != null && this.host.indexOf(":") >= 0 && this.host.indexOf("[") == -1)
 
695
      {
 
696
         this.host = "[" + this.host + "]";
 
697
      }
 
698
      
 
699
      rebuildLocatorURI();
 
700
      originalURL = uri;
 
701
      
 
702
      if (!MULTIHOME.equals(host))
 
703
      {
 
704
         homeInUse = new Home(host, port);
 
705
         homes.add(homeInUse);
 
706
         connectHomes.add(homeInUse);
 
707
 
 
708
         if (parameters != null)
 
709
         {
 
710
            // Use "host:port" to connect.
 
711
            String s = (String) parameters.remove(CONNECT_HOMES_KEY);
 
712
            if (s != null) log.warn("host != " + MULTIHOME + ": " + CONNECT_HOMES_KEY + " will be ignored");
 
713
         }
 
714
      }
 
715
   }
 
716
 
 
717
   public int hashCode()
 
718
   {
 
719
      return uri.hashCode();
 
720
   }
 
721
 
 
722
   /**
 
723
    * Compares to see if Object passed is of type InvokerLocator and
 
724
    * it's internal locator uri hashcode is same as this one.  Note, this
 
725
    * means is testing to see if not only the host, protocol, and port are the
 
726
    * same, but the path and parameters as well.  Therefore 'socket://localhost:9000'
 
727
    * and 'socket://localhost:9000/foobar' would NOT be considered equal.
 
728
    * @param obj
 
729
    * @return
 
730
    */
 
731
   public boolean equals(Object obj)
 
732
   {
 
733
      return obj != null && obj instanceof InvokerLocator && uri.equals(((InvokerLocator)obj).getLocatorURI());
 
734
   }
 
735
 
 
736
   /**
 
737
    * Compares to see if InvokerLocator passed represents the same physical remoting server
 
738
    * endpoint as this one.  Unlike the equals() method, this just tests to see if protocol, host,
 
739
    * and port are the same and ignores the path and parameters.
 
740
    * @param compareMe
 
741
    * @return
 
742
    */
 
743
   public boolean isSameEndpoint(InvokerLocator compareMe)
 
744
   {
 
745
      return compareMe != null && getProtocol().equalsIgnoreCase(compareMe.getProtocol()) &&
 
746
             getHost().equalsIgnoreCase(compareMe.getHost()) && getPort() == compareMe.getPort();
 
747
   }
 
748
   
 
749
   public boolean isCompatibleWith(InvokerLocator other)
 
750
   {
 
751
      if (other == null)
 
752
         return false;
 
753
      
 
754
      // If this or other comes from pre-2.4.0 Remoting.
 
755
      if (homes == null || other.homes == null)
 
756
         return false;
 
757
      
 
758
      boolean result1 = getProtocol().equalsIgnoreCase(other.getProtocol()) &&
 
759
                        path.equals(other.getPath()) &&
 
760
                        parameters.equals(other.getParameters());
 
761
      
 
762
      ArrayList tempHomes = connectHomes.isEmpty() ? homes : connectHomes;
 
763
      boolean result2 = intersects(tempHomes, other.getConnectHomeList()) || 
 
764
                        intersects(tempHomes, other.getHomeList());
 
765
      
 
766
      return result1 && result2;
 
767
   }
 
768
 
 
769
   /**
 
770
    * return the locator URI, in the format: <P>
 
771
    * <p/>
 
772
    * <tt>protocol://host[:port][/path[?param=value&param2=value2]]</tt>
 
773
    * Note, this may not be the same as the original uri passed as parameter to the constructor.
 
774
    * @return
 
775
    */
 
776
   public String getLocatorURI()
 
777
   {
 
778
      return uri;
 
779
   }
 
780
 
 
781
   public String getProtocol()
 
782
   {
 
783
      return protocol;
 
784
   }
 
785
 
 
786
   public String getHost()
 
787
   {
 
788
      if (host.equals(MULTIHOME) && homeInUse != null)
 
789
         return homeInUse.host;
 
790
      
 
791
      return host;
 
792
   }
 
793
   
 
794
   public String getActualHost()
 
795
   {
 
796
      return host;
 
797
   }
 
798
   
 
799
   public boolean isMultihome()
 
800
   {
 
801
      return MULTIHOME.equals(host);
 
802
   }
 
803
   
 
804
   public String getConnectHomes()
 
805
   {
 
806
      return convertHomesListToString(connectHomes);
 
807
   }
 
808
   
 
809
   public List getConnectHomeList()
 
810
   {
 
811
      if (connectHomes == null)
 
812
      {
 
813
         ArrayList list = new ArrayList();
 
814
         list.add(new Home(host, port));
 
815
         return list;
 
816
      }
 
817
      
 
818
      return new ArrayList(connectHomes);
 
819
   }
 
820
   
 
821
   public void setConnectHomeList(List connectHomes)
 
822
   {
 
823
      if (connectHomes == null)
 
824
         this.connectHomes = new ArrayList();
 
825
      else
 
826
         this.connectHomes = new ArrayList(connectHomes);
 
827
      
 
828
      rebuildLocatorURI();
 
829
   }
 
830
   
 
831
   public Home getHomeInUse()
 
832
   {
 
833
      if (homeInUse != null || isMultihome())
 
834
         return homeInUse;
 
835
      
 
836
      return new Home(host, port);
 
837
   }
 
838
   
 
839
   public void setHomeInUse(Home homeInUse)
 
840
   {
 
841
      this.homeInUse = homeInUse;
 
842
   }
 
843
   
 
844
   public String getHomes()
 
845
   {  
 
846
      return convertHomesListToString(homes);
 
847
   }
 
848
   
 
849
   public List getHomeList()
 
850
   {
 
851
      if (homes == null)
 
852
      {
 
853
         ArrayList list = new ArrayList();
 
854
         list.add(new Home(host, port));
 
855
         return new ArrayList();
 
856
      }
 
857
      
 
858
      return new ArrayList(homes);
 
859
   }
 
860
 
 
861
   public void setHomeList(List homes)
 
862
   {
 
863
      if (homes == null)
 
864
         this.homes = new ArrayList();
 
865
      else
 
866
         this.homes = new ArrayList(homes);
 
867
      
 
868
      rebuildLocatorURI();
 
869
   }
 
870
   
 
871
   public int getPort()
 
872
   {
 
873
      if (host.equals(MULTIHOME) && homeInUse != null)
 
874
         return homeInUse.port;
 
875
      
 
876
      return port;
 
877
   }
 
878
   
 
879
   public int getActualPort()
 
880
   {
 
881
      return port;
 
882
   }
 
883
 
 
884
   public String getPath()
 
885
   {
 
886
      return path;
 
887
   }
 
888
 
 
889
   public Map getParameters()
 
890
   {
 
891
      if (parameters == null)
 
892
      {
 
893
         parameters = new TreeMap();
 
894
      }
 
895
      return parameters;
 
896
   }
 
897
 
 
898
   public String toString()
 
899
   {
 
900
      return "InvokerLocator [" + uri + "]";
 
901
   }
 
902
 
 
903
   /**
 
904
    * Gets the original uri passed to constructor (if there was one).
 
905
    * @return
 
906
    */
 
907
   public String getOriginalURI()
 
908
   {
 
909
      return originalURL;
 
910
   }
 
911
 
 
912
   /**
 
913
    * narrow this invoker to a specific RemoteClientInvoker instance
 
914
    *
 
915
    * @return
 
916
    * @throws Exception
 
917
    */
 
918
   public ClientInvoker narrow() throws Exception
 
919
   {  
 
920
      try
 
921
      {
 
922
         return (ClientInvoker) AccessController.doPrivileged( new PrivilegedExceptionAction()
 
923
         {
 
924
            public Object run() throws Exception
 
925
            {
 
926
               return InvokerRegistry.createClientInvoker(InvokerLocator.this);
 
927
            }
 
928
         });
 
929
      }
 
930
      catch (PrivilegedActionException pae)
 
931
      {
 
932
         throw pae.getException();
 
933
      }
 
934
   }
 
935
 
 
936
 
 
937
   public String findSerializationType()
 
938
   {
 
939
      String serializationTypeLocal = SerializationStreamFactory.JAVA;
 
940
      if(parameters != null)
 
941
      {
 
942
         serializationTypeLocal = (String) parameters.get(SERIALIZATIONTYPE);
 
943
         if(serializationTypeLocal == null)
 
944
         {
 
945
            serializationTypeLocal = (String) parameters.get(InvokerLocator.SERIALIZATIONTYPE_CASED);
 
946
            if(serializationTypeLocal == null)
 
947
            {
 
948
               serializationTypeLocal = SerializationStreamFactory.JAVA;
 
949
            }
 
950
         }
 
951
      }
 
952
 
 
953
      return serializationTypeLocal;
 
954
   }
 
955
 
 
956
   protected boolean intersects(Collection c1, Collection c2)
 
957
   {
 
958
      Iterator it = c1.iterator();
 
959
      while (it.hasNext())
 
960
      {
 
961
         if (c2.contains(it.next()))
 
962
            return true;
 
963
      }
 
964
      return false;
 
965
   }
 
966
   
 
967
   protected void rebuildLocatorURI()
 
968
   {  
 
969
      String portPart = (port > -1) ? (":" + port) : "";
 
970
      String divider = path.startsWith("/") ? "" : "/";
 
971
      String parametersPart = (parameters != null) ? "?" : "";
 
972
      uri = protocol + "://" + host + portPart + divider + path + parametersPart;
 
973
      
 
974
      if(parameters != null)
 
975
      {
 
976
         if (!homes.isEmpty())
 
977
            parameters.put(HOMES_KEY, convertHomesListToString(homes));
 
978
         if (!connectHomes.isEmpty())
 
979
            parameters.put(CONNECT_HOMES_KEY, convertHomesListToString(connectHomes));
 
980
         
 
981
         Iterator iter = parameters.keySet().iterator();
 
982
         while(iter.hasNext())
 
983
         {
 
984
            String key = (String) iter.next();
 
985
            String val = (String) parameters.get(key);
 
986
            if ("".equals(val))
 
987
            {
 
988
               uri += key;  
 
989
            }
 
990
            else
 
991
            {
 
992
               uri += key + "=" + val;  
 
993
            }
 
994
            if(iter.hasNext())
 
995
            {
 
996
               uri += "&";
 
997
            }
 
998
         }
 
999
         
 
1000
         parameters.remove(HOMES_KEY);
 
1001
         parameters.remove(CONNECT_HOMES_KEY);
 
1002
      }
 
1003
   }
 
1004
   
 
1005
   protected static String encodePercent(String s)
 
1006
   {
 
1007
      if (s == null) return null;
 
1008
      StringTokenizer st = new StringTokenizer(s, "%");
 
1009
      StringBuffer sb = new StringBuffer();
 
1010
      int limit = st.countTokens() - 1;
 
1011
      for (int i = 0; i < limit; i++)
 
1012
      {
 
1013
         String token = st.nextToken();
 
1014
         sb.append(token).append("%25");
 
1015
      }
 
1016
      sb.append(st.nextToken());
 
1017
      return sb.toString();
 
1018
   }
 
1019
   
 
1020
   protected static String decodePercent(String s)
 
1021
   {
 
1022
      if (s == null) return null;
 
1023
      StringBuffer sb = new StringBuffer();
 
1024
      int fromIndex = 0;
 
1025
      int index = s.indexOf("%25", fromIndex);
 
1026
      while (index >= 0)
 
1027
      {
 
1028
         sb.append(s.substring(fromIndex, index)).append('%');
 
1029
         fromIndex = index + 3;
 
1030
         index = s.indexOf("%25", fromIndex);
 
1031
      }
 
1032
      sb.append(s.substring(fromIndex));
 
1033
      return sb.toString();
 
1034
   }
 
1035
   
 
1036
   static private String getSystemProperty(final String name, final String defaultValue)
 
1037
   {
 
1038
      if (SecurityUtility.skipAccessControl())
 
1039
         return System.getProperty(name, defaultValue);
 
1040
         
 
1041
      String value = null;
 
1042
      try
 
1043
      {
 
1044
         value = (String)AccessController.doPrivileged( new PrivilegedExceptionAction()
 
1045
         {
 
1046
            public Object run() throws Exception
 
1047
            {
 
1048
               return System.getProperty(name, defaultValue);
 
1049
            }
 
1050
         });
 
1051
      }
 
1052
      catch (PrivilegedActionException e)
 
1053
      {
 
1054
         throw (RuntimeException) e.getCause();
 
1055
      }
 
1056
      
 
1057
      return value;
 
1058
   }
 
1059
   
 
1060
   static private String getSystemProperty(final String name)
 
1061
   {
 
1062
      if (SecurityUtility.skipAccessControl())
 
1063
         return System.getProperty(name);
 
1064
      
 
1065
      String value = null;
 
1066
      try
 
1067
      {
 
1068
         value = (String)AccessController.doPrivileged( new PrivilegedExceptionAction()
 
1069
         {
 
1070
            public Object run() throws Exception
 
1071
            {
 
1072
               return System.getProperty(name);
 
1073
            }
 
1074
         });
 
1075
      }
 
1076
      catch (PrivilegedActionException e)
 
1077
      {
 
1078
         throw (RuntimeException) e.getCause();
 
1079
      }
 
1080
      
 
1081
      return value;
 
1082
   }
 
1083
   
 
1084
   static private boolean getBoolean(final String name)
 
1085
   {
 
1086
      if (SecurityUtility.skipAccessControl())
 
1087
         return Boolean.getBoolean(name);
 
1088
      
 
1089
      Boolean value = null;
 
1090
      try
 
1091
      {
 
1092
         value = (Boolean)AccessController.doPrivileged( new PrivilegedExceptionAction()
 
1093
         {
 
1094
            public Object run() throws Exception
 
1095
            {
 
1096
               return Boolean.valueOf(Boolean.getBoolean(name));
 
1097
            }
 
1098
         });
 
1099
      }
 
1100
      catch (PrivilegedActionException e)
 
1101
      {
 
1102
         throw (RuntimeException) e.getCause();
 
1103
      }
 
1104
      
 
1105
      return value.booleanValue();
 
1106
   }
 
1107
}