summaryrefslogtreecommitdiff
path: root/java/JACE/netsvcs/Token/LockHandlerAdapter.java
blob: e240000161c4d34954ca560aad1152ede1b3484a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
package JACE.netsvcs.Token;

import java.util.*;
import JACE.ASX.*;
import JACE.OS.*;
import JACE.Concurrency.*;

/**
 * LockHandler implementation for any AbstractLock.
 * <P>
 * Provides the dispatching to appropriate methods on an AbstractLock
 * as requests come in.
 */
public class LockHandlerAdapter implements LockHandler
{
  /**
   * Constructor taking an AbstractLock to use as the locking
   * mechanism the requests work on.
   */
  public LockHandlerAdapter (AbstractLock lock)
  {
    lock_ = lock;
  }

  /**
   * Default constructor.
   */
  public LockHandlerAdapter ()
  {
    lock_ = null;
  }

  /**
   * Dispatch the request according to its type, calling the
   * appropriate methods on the AbstractLock member.
   *
   *@param caller TokenRequestHandler which called handleRequest (unused)
   *@param request request to process
   *@return appropriate reply to send to the client
   */
  public TokenReply handleRequest (TokenRequestHandler caller,
				   TokenRequest request)
  {
    String client = request.clientID ();
    String token = request.tokenName ();
    TokenReply result = null;

    // Dispatch according to operation type
    switch (request.operationType ())
      {
      case LockOperations.ACQUIRE:
	ACE.DEBUG (client + " begins ACQUIRE for " + token);
	result = acquireDispatcher (request);
	break;
      case LockOperations.RELEASE:
	ACE.DEBUG (client + " begins RELEASE for " + token);
	result = release (request);
	break;
      case LockOperations.RENEW:
	ACE.DEBUG (client + " begins RENEW for " + token);
	result = renew (request);
	break;
      case LockOperations.REMOVE:
	ACE.DEBUG (client + " begins REMOVE for " + token);
	result = remove (request);
	break;
      case LockOperations.TRY_ACQUIRE:
	ACE.DEBUG (client + " begins TRY_ACQUIRE for " + token);
	result = tryAcquireDispatcher (request);
	break;
      default:
	ACE.ERROR ("Unknown operation: " + request.operationType ());
	break;
      }

    ACE.DEBUG (client + " result: " + result);

    return result;
  }
  
  /**
   * Create a TimeValue from the given request's timeout information.  Note
   * that the time in the request is an absolute time timeout.
   *
   *@param request request to obtain the timeout info from
   *@return null if useTimeout is false, otherwise a TimeValue
   *        representing the appropriate time period
   */
  protected TimeValue getTimeout (TokenRequest request)
  {
    if (request.useTimeout ()) 
      return new TimeValue (request.sec (),
			    request.usec () * 1000);
    else
      return null;
  }

  /**
   * Call acquireWrite on the lock, returning its return value.
   *
   *@see AbstractLock#acquireWrite
   *@return value from the lock's operation
   */
  protected int acquireWrite (TokenRequest request, TimeValue timeout)
    throws LockException, TimeoutException, InterruptedException
  {
    int result;

    if (timeout != null)
      result = lock_.acquireWrite (timeout);
    else
      result = lock_.acquireWrite ();
    
    return result;
  }

  /**
   * Call acquireRead on the lock, returning its return value.
   *
   *@see AbstractLock#acquireRead
   *@return value from the lock's operation
   */
  protected int acquireRead (TokenRequest request, TimeValue timeout)
    throws LockException, TimeoutException, InterruptedException
  {
    int result;

    if (timeout != null)
      result = lock_.acquireRead (timeout);
    else
      result = lock_.acquireRead ();

    return result;
  }

  /**
   * Call acquire on the lock, returning its return value.
   *
   *@see AbstractLock#acquire
   *@return value from the lock's operation
   */
  protected int acquire (TokenRequest request, TimeValue timeout)
    throws LockException, TimeoutException, InterruptedException
  {
    int result;

    if (timeout != null)
      result = lock_.acquire (timeout);
    else
      result = lock_.acquire ();

    return result;
  }

  /**
   * Dispatch to the appropriate acquire method.  In C++ ACE, when
   * the type is LockTypes.RWLOCK and the proxy type is
   * LockTypes.WRITE_LOCK_PROXY, then this calls acquireWrite.
   * If it's RWLOCK and the proxy is READ_LOCK_PROXY, it calls
   * acquireRead.  In the normal case, it just calls acquire.
   *
   *@return reply to be sent back to the client (values for errno
   *        include constants in TokenReply such as EFAULT, ETIME,
   *        EINTR, or NO_ERRORS)
   */
  protected TokenReply acquireDispatcher (TokenRequest request)
  {
    int result;
    TimeValue timeout = getTimeout (request);
    
    try {

      /*
	ACE specifies that when requesting a reader lock, the
	token type will be RWLOCK and the proxy type is 0.
	When it's a writer lock, the proxy type is 1.
      */
      if (request.tokenType () == LockTypes.RWLOCK) {
	if (request.proxyType () == LockTypes.READ_LOCK_PROXY)
	  result = acquireRead (request, timeout);
	else
	  result = acquireWrite (request, timeout);
      } else
	result = acquire (request, timeout);
  
    } catch (LockException e) {
      return new TokenReply (TokenReply.EFAULT,
			     request.arg ());
    } catch (TimeoutException e) {
      return new TokenReply (TokenReply.ETIME,
			     request.arg ());
    } catch (InterruptedException e) {
      return new TokenReply (TokenReply.EINTR,
			     request.arg ());
    }
    
    if (result == AbstractLock.FAILURE) {
      return new TokenReply (TokenReply.EFAULT,
			     request.arg ());
    } else {
      return new TokenReply (TokenReply.NO_ERRORS, 
			     request.arg ());
    }
  }

