Copied remotely
[mono.git] / mcs / class / Novell.Directory.Ldap / Novell.Directory.Ldap / MessageAgent.cs
1 /******************************************************************************
2 * The MIT License
3 * Copyright (c) 2003 Novell Inc.  www.novell.com
4
5 * Permission is hereby granted, free of charge, to any person obtaining  a copy
6 * of this software and associated documentation files (the Software), to deal
7 * in the Software without restriction, including  without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
9 * copies of the Software, and to  permit persons to whom the Software is 
10 * furnished to do so, subject to the following conditions:
11
12 * The above copyright notice and this permission notice shall be included in 
13 * all copies or substantial portions of the Software.
14
15 * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *******************************************************************************/
23 //
24 // Novell.Directory.Ldap.MessageAgent.cs
25 //
26 // Author:
27 //   Sunil Kumar (Sunilk@novell.com)
28 //
29 // (C) 2003 Novell, Inc (http://www.novell.com)
30 //
31
32 using System;
33 using Novell.Directory.Ldap.Utilclass;
34
35 namespace Novell.Directory.Ldap
36 {
37         
38         /* package */
39         class MessageAgent
40         {
41                 private void  InitBlock()
42                 {
43                         messages = new MessageVector(5, 5);
44                 }
45                 /// <summary> empty and return all messages owned by this agent
46                 /// 
47                 /// 
48                 /// </summary>
49                 virtual internal System.Object[] MessageArray
50                 {
51                         /* package */
52                         
53                         get
54                         {
55                                 return messages.ObjectArray;
56                         }
57                         
58                 }
59                 /// <summary> Get a list of message ids controlled by this agent
60                 /// 
61                 /// </summary>
62                 /// <returns> an array of integers representing the message ids
63                 /// </returns>
64                 virtual internal int[] MessageIDs
65                 {
66                         /* package */
67                         
68                         get
69                         {
70                                 int size = messages.Count;
71                                 int[] ids = new int[size];
72                                 Message info;
73                                 
74                                 for (int i = 0; i < size; i++)
75                                 {
76                                         info = (Message) messages[i];
77                                         ids[i] = info.MessageID;
78                                 }
79                                 return ids;
80                         }
81                         
82                 }
83                 /// <summary> Get the maessage agent number for debugging
84                 /// 
85                 /// </summary>
86                 /// <returns> the agent number
87                 /// </returns>
88                 virtual internal System.String AgentName
89                 {
90                         /*packge*/
91                         
92                         get
93                         {
94                                 return name;
95                         }
96                         
97                 }
98                 /// <summary> Get a count of all messages queued</summary>
99                 virtual internal int Count
100                 {
101                         /* package */
102                         
103                         get
104                         {
105                                 int count = 0;
106                                 System.Object[] msgs = messages.ToArray();
107                                 for (int i = 0; i < msgs.Length; i++)
108                                 {
109                                         Message m = (Message) msgs[i];
110                                         count += m.Count;
111                                 }
112                                 return count;
113                         }
114                         
115                 }
116                 private MessageVector messages;
117                 private int indexLastRead = 0;
118                 private static System.Object nameLock; // protect agentNum
119                 private static int agentNum = 0; // Debug, agent number
120                 private System.String name; // String name for debug
121                 
122                 /* package */
123                 internal MessageAgent()
124                 {
125                         InitBlock();
126                         // Get a unique agent id for debug
127                 }
128                 
129                 /// <summary> merges two message agents
130                 /// 
131                 /// </summary>
132                 /// <param name="fromAgent">the agent to be merged into this one
133                 /// </param>
134                 /* package */
135                 internal void  merge(MessageAgent fromAgent)
136                 {
137                         System.Object[] msgs = fromAgent.MessageArray;
138                         for (int i = 0; i < msgs.Length; i++)
139                         {
140                                 messages.Add(msgs[i]);
141                                 ((Message) (msgs[i])).Agent = this;
142                         }
143                         lock (messages)
144                         {
145                                 if (msgs.Length > 1)
146                                 {
147                                         System.Threading.Monitor.PulseAll(messages); // wake all threads waiting for messages
148                                 }
149                                 else if (msgs.Length == 1)
150                                 {
151                                         System.Threading.Monitor.Pulse(messages); // only wake one thread
152                                 }
153                         }
154                         return ;
155                 }
156                 
157                 
158                 /// <summary> Wakes up any threads waiting for messages in the message agent
159                 /// 
160                 /// </summary>
161                 /* package */
162                 internal void  sleepersAwake(bool all)
163                 {
164                         lock (messages)
165                         {
166                                 if (all)
167                                         System.Threading.Monitor.PulseAll(messages);
168                                 else
169                                         System.Threading.Monitor.Pulse(messages);
170                         }
171                         return ;
172                 }
173                 
174                 /// <summary> Returns true if any responses are queued for any of the agent's messages
175                 /// 
176                 /// return false if no responses are queued, otherwise true
177                 /// </summary>
178                 /* package */
179                 internal bool isResponseReceived()
180                 {
181                         int size = messages.Count;
182                         int next = indexLastRead + 1;
183                         Message info;
184                         for (int i = 0; i < size; i++)
185                         {
186                                 if (next == size)
187                                 {
188                                         next = 0;
189                                 }
190                                 info = (Message) messages[next];
191                                 if (info.hasReplies())
192                                 {
193                                         return true;
194                                 }
195                         }
196                         return false;
197                 }
198                 
199                 /// <summary> Returns true if any responses are queued for the specified msgId
200                 /// 
201                 /// return false if no responses are queued, otherwise true
202                 /// </summary>
203                 /* package */
204                 internal bool isResponseReceived(int msgId)
205                 {
206                         try
207                         {
208                                 Message info = messages.findMessageById(msgId);
209                                 return info.hasReplies();
210                         }
211                         catch (System.FieldAccessException ex)
212                         {
213                                 return false;
214                         }
215                 }
216                 
217                 /// <summary> Abandon the request associated with MsgId
218                 /// 
219                 /// </summary>
220                 /// <param name="msgId">the message id to abandon
221                 /// 
222                 /// </param>
223                 /// <param name="cons">constraints associated with this request
224                 /// </param>
225                 /* package */
226                 internal void  Abandon(int msgId, LdapConstraints cons)
227                 //, boolean informUser)
228                 {
229                         Message info = null;
230                         try
231                         {
232                                 // Send abandon request and remove from connection list
233                                 info = messages.findMessageById(msgId);
234                                 SupportClass.VectorRemoveElement(messages, info); // This message is now dead
235                                 info.Abandon(cons, null);
236                                 
237                                 return ;
238                         }
239                         catch (System.FieldAccessException ex)
240                         {
241                         }
242                         return ;
243                 }
244                 
245                 /// <summary> Abandon all requests on this MessageAgent</summary>
246                 /* package */
247                 internal void  AbandonAll()
248                 {
249                         int size = messages.Count;
250                         Message info;
251                         
252                         for (int i = 0; i < size; i++)
253                         {
254                                 info = (Message) messages[i];
255                                 // Message complete and no more replies, remove from id list
256                                 SupportClass.VectorRemoveElement(messages, info);
257                                 info.Abandon(null, null);
258                         }
259                         return ;
260                 }
261                 
262                 /// <summary> Indicates whether a specific operation is complete
263                 /// 
264                 /// </summary>
265                 /// <returns> true if a specific operation is complete
266                 /// </returns>
267                 /* package */
268                 internal bool isComplete(int msgid)
269                 {
270                         try
271                         {
272                                 Message info = messages.findMessageById(msgid);
273                                 if (!info.Complete)
274                                 {
275                                         return false;
276                                 }
277                         }
278                         catch (System.FieldAccessException ex)
279                         {
280                                 ; // return true, if no message, it must be complete
281                         }
282                         return true;
283                 }
284                 
285                 /// <summary> Returns the Message object for a given messageID
286                 /// 
287                 /// </summary>
288                 /// <param name="msgid">the message ID.
289                 /// </param>
290                 /* package */
291                 internal Message getMessage(int msgid)
292                 {
293                         return messages.findMessageById(msgid);
294                 }
295                 
296                 /// <summary> Send a request to the server.  A Message class is created
297                 /// for the specified request which causes the message to be sent.
298                 /// The request is added to the list of messages being managed by
299                 /// this agent.
300                 /// 
301                 /// </summary>
302                 /// <param name="conn">the connection that identifies the server.
303                 /// 
304                 /// </param>
305                 /// <param name="msg">the LdapMessage to send
306                 /// 
307                 /// </param>
308                 /// <param name="timeOut">the interval to wait for the message to complete or
309                 /// <code>null</code> if infinite.
310                 /// </param>
311                 /// <param name="queue">the LdapMessageQueue associated with this request.
312                 /// </param>
313                 /* package */
314                 internal void  sendMessage(Connection conn, LdapMessage msg, int timeOut, LdapMessageQueue queue, BindProperties bindProps)
315                 {
316                         // creating a messageInfo causes the message to be sent
317                         // and a timer to be started if needed.
318                         Message message = new Message(msg, timeOut, conn, this, queue, bindProps);
319                         messages.Add(message);
320                         message.sendMessage(); // Now send message to server
321                         return ;
322                 }
323                 
324                 /// <summary> Returns a response queued, or waits if none queued
325                 /// 
326                 /// </summary>
327                 /* package */
328 //              internal System.Object getLdapMessage(System.Int32 msgId)
329                 internal System.Object getLdapMessage(System.Int32 msgId)
330                 {
331                         return (getLdapMessage(new Integer32(msgId)));
332                 }
333
334                 internal System.Object getLdapMessage(Integer32 msgId)
335                 {
336                         System.Object rfcMsg;
337                         // If no messages for this agent, just return null
338                         if (messages.Count == 0)
339                         {
340                                 return null;
341                         }
342                         if ( msgId != null)
343                         {
344                                 // Request messages for a specific ID
345                                 try
346                                 {
347                                         // Get message for this ID
348 //                                      Message info = messages.findMessageById(msgId);
349                                         Message info = messages.findMessageById(msgId.intValue);
350                                         rfcMsg = info.waitForReply(); // blocks for a response
351                                         if (!info.acceptsReplies() && !info.hasReplies())
352                                         {
353                                                 // Message complete and no more replies, remove from id list
354                                                 SupportClass.VectorRemoveElement(messages, info);
355                                                 info.Abandon(null, null); // Get rid of resources
356                                         }
357                                         else
358                                         {
359                                         }
360                                         return rfcMsg;
361                                 }
362                                 catch (System.FieldAccessException ex)
363                                 {
364                                         // no such message id
365                                         return null;
366                                 }
367                         }
368                         else
369                         {
370                                 // A msgId was NOT specified, any message will do
371                                 lock (messages)
372                                 {
373                                         while (true)
374                                         {
375                                                 int next = indexLastRead + 1;
376                                                 Message info;
377                                                 for (int i = 0; i < messages.Count; i++)
378                                                 {
379                                                         if (next >= messages.Count)
380                                                         {
381                                                                 next = 0;
382                                                         }
383                                                         info = (Message) messages[next];
384                                                         indexLastRead = next++;
385                                                         rfcMsg = info.Reply;
386                                                         // Check this request is complete
387                                                         if (!info.acceptsReplies() && !info.hasReplies())
388                                                         {
389                                                                 // Message complete & no more replies, remove from id list
390                                                                 SupportClass.VectorRemoveElement(messages, info); // remove from list
391                                                                 info.Abandon(null, null); // Get rid of resources
392                                                                 // Start loop at next message that is now moved
393                                                                 // to the current position in the Vector.
394                                                                 i -= 1;
395                                                         }
396                                                         if (rfcMsg != null)
397                                                         {
398                                                                 // We got a reply
399                                                                 return rfcMsg;
400                                                         }
401                                                         else
402                                                         {
403                                                                 // We found no reply here
404                                                         }
405                                                 } // end for loop */
406                                                 // Messages can be removed in this loop, we we must
407                                                 // check if any messages left for this agent
408                                                 if (messages.Count == 0)
409                                                 {
410                                                         return null;
411                                                 }
412                                                 
413                                                 // No data, wait for something to come in.
414                                                 try
415                                                 {
416                                                         System.Threading.Monitor.Wait(messages);
417                                                 }
418                                                 catch (System.Threading.ThreadInterruptedException ex)
419                                                 {
420                                                 }
421                                         } /* end while */
422                                 } /* end synchronized */
423                         }
424                 }
425                 
426                 /// <summary> Debug code to print messages in message vector</summary>
427                 private void  debugDisplayMessages()
428                 {
429                         return ;
430                 }
431                 static MessageAgent()
432                 {
433                         nameLock = new System.Object();
434                 }
435         }
436 }