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

« back to all changes in this revision

Viewing changes to src/main/org/jboss/remoting/MicroRemoteClientInvoker.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
package org.jboss.remoting;
 
2
 
 
3
import org.jboss.logging.Logger;
 
4
import org.jboss.remoting.loading.ClassByteClassLoader;
 
5
import org.jboss.remoting.loading.RemotingClassLoader;
 
6
import org.jboss.remoting.marshal.InvalidMarshallingResource;
 
7
import org.jboss.remoting.marshal.MarshalFactory;
 
8
import org.jboss.remoting.marshal.Marshaller;
 
9
import org.jboss.remoting.marshal.UnMarshaller;
 
10
import org.jboss.remoting.marshal.UpdateableClassloaderUnMarshaller;
 
11
import org.jboss.remoting.transport.ClientInvoker;
 
12
import org.jboss.remoting.util.SecurityUtility;
 
13
import org.jboss.util.id.GUID;
 
14
 
 
15
import java.io.IOException;
 
16
import java.security.AccessController;
 
17
import java.security.PrivilegedAction;
 
18
import java.security.PrivilegedActionException;
 
19
import java.security.PrivilegedExceptionAction;
 
20
import java.util.HashMap;
 
21
import java.util.List;
 
22
import java.util.Map;
 
23
import java.util.WeakHashMap;
 
24
 
 
25
/**
 
26
 * MicroRemoteClientInvoker is an abstract client part handler that implements the bulk of the heavy
 
27
 * lifting to process a remote method and dispatch it to a remote ServerInvoker and handle the result. <P>
 
28
 * <p/>
 
29
 * Specialized Client/Server Invokers might add additional functionality as part of the invocation - such as
 
30
 * delivering queued notifcations from a remote server by adding the notification objects during each invocation
 
31
 * to the invocation result payload and then having the client re-dispatch the notifications locally upon
 
32
 * receiving the return invocation result.
 
33
 *
 
34
 * The reason for the name micro is that this class contains only api that can be run within a J2ME envrionment.
 
35
 *
 
36
 * @author <a href="mailto:jhaynie@vocalocity.net">Jeff Haynie</a>
 
37
 * @author <a href="mailto:telrod@e2technologies.net">Tom Elrod</a>
 
38
 * @version $Revision: 5868 $
 
39
 */
 
40
public abstract class MicroRemoteClientInvoker extends AbstractInvoker implements ClientInvoker
 
