summaryrefslogtreecommitdiff
path: root/java/JACE/netsvcs/Token/TokenRequestHandler.java
blob: cb6d729f3bd0c2b2aea63554b34b1cf329a5e103 (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
package JACE.netsvcs.Token;

import java.io.*;
import java.net.SocketException;
import java.util.*;
import JACE.Connection.*;
import JACE.OS.*;
import JACE.netsvcs.Handler;

/**
 * Created by TokenAcceptor to handle token requests.  Delegates to
 * the appropriate LockHandler.  This is fairly robust, and can handle
 * multiple clients and locks (meaning requests can come in to this
 * handle with varying client IDs and token names and still be processed
 * and released appropriately.)  Compatible with the C++ ACE token service.
 *
 *@author Everett Anderson
 */
class TokenRequestHandler extends Handler
{
  /** 
   * Default constructor.
   */
  public TokenRequestHandler() {
    this.clients_ = new Vector (10);
  }
  
  /** 
   * Creates a new TokenRequest instance.
   */
  public Object newRequest ()
  {
    return new TokenRequest ();
  }

  /** 
   * Sends an error message to a client with the TokenReply.EIO
   * errno before abandoning the connection.  This is used when an IO 
   * error occured while receiving the request.
   *
   *@param lastRequest request object to get the arg from
   */
  protected void sendAbortMessage (TokenRequest lastRequest)
  {
    TokenReply reply = new TokenReply (TokenReply.EIO,
				       lastRequest.arg ());
    try {
      reply.streamOutTo (this.peer ().dataOutputStream ());
    } catch (Exception e) {
      // Doesn't matter if there is an error here, we've abandoned
      // the connection.
    }
  }

  /** 
   * Safely shuts down this handler, making sure to release any locks
   * that were touched by clients from this TokenRequestHandler.
   * 
   *@return -1 on failure, 0 on success
   */
  public synchronized int close ()
  {
    // For every client X that has used this handler
    //    for every LockHandler that X has used
    //        release the lock until it fails because X isn't the owner
    //    remove the client entries
    // Call Handler.close ()
    if (!done ()) {
      
      TokenAcceptor parent = (TokenAcceptor) parent ();
      Enumeration clientEnum = clients_.elements ();

      while (clientEnum.hasMoreElements ()) {
	String clientID = (String)clientEnum.nextElement ();
	
	Enumeration handlers = parent.getClientLockHandlers (clientID);
	if (handlers == null)
	  continue;
	
	int num = 0;
	
	while (handlers.hasMoreElements ()) {
	  LockHandler handler = (LockHandler)handlers.nextElement ();
	  
	  handler.abandonLock (clientID);

	  num++;
	}
	
	parent.removeClient (clientID);
      }

      return super.close ();
    }

    return 0;
  }

  /**
   * Read in the given TokenRequest and delegates to the appropriate
   * LockHandler.
   *
   *@see JACE.netsvcs.Handler
   *@param requestObject TokenRequest object to use
   */
  public void processRequest (Object requestObject)
    throws SocketException, EOFException, IOException
  {
    TokenRequest request = (TokenRequest)requestObject;
    TokenAcceptor parent = (TokenAcceptor) parent ();

    try {
      request.streamInFrom (this.peer ().dataInputStream ());
      
      if (!request.tokenName ().equals (lastTokenName_)) {
	// Switched tokens:
	//
	// Either find a handler that's already been made (which would
	// mean this token has been accessed before), or create a new
	// one with a new token
	handler_ = parent.getLockHandler(request.tokenName(),
					 request.tokenType());
	
	if (handler_ == null) {
	  // The client asked for an operation on a type of token
	  // that we don't know about.
	  ACE.ERROR ("Unknown lock type: " + request.tokenType ());
	  TokenReply error = new TokenReply (TokenReply.EINVAL,
					     request.arg ());
	  error.streamOutTo(this.peer ().dataOutputStream ());
	  return;
	}
	
	// Add this LockHandler to the list of those accessed by
	// this clientID
	parent.addClientLockHandler (request.clientID (),
				     handler_);
      }
      
      if (!request.clientID ().equals (lastClientID_)) {
	// Switched clients
	
	if (!clients_.contains (request.clientID ())) 
	  clients_.addElement (request.clientID ());
	
	parent.addClientLockHandler (request.clientID (),
				     handler_);
      }
      
      lastClientID_ = request.clientID ();
      lastTokenName_ = request.tokenName ();
      
      TokenReply reply = handler_.handleRequest(this, request);

      reply.streamOutTo(this.peer ().dataOutputStream ());
      
    } catch (NullPointerException e) {
      sendAbortMessage (request);
      throw e;
    } catch (IOException e) {
      sendAbortMessage (request);
      throw e;
    }
  }

  // List of clientIDs that have been processed by this instance
  // of TokenRequestHandler.  This is useful when abandoning the
  // locks of any clients that have been using this socket.
  private Vector clients_;

  // Name of the last token accessed
  private String lastTokenName_ = null;

  // Last client ID which accessed a token from this handler
  private String lastClientID_ = null;

  // Current LockHandler
  private LockHandler handler_ = null;
}