  /**
   * Process a release request and construct a reply.  The values
   * for errno include TokenReply constants EFAULT, EACCES, or
   * NO_ERRORS.
   */
  protected TokenReply release (TokenRequest request)
  {
    int result;

    try {
      result = lock_.release ();
    } catch (LockException e) {
      return new TokenReply (TokenReply.EFAULT,
			     request.arg ());
    }

    if (result == AbstractLock.FAILURE) {
      return new TokenReply (TokenReply.EACCES,
			     request.arg ());
    } else {
      return new TokenReply (TokenReply.NO_ERRORS,
			     request.arg ());
    }
  }

  /**
   * Process a renew request and construct a reply.  The values for
   * errno include TokenReply constants EFAULT, ETIME, EINTR, EACCES,
   * or NO_ERRORS.
   */
  protected TokenReply renew (TokenRequest request)
  {
    int result = AbstractLock.FAILURE;
    TimeValue timeout = getTimeout (request);

    try {

      if (timeout != null) {
	result = lock_.renew (request.requeuePosition (),
			     timeout);
      } else {
	result = lock_.renew (request.requeuePosition ());
      }

    } catch (LockException e) {
      return new TokenReply (TokenReply.EFAULT,
			     request.arg ());
    } catch (TimeoutException e) {
      return new TokenReply (TokenReply.ETIME,
			     request.arg ());
    } catch (InterruptedException e) {
      return new TokenReply (TokenReply.EINTR,
			     request.arg ());
    }

    if (result == AbstractLock.FAILURE) {
      return new TokenReply (TokenReply.EACCES,
			     request.arg ());
    } else {
      return new TokenReply (TokenReply.NO_ERRORS, 
			     request.arg ());
    }
  }

  /**
   * Process a remove request and construct a reply.  This currently
   * is not supported in the normal AbstractLock interface, so the
   * default implementation returns a reply with errno set to
   * TokenReply.ENOTSUP.
   */
  protected TokenReply remove (TokenRequest request)
  {
    ACE.ERROR ("Remove is unimplemented");
    return new TokenReply (TokenReply.ENOTSUP,
			   request.arg ());
  }

  /**
   * Call tryAcquireWrite on the lock, returning the result.
   */
  protected int tryAcquireWrite (TokenRequest request)
    throws LockException
  {
    return lock_.tryAcquireWrite ();
  }

  /**
   * Call tryAcquireRead on the lock, returning the result.
   */
  protected int tryAcquireRead (TokenRequest request)
    throws LockException
  {
    return lock_.tryAcquireRead ();
  }

  /**
   * Call tryAcquire on the lock, returning the result.
   */
  protected int tryAcquire (TokenRequest request) throws LockException
  {
    return lock_.tryAcquire ();
  }

  /**
   * Dispatch to the appropriate tryAcquire method.  In C++ ACE, when
   * the type is LockTypes.RWLOCK and the proxy type is
   * LockTypes.WRITE_LOCK_PROXY, then this calls acquireWrite.
   * If it's RWLOCK and the proxy is READ_LOCK_PROXY, it calls
   * acquireRead.  In the normal case, it just calls acquire.
   *
   *@return reply to be sent back to the client (values for errno
   *        include constants in TokenReply such as EFAULT, 
   *        EWOULDBLOCK, or NO_ERRORS).
   */
  protected TokenReply tryAcquireDispatcher (TokenRequest request)
  {
    int result;

    try {

      /*
	ACE specifies that when requesting a reader lock, the
	token type will be RWLOCK and the proxy type is 0.
	When it's a writer lock, the proxy type is 1.
      */
      if (request.tokenType () == LockTypes.RWLOCK) {
	if (request.proxyType () == LockTypes.READ_LOCK_PROXY)
	  result = tryAcquireRead (request);
	else
	  result = tryAcquireWrite (request);
      } else
	result = tryAcquire (request);
  
    } catch (LockException e) {
      return new TokenReply (TokenReply.EFAULT,
			     request.arg ());
    }

    if (result == AbstractLock.FAILURE) {
      return new TokenReply (TokenReply.EWOULDBLOCK,
			     request.arg ());
    } else {
      return new TokenReply (TokenReply.NO_ERRORS, 
			     request.arg ());
    }
  }

  /**
   * Abandon any claim the specified client has on the lock.
   *
   *@param clientID identification of the client
   */
  public void abandonLock (String clientID)
  {
    ACE.DEBUG (clientID + " abandoning lock");
    try {
      int nesting_level = 0;
      while (lock_.release () != AbstractLock.FAILURE) 
	{
	  nesting_level++;
	  // Loop until not the owner in case the lock
	  // supports nested acquires
	}
      if (nesting_level == 0) 
	ACE.DEBUG (clientID + " was not the owner");
      else
	ACE.DEBUG (clientID + " had " + nesting_level + " locks");
    } catch (LockException e) {
      ACE.ERROR ("While abandoning lock: " + e.getMessage ());
      // Don't need to send a reply to the client
    }
  }

  protected AbstractLock lock_;
}