41
{
 
42
   private static final Logger log = Logger.getLogger(MicroRemoteClientInvoker.class);
 
43
   private boolean trace = log.isTraceEnabled();
 
44
 
 
45
   protected boolean connected = false;
 
46
   private Marshaller marshaller;
 
47
   private Map unmarshallers = new WeakHashMap();
 
48
   private String dataType;
 
49
   private final Object clientLeaseLock = new Object();
 
50
   private LeasePinger leasePinger = null;
 
51
   private String invokerSessionID = new GUID().toString();
 
52
   protected boolean parentFirstClassLoading = true;
 
53
   private boolean changeInvalidStateToCannotConnect = false;
 
54
   
 
55
   protected List connectHomes;
 
56
 
 
57
   public MicroRemoteClientInvoker(InvokerLocator locator)
 
58
   {
 
59
      super(locator);
 
60
      init();
 
61
   }
 
62
 
 
63
   public MicroRemoteClientInvoker(InvokerLocator locator, Map configuration)
 
64
   {
 
65
      super(locator, configuration);
 
66
      init();
 
67
   }
 
68
 
 
69
   /**
 
70
    * Transport a request against a remote ServerInvoker.
 
71
    */
 
72
   public Object invoke(InvocationRequest invocationReq) throws Throwable
 
73
   {
 
74
      Object returnValue = null;
 
75
      int invokeCount = 0;
 
76
 
 
77
      if (trace) { log.trace(this + "(" + (++invokeCount) + ") invoking " + invocationReq); }
 
78
 
 
79
      // Set up marshaller and unmarshaller.
 
80
      Marshaller marshaller = null;
 
81
      UnMarshaller unmarshaller = null;
 
82
      RemotingClassLoader rcl = null;
 
83
      synchronized (MicroRemoteClientInvoker.class)
 
84
      {
 
85
         marshaller = getMarshaller();
 
86
         if (marshaller == null)
 
87
         {
 
88
            // try by locator (in case marshaller class name specified)
 
89
            Map map = passConfigMapToMarshalFactory ? configuration : null;
 
90
            marshaller = MarshalFactory.getMarshaller(getLocator(), getClassLoader(), map);
 
91
            if (marshaller == null)
 
92
            {
 
93
               // need to have a marshaller, so create a default one
 
94
               marshaller = MarshalFactory.getMarshaller(getDataType(), getSerializationType());
 
95
               if (marshaller == null)
 
96
               {
 
97
                  // went as far as possible to find a marshaller, will have to give up
 
98
                  throw new InvalidMarshallingResource(
 
99
                        "Can not find a valid marshaller for data type: " + getDataType());
 
100
               }
 
101
            }
 
102
            setMarshaller(marshaller);
 
103
         }
 
104
         
 
105
         unmarshaller = getUnMarshaller();
 
106
         if (unmarshaller == null)
 
107
         {
 
108
            // try by locator (in case unmarshaller class name specified)
 
109
            Map map = passConfigMapToMarshalFactory ? configuration : null;
 
110
            unmarshaller = MarshalFactory.getUnMarshaller(getLocator(), getClassLoader(), map);
 
111
            if (unmarshaller == null)
 
112
            {
 
113
               unmarshaller = MarshalFactory.getUnMarshaller(getDataType(), getSerializationType());
 
114
               if (unmarshaller == null)
 
115
               {
 
116
                  // went as far as possible to find a unmarshaller, will have to give up
 
117
                  throw new InvalidMarshallingResource(
 
118
                        "Can not find a valid unmarshaller for data type: " + getDataType());
 
119
               }
 
120
            }
 
121
            setUnMarshaller(unmarshaller);
 
122
         }
 
123
 
 
124
         // Each unmarshaller gets a RemotingClassloader classloader containing the 
 
125
         // remoting class loader (for remote classloading) and the current thread's
 
126
         // class loader.  This allows to load remoting classes as well as user's
 
127
         // classes.  If possible, will simply reset context classloader on existing
 
128
         // RemotingClassLoader.
 
129
         final ClassLoader contextClassLoader = getContextClassLoader(Thread.currentThread());
 
130
         if (unmarshaller instanceof UpdateableClassloaderUnMarshaller)
 
131
         {
 
132
            UpdateableClassloaderUnMarshaller uclum = (UpdateableClassloaderUnMarshaller) unmarshaller;
 
133
            ClassLoader cl = uclum.getClassLoader();
 
134
            if (cl instanceof RemotingClassLoader)
 
135
            {
 
136
               rcl = (RemotingClassLoader) cl;
 
137
               rcl.setUserClassLoader(contextClassLoader);
 
138
            }
 
139
            else
 
140
            {
 
141
               rcl = createRemotingClassLoader(getClassLoader(), contextClassLoader, parentFirstClassLoading);
 
142
               unmarshaller.setClassLoader(rcl);
 
143
            }
 
144
         }
 
145
         else
 
146
         {
 
147
            rcl = createRemotingClassLoader(getClassLoader(), contextClassLoader, parentFirstClassLoading);
 
148
            unmarshaller.setClassLoader(rcl);  
 
149
         }
 
150
      }
 
151
 
 
152
      // if raw, then send only param of invocation request
 
153
      Object payload = null;
 
154
      Map metadata = invocationReq.getRequestPayload();
 
155
      if (metadata != null && metadata.get(Client.RAW) != null)
 
156
      {
 
157
         payload = invocationReq.getParameter();
 
158
      }
 
159
      else
 
160
      {
 
161
         payload = invocationReq;
 
162
      }
 
163
 
 
164
      try
 
165
      {
 
166
         String sessionId = invocationReq.getSessionId();
 
167
         returnValue = transport(sessionId, payload, metadata, marshaller, unmarshaller);
 
168
      }
 
169
      finally
 
170
      {
 
171
         // Delete reference to current thread's context classloader.
 
172
         synchronized (MicroRemoteClientInvoker.class)
 
173
         {
 
174
            rcl.unsetUserClassLoader();
 
175
         }
 
176
      }
 
177
      
 
178
      // Now check if is remoting response and process
 
179
      if (returnValue instanceof InvocationResponse)
 
180
      {
 
181
         InvocationResponse response = (InvocationResponse)returnValue;
 
182
         returnValue = response.getResult();
 
183
 
 
184
         // if is a server side exception, throw it
 
185
         if (response.isException())
 
186
         {
 
187
            Throwable e = (Throwable)returnValue;
 
188
 
 
189
            if (trace) { log.trace(this + " received a server-side exception as response to the invocation: " + e); }
 
190
 
 
191
            StackTraceElement[] serverStackTrace;
 
192
            if (e.getCause() != null)
 
193
            {
 
194
               serverStackTrace = e.getCause().getStackTrace();
 
195
               if (serverStackTrace == null || serverStackTrace.length == 0)
 
196
               {
 
197
                  serverStackTrace = e.getStackTrace();
 
198
               }
 
199
            }
 
200
            else
 
201
            {
 
202
               serverStackTrace = e.getStackTrace();
 
203
            }
 
204
 
 
205
            // need to check that there is a server stack trace.  If there is not, need to log
 
206
            // warning here so caller knows that error happened on server side and to look there,
 
207
            // as stack trace is just going to lead them to here, giving the impression that is
 
208
            // a client side exception from this point within remoting client.
 
209
            if (serverStackTrace == null || serverStackTrace.length == 0)
 
210
            {
 
211
               log.warn("An exception occurred on the server side when making remote invocation.  " +
 
212
                        "The exception returned from server does not include a stack trace.  " +
 
213
                        "Original server side exception message is " + e.getMessage(), e);
 
214
            }
 
215
 
 
216
            Exception clientException = new Exception();
 
217
            StackTraceElement[] clientStackTrace = clientException.getStackTrace();
 
218
            StackTraceElement[] completeStackTrace = new StackTraceElement[serverStackTrace.length + clientStackTrace.length];
 
219
            System.arraycopy(serverStackTrace, 0, completeStackTrace, 0, serverStackTrace.length);
 
220
            System.arraycopy(clientStackTrace, 0, completeStackTrace, serverStackTrace.length, clientStackTrace.length);
 
221
 
 
222
            Throwable responseException = null;
 
223
            if (e instanceof ServerInvoker.InvalidStateException && changeInvalidStateToCannotConnect)
 
224
            {
 
225
               responseException = new CannotConnectException(e.getMessage(), e.getCause());
 
226
            }
 
227
            else
 
228
            {
 
229
               responseException = e;
 
230
            }
 
231
            
 
232
            if (e.getCause() != null)
 
233
            {
 
234
               responseException.getCause().setStackTrace(completeStackTrace);
 
235
            }
 
236
            else
 
237
            {
 
238
               responseException.setStackTrace(completeStackTrace);
 
239
            }
 
240
 
 
241
            throw responseException;
 
242
         }
 
243
 
 
244
         if (trace) { log.trace(this + " received InvocationResponse so going to return response's return value of " + returnValue);}
 
245
 
 
246
      }
 
247
 
 
248
      return returnValue;
 
249
   }
 
250
 
 
251
   /**
 
252
    * this method is called prior to making the remote invocation to allow the subclass the ability
 
253
    * to provide additional data or modify the invocation
 
254
    *
 
255
    * @param sessionId
 
256
    * @param param
 
257
    * @param sendPayload
 
258
    * @param receivedPayload
 
259
    */
 
260
   protected void preProcess(String sessionId, Object param, Map sendPayload, Map receivedPayload)
 
261
   {
 
262
   }
 
263
 
 
264
   /**
 
265
    * this method is called prior to returning the result for the invocation to allow the subclass the ability
 
266
    * to modify the result result
 
267
    *
 
268
    * @param sessionId
 
269
    * @param param
 
270
    * @param sendPayload
 
271
    * @param receivedPayload
 
272
    */
 
273
   protected void postProcess(String sessionId, Object param, Map sendPayload,
 
274
                              Map receivedPayload)
 
275
   {
 
276
 
 
277
   }
 
278
 
 
279
   protected abstract Object transport(String sessionId, Object invocation, Map metadata,
 
280
                                       Marshaller marshaller, UnMarshaller unmarshaller)
 
281
      throws IOException, ConnectionFailedException, ClassNotFoundException;
 
282
 
 
283
   /**
 
284
    * Subclasses must provide this method to return true if their remote connection is connected and
 
285
    * false if disconnected.  in some transports, such as SOAP, this method may always return true,
 
286
    * since the remote connectivity is done on demand and not kept persistent like other transports
 
287
    * (such as socket-based transport).
 
288
    *
 
289
    * @return boolean true if connected, false if not
 
290
    */
 
291
   public boolean isConnected()
 
292
   {
 
293
      return connected;
 
294
   }
 
295
 
 
296
   /**
 
297
    * Connect to the remote invoker.
 
298
    */
 
299
   public synchronized void connect() throws ConnectionFailedException
 
300
   {
 
301
      if (!connected)
 
302
      {
 
303
         log.debug(this + " connecting");
 
304
         
 
305
         // In single home case, locator's connect homes list consists
 
306
         // locator's host:port.  In multihome case, connect homes list 
 
307
         // is empty unless explicitly defined.
 
308
         connectHomes = locator.getConnectHomeList();
 
309
         if (locator.isMultihome() && connectHomes.isEmpty())
 
310
         {
 
311
            connectHomes = locator.getHomeList();
 
312
         }
 
313
 
 
314
         handleConnect();
 
315
         connected = true;
 
316
 
 
317
         log.debug(this + " connected");
 
318
      }
 
319
   }
 
320
 
 
321
   /**
 
322
    * Subclasses must implement this method to provide a hook to connect to the remote server, if
 
323
    * this applies to the specific transport. However, in some transport implementations, this may
 
324
    * not make must difference since the connection is not persistent among invocations, such as
 
325
    * SOAP.  In these cases, the method should silently return without any processing.
 
326
    *
 
327
    * @throws ConnectionFailedException
 
328
    *
 
329
    */
 
330
   protected abstract void handleConnect() throws ConnectionFailedException;
 
331
 
 
332
   /**
 
333
    * Subclasses must implement this method to provide a hook to disconnect from the remote server,
 
334
    * if this applies to the specific transport. However, in some transport implementations, this
 
335
    * may not make must difference since the connection is not persistent among invocations, such as
 
336
    * SOAP. In these cases, the method should silently return without any processing.
 
337
    */
 
338
   protected abstract void handleDisconnect();
 
339
 
 
340
   /**
 
341
    * disconnect from the remote invokere
 
342
    */
 
343
   public synchronized void disconnect()
 
344
   {
 
345
      if (trace) { log.trace(this + " disconnecting ..."); }
 
346
 
 
347
      if (connected)
 
348
      {
 
349
         connected = false;
 
350
         handleDisconnect();
 
351
         ClassLoader classLoader = getClassLoader();
 
352
         if (classLoader != null && classLoader instanceof ClassByteClassLoader)
 
353
         {
 
354
            ((ClassByteClassLoader) classbyteloader).destroy();
 
355
         }
 
356
         if (trace) { log.trace(this + " disconnected"); }
 
357
      }
 
358
      else
 
359
      {
 
360
         if (trace) { log.trace(this + " is not connected!"); }
 
361
      }
 
362
   }
 
363
 
 
364
   public void setMarshaller(Marshaller marshaller)
 
365
   {
 
366
      this.marshaller = marshaller;
 
367
   }
 
368
 
 
369
   public Marshaller getMarshaller()
 
370
   {
 
371
      return this.marshaller;
 
372
   }
 
373
 
 
374
   public void setUnMarshaller(UnMarshaller unmarshaller)
 
375
   {
 
376
      ClassLoader classLoader = getContextClassLoader(Thread.currentThread());
 
377
      unmarshallers.put(classLoader, unmarshaller);
 
378
   }
 
379
 
 
380
   public UnMarshaller getUnMarshaller()
 
381
   {
 
382
      ClassLoader classLoader = getContextClassLoader(Thread.currentThread());
 
383
      return (UnMarshaller)unmarshallers.get(classLoader);
 
384
   }
 
385
   
 
386
   public String getSessionId()
 
387
   {
 
388
      return this.invokerSessionID;
 
389
   }
 
390
 
 
391
   public void terminateLease(String sessionId, int disconnectTimeout)
 
392
   {
 
393
      terminateLease(sessionId, disconnectTimeout, null);
 
394
   }
 
395
   
 
396
   public void terminateLease(String sessionId, int disconnectTimeout, LeasePinger passedLeasePinger)
 
397
   {
 
398
      synchronized(clientLeaseLock)
 
399
      {
 
400
         if (passedLeasePinger != null && passedLeasePinger != leasePinger)
 
401
         {
 
402
            if (trace) log.trace(this + ": " + passedLeasePinger + " != " + leasePinger);
 
403
            return;
 
404
         }
 
405
         if (trace) log.trace(this + " entering terminateLease() for " + leasePinger);
 
406
         if(leasePinger != null)
 
407
         {
 
408
            leasePinger.setDisconnectTimeout(disconnectTimeout);
 
409
            
 
410
            if (sessionId == null)
 
411
            {
 
412
               if (trace) log.trace(this + " shutting down LeasePinger: " + leasePinger);
 
413
               // Independent of any particular Client - force LeasePinger shutdown.
 
414
               // Should be called only if there is a reasonable belief that the lease
 
415
               // has already stopped on the server side.
 
416
               try
 
417
               {
 
418
                  leasePinger.stopPing();
 
419
               }
 
420
               catch (Exception e)
 
421
               {
 
422
                  log.debug("error shutting down lease pinger" + e.getMessage());
 
423
                  log.trace("error shutting down lease pinger", e);
 
424
               }
 
425
               leasePinger = null;
 
426
            }
 
427
            else
 
428
            {
 
429
               // Remove a particular Client.
 
430
               if (trace) log.trace(this + " removing client " + sessionId + " from LeasePinger: " + leasePinger);
 
431
               boolean isLastClientLease = leasePinger.removeClient(sessionId);
 
432
               if(isLastClientLease)
 
433
               {
 
434
                  if (trace) log.trace(this + " shutting down LeasePinger, " + sessionId + " was last client lease: " + leasePinger);
 
435
                  try
 
436
                  {
 
437
                     leasePinger.stopPing();
 
438
                  }
 
439
                  catch (Exception e)
 
440
                  {
 
441
                     log.debug("error shutting down lease pinger");
 
442
                  }
 
443
                  leasePinger = null;
 
444
               }
 
445
            }
 
446
         }
 
447
         else
 
448
         {
 
449
            if (trace) log.trace(this + " leasePinger is null: must have been shut down already");
 
450
         }
 
451
         if (trace) log.trace(this + " leaving terminateLease() for " + leasePinger);
 
452
      }
 
453
   }
 
454
 
 
455
   public long getLeasePeriod(String sessionID)
 
456
   {
 
457
      synchronized(clientLeaseLock)
 
458
      {
 
459
         if(leasePinger == null)
 
460
         {
 
461
            return -1;
 
462
         }
 
463
 
 
464
         return leasePinger.getLeasePeriod(sessionID);
 
465
      }
 
466
   }
 
467
 
 
468
   public void establishLease(String clientSessionID, Map configuration, long leasePeriod)
 
469
      throws Throwable
 
470
   {
 
471
      Client client = (Client) configuration.get(Client.CLIENT);
 
472
      ConnectionListener listener = (ConnectionListener) configuration.remove(Client.CONNECTION_LISTENER);
 
473
      boolean useClientConnectionIdentity = false;
 
474
      if (configuration != null)
 
475
      {
 
476
         Object o = configuration.get(Remoting.USE_CLIENT_CONNECTION_IDENTITY);
 
477
         if (o instanceof String)
 
478
         {
 
479
            useClientConnectionIdentity = Boolean.valueOf((String) o).booleanValue();
 
480
         }
 
481
         else if (o != null)
 
482
         {
 
483
            log.warn("value of " + Remoting.USE_CLIENT_CONNECTION_IDENTITY + " must be a String: " + o); 
 
484
         }
 
485
      }
 
486
       
 
487
      synchronized (clientLeaseLock)
 
488
      {
 
489
         // if already have a lease pinger, then already have a client with an established
 
490
         // lease and just need to update the lease pinger
 
491
         if (leasePinger != null)
 
492
         {
 
493
            leasePinger.addClient(clientSessionID, configuration, leasePeriod);
 
494
            if (trace) log.trace(this + " added client with session ID " + clientSessionID + " to " + leasePinger);
 
495
         }
 
496
         else
 
497
         {
 
498
            try
 
499
            {
 
500
               if(trace) { log.trace(this + " sending initial lease ping to server to determine if server has leasing enabled."); }
 
501
 
 
502
               // configuration should NOT be passed as want ping to be specific to client invoker
 
503
               // and NOT to the client.
 
504
 
 
505
               String leasePingerId = new GUID().toString();
 
506
               Map requestMap = new HashMap();
 
507
               requestMap.put(LeasePinger.LEASE_PINGER_ID, leasePingerId);
 
508
               requestMap.put(LeasePinger.TIME_STAMP, Long.toString(System.currentTimeMillis()));
 
509
               if (trace) log.trace(this + " initiating lease for leasePingerId " + leasePingerId);
 
510
               InvocationRequest ir = new InvocationRequest(invokerSessionID, null, "$PING$", requestMap, new HashMap(), null);
 
511
 
 
512
               Object ret = invoke(ir);
 
513
 
 
514
               if (ret instanceof InvocationResponse)
 
515
               {
 
516
                  InvocationResponse resp = (InvocationResponse) ret;
 
517
                  Boolean shouldLease = (Boolean)resp.getResult();
 
518
 
 
519
                  if (shouldLease.booleanValue())
 
520
                  {
 
521
                     long defaultLeasePeriod = LeasePinger.DEFAULT_LEASE_PERIOD;
 
522
                     Map respMap = resp.getPayload();
 
523
 
 
524
                     if (respMap != null)
 
525
                     {
 
526
                        Long leaseTimeoutValue = (Long)respMap.get("clientLeasePeriod");
 
527
                        long serverDefaultLeasePeriod = leaseTimeoutValue.longValue();
 
528
                        if(serverDefaultLeasePeriod > 0)
 
529
                        {
 
530
                           defaultLeasePeriod = serverDefaultLeasePeriod;
 
531
                        }
 
532
                     }
 
533
 
 
534
                     if(trace) { log.trace("server does have leasing enabled (with default lease period of " + defaultLeasePeriod + ") and will start a new lease pinger."); }
 
535
 
 
536
                     leasePinger = new LeasePinger(this, invokerSessionID, defaultLeasePeriod, configuration);
 
537
                     leasePinger.setLeasePingerId(leasePingerId);
 
538
                     leasePinger.setUseClientConnectionIdentity(useClientConnectionIdentity);
 
539
                     leasePinger.addClient(clientSessionID, configuration, leasePeriod);
 
540
                     leasePinger.startPing();
 
541
                  }
 
542
               }
 
543
            }
 
544
            catch (Throwable throwable)
 
545
            {
 
546
               Exception e = new Exception("Error setting up client lease");
 
547
               e.initCause(throwable);
 
548
               throw e;
 
549
            }
 
550
         }
 
551
 
 
552
         if (trace) log.trace(this + ": client = " + client + ", listener = " + listener);
 
553
         if (client != null && listener != null)
 
554
         {
 
555
            client.addConnectionListener(listener, configuration);
 
556
         }
 
557
      }
 
558
   }
 
559
 
 
560
   /**
 
561
    * Will get the data type for the marshaller factory so know which marshaller to
 
562
    * get to marshal the data.  Will first check the locator uri for a 'datatype'
 
563
    * parameter and take that value if it exists.  Otherwise, will use the
 
564
    * default datatype for the client invoker, based on transport.
 
565
    */
 
566
   private String getDataType()
 
567
   {
 
568
      if (dataType == null)
 
569
      {
 
570
         String localDataType = getDataType(getLocator());
 
571
         if (localDataType == null)
 
572
         {
 
573
            localDataType = getDefaultDataType();
 
574
         }
 
575
         dataType = localDataType;
 
576
      }
 
577
      return dataType;
 
578
   }
 
579
 
 
580
   private String getDataType(InvokerLocator locator)
 
581
   {
 
582
      String type = null;
 
583
 
 
584
      if (locator != null)
 
585
      {
 
586
         Map params = locator.getParameters();
 
587
         if (params != null)
 
588
         {
 
589
            type = (String) params.get(InvokerLocator.DATATYPE);
 
590
            if (type == null)
 
591
            {
 
592
               type = (String) params.get(InvokerLocator.DATATYPE_CASED);
 
593
            }
 
594
         }
 
595
      }
 
596
      return type;
 
597
   }
 
598
   
 
599
   protected void init()
 
600
   {
 
601
      // Get the parent delegation order flag, default is parent first
 
602
      Object flag = super.getConfiguration().get(Remoting.CLASSLOADING_PARENT_FIRST_DELEGATION);
 
603
      if(flag == null)
 
604
      {
 
605
         // Fallback to the system property
 
606
         flag = getSystemProperty(Remoting.CLASSLOADING_PARENT_FIRST_DELEGATION_PROP);
 
607
      }
 
608
      boolean parentFirst = true;
 
609
      if (flag != null)
 
610
      {
 
611
         String sflag = flag.toString();
 
612
         parentFirst = Boolean.valueOf(sflag).booleanValue();
 
613
      }
 
614
      parentFirstClassLoading = parentFirst;
 
615
      
 
616
      flag = configuration.get(Remoting.CHANGE_INVALID_STATE_TO_CANNOT_CONNECT);
 
617
      if (flag != null)
 
618
      {
 
619
         String sflag = flag.toString();
 
620
         changeInvalidStateToCannotConnect = Boolean.valueOf(sflag).booleanValue();
 
621
      }
 
622
   }
 
623
 
 
624
   /**
 
625
    * Each implementation of the remote client invoker should have
 
626
    * a default data type that is uses in the case it is not specified
 
627
    * in the invoker locator uri.
 
628
    */
 
629
   protected abstract String getDefaultDataType();
 
630
 
 
631
   
 
632
   protected List getConnectHomes()
 
633
   {
 
634
      return connectHomes;
 
635
   }
 
636
 
 
637
   /**
 
638
    * Called by the garbage collector on an object when garbage collection
 
639
    * determines that there are no more references to the object.
 
640
    * A subclass overrides the <code>finalize</code> method to dispose of
 
641
    * system resources or to perform other cleanup.
 
642
    * <p/>
 
643
    * The general contract of <tt>finalize</tt> is that it is invoked
 
644
    * if and when the Java<font size="-2"><sup>TM</sup></font> virtual
 
645
    * machine has determined that there is no longer any
 
646
    * means by which this object can be accessed by any thread that has
 
647
    * not yet died, except as a result of an action taken by the
 
648
    * finalization of some other object or class which is ready to be
 
649
    * finalized. The <tt>finalize</tt> method may take any action, including
 
650
    * making this object available again to other threads; the usual purpose
 
651
    * of <tt>finalize</tt>, however, is to perform cleanup actions before
 
652
    * the object is irrevocably discarded. For example, the finalize method
 
653
    * for an object that represents an input/output connection might perform
 
654
    * explicit I/O transactions to break the connection before the object is
 
655
    * permanently discarded.
 
656
    * <p/>
 
657
    * The <tt>finalize</tt> method of class <tt>Object</tt> performs no
 
658
    * special action; it simply returns normally. Subclasses of
 
659
    * <tt>Object</tt> may override this definition.
 
660
    * <p/>
 
661
    * The Java programming language does not guarantee which thread will
 
662
    * transport the <tt>finalize</tt> method for any given object. It is
 
663
    * guaranteed, however, that the thread that invokes finalize will not
 
664
    * be holding any user-visible synchronization locks when finalize is
 
665
    * invoked. If an uncaught exception is thrown by the finalize method,
 
666
    * the exception is ignored and finalization of that object terminates.
 
667
    * <p/>
 
668
    * After the <tt>finalize</tt> method has been invoked for an object, no
 
669
    * further action is taken until the Java virtual machine has again
 
670
    * determined that there is no longer any means by which this object can
 
671
    * be accessed by any thread that has not yet died, including possible
 
672
    * actions by other objects or classes which are ready to be finalized,
 
673
    * at which point the object may be discarded.
 
674
    * <p/>
 
675
    * The <tt>finalize</tt> method is never invoked more than once by a Java
 
676
    * virtual machine for any given object.
 
677
    * <p/>
 
678
    * Any exception thrown by the <code>finalize</code> method causes
 
679
    * the finalization of this object to be halted, but is otherwise
 
680
    * ignored.
 
681
    *
 
682
    * @throws Throwable the <code>Exception</code> raised by this method
 
683
    */
 
684
   protected void finalize() throws Throwable
 
685
   {
 
686
      disconnect();
 
687
      super.finalize();
 
688
   }
 
689
   
 
690
   protected LeasePinger getLeasePinger()
 
691
   {
 
692
      synchronized(clientLeaseLock)
 
693
      {
 
694
         return leasePinger;
 
695
      }
 
696
   }
 
697
   
 
698
   static private String getSystemProperty(final String name)
 
699
   {
 
700
      if (SecurityUtility.skipAccessControl())
 
701
         return System.getProperty(name);
 
702
      
 
703
      String value = null;
 
704
      try
 
705
      {
 
706
         value = (String)AccessController.doPrivileged( new PrivilegedExceptionAction()
 
707
         {
 
708
            public Object run() throws Exception
 
709
            {
 
710
               return System.getProperty(name);
 
711
            }
 
712
         });
 
713
      }
 
714
      catch (PrivilegedActionException e)
 
715
      {
 
716
         throw (RuntimeException) e.getCause();
 
717
      }
 
718
      
 
719
      return value;
 
720
   }
 
721
   
 
722
   static private RemotingClassLoader createRemotingClassLoader(final ClassLoader remotingClassLoader,
 
723
         final ClassLoader userClassLoader, final boolean parentFirstDelegation)
 
724
   {
 
725
      if (SecurityUtility.skipAccessControl())
 
726
      {
 
727
         return new RemotingClassLoader(remotingClassLoader, userClassLoader, parentFirstDelegation);
 
728
      }
 
729
 
 
730
      return (RemotingClassLoader)AccessController.doPrivileged( new PrivilegedAction()
 
731
      {
 
732
         public Object run()
 
733
         {
 
734
            return new RemotingClassLoader(remotingClassLoader, userClassLoader, parentFirstDelegation);
 
735
         }
 
736
      });
 
737
   }
 
738
   
 
739
   static private ClassLoader getContextClassLoader(final Thread thread)
 
740
   {
 
741
      if (SecurityUtility.skipAccessControl())
 
742
      {
 
743
         return thread.getContextClassLoader();
 
744
      }
 
745
 
 
746
      return (ClassLoader) AccessController.doPrivileged( new PrivilegedAction()
 
747
      {
 
748
         public Object run()
 
749
         {
 
750
            return thread.getContextClassLoader();
 
751
         }
 
752
      });
 
753
   }
 
754
}