Merge pull request #5714 from alexischr/update_bockbuild
[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                                 for (int i = 0; i < messages.Count; i++)
107                                 {
108                                         Message m = (Message) messages[i];
109                                         count += m.Count;
110                                 }
111                                 return count;
112                         }
113                         
114                 }
115                 private MessageVector messages;
116                 private int indexLastRead = 0;
117                 private static System.Object nameLock; // protect agentNum
118                 private static int agentNum = 0; // Debug, agent number
119                 private System.String name; // String name for debug
120                 
121                 /* package */
122                 internal MessageAgent()
123                 {
124                         InitBlock();
125                         // Get a unique agent id for debug
126                 }
127                 
128                 /// <summary> merges two message agents
129                 /// 
130                 /// </summary>
131                 /// <param name="fromAgent">the agent to be merged into this one
132                 /// </param>
133                 /* package */
134                 internal void  merge(MessageAgent fromAgent)
135                 {
136                         System.Object[] msgs = fromAgent.MessageArray;
137                         for (int i = 0; i < msgs.Length; i++)
138                         {
139                                 messages.Add(msgs[i]);
140                                 ((Message) (msgs[i])).Agent = this;
141                         }
142                         lock (messages.SyncRoot)
143                         {
144                                 if (msgs.Length > 1)
145                                 {
146                                         System.Threading.Monitor.PulseAll(messages.SyncRoot); // wake all threads waiting for messages
147                                 }
148                                 else if (msgs.Length == 1)
149                                 {
150                                         System.Threading.Monitor.Pulse(messages.SyncRoot); // only wake one thread
151                                 }
152                         }
153                         return ;
154                 }
155                 
156                 
157                 /// <summary> Wakes up any threads waiting for messages in the message agent
158                 /// 
159                 /// </summary>
160                 /* package */
161                 internal void  sleepersAwake(bool all)
162                 {
163                         lock (messages.SyncRoot)
164                         {
165                                 if (all)
166                                         System.Threading.Monitor.PulseAll(messages.SyncRoot);
167                                 else
168                                         System.Threading.Monitor.Pulse(messages.SyncRoot);
169                         }
170                         return ;
171                 }
172                 
173                 /// <summary> Returns true if any responses are queued for any of the agent's messages
174                 /// 
175                 /// return false if no responses are queued, otherwise true
176                 /// </summary>
177                 /* package */
178                 internal bool isResponseReceived()
179                 {
180                         int size = messages.Count;
181                         int next = indexLastRead + 1;
182                         Message info;
183                         for (int i = 0; i < size; i++)
184                         {
185                                 if (next == size)
186                                 {
187                                         next = 0;
188                                 }
189                                 info = (Message) messages[next];
190                                 if (info.hasReplies())
191                                 {
192                                         return true;
193                                 }
194                         }
195                         return false;
196                 }
197                 
198                 /// <summary> Returns true if any responses are queued for the specified msgId
199                 /// 
200                 /// return false if no responses are queued, otherwise true
201                 /// </summary>
202                 /* package */
203                 internal bool isResponseReceived(int msgId)
204                 {
205                         try
206                         {
207                                 Message info = messages.findMessageById(msgId);
208                                 return info.hasReplies();
209                         }
210                         catch (System.FieldAccessException ex)
211                         {
212                                 return false;
213                         }
214                 }
215                 
216                 /// <summary> Abandon the request associated with MsgId
217                 /// 
218                 /// </summary>
219                 /// <param name="msgId">the message id to abandon
220                 /// 
221                 /// </param>
222                 /// <param name="cons">constraints associated with this request
223                 /// </param>
224                 /* package */
225                 internal void  Abandon(int msgId, LdapConstraints cons)
226                 //, boolean informUser)
227                 {
228                         Message info = null;
229                         try
230                         {
231                                 // Send abandon request and remove from connection list
232                                 info = messages.findMessageById(msgId);
233                                 SupportClass.VectorRemoveElement(messages, info); // This message is now dead
234                                 info.Abandon(cons, null);
235                                 
236                                 return ;
237                         }
238                         catch (System.FieldAccessException ex)
239                         {
240                         }
241                         return ;
242                 }
243                 
244                 /// <summary> Abandon all requests on this MessageAgent</summary>
245                 /* package */
246                 internal void  AbandonAll()
247                 {
248                         int size = messages.Count;
249                         Message info;
250                         
251                         for (int i = 0; i < size; i++)
252                         {
253                                 info = (Message) messages[i];
254                                 // Message complete and no more replies, remove from id list
255                                 SupportClass.VectorRemoveElement(messages, info);
256                                 info.Abandon(null, null);
257                         }
258                         return ;
259                 }
260                 
261                 /// <summary> Indicates whether a specific operation is complete
262                 /// 
263                 /// </summary>
264                 /// <returns> true if a specific operation is complete
265                 /// </returns>
266                 /* package */
267                 internal bool isComplete(int msgid)
268                 {
269                         try
270                         {
271                                 Message info = messages.findMessageById(msgid);
272                                 if (!info.Complete)
273                                 {
274                                         return false;
275                                 }
276                         }
277                         catch (System.FieldAccessException ex)
278                         {
279                                 ; // return true, if no message, it must be complete
280                         }
281                         return true;
282                 }
283                 
284                 /// <summary> Returns the Message object for a given messageID
285                 /// 
286                 /// </summary>
287                 /// <param name="msgid">the message ID.
288                 /// </param>
289                 /* package */
290                 internal Message getMessage(int msgid)
291                 {
292                         return messages.findMessageById(msgid);
293                 }
294                 
295                 /// <summary> Send a request to the server.  A Message class is created
296                 /// for the specified request which causes the message to be sent.
297                 /// The request is added to the list of messages being managed by
298                 /// this agent.
299                 /// 
300                 /// </summary>
301                 /// <param name="conn">the connection that identifies the server.
302                 /// 
303                 /// </param>
304                 /// <param name="msg">the LdapMessage to send
305                 /// 
306                 /// </param>
307                 /// <param name="timeOut">the interval to wait for the message to complete or
308                 /// <code>null</code> if infinite.
309                 /// </param>
310                 /// <param name="queue">the LdapMessageQueue associated with this request.
311                 /// </param>
312                 /* package */
313                 internal void  sendMessage(Connection conn, LdapMessage msg, int timeOut, LdapMessageQueue queue, BindProperties bindProps)
314                 {
315                         // creating a messageInfo causes the message to be sent
316                         // and a timer to be started if needed.
317                         Message message = new Message(msg, timeOut, conn, this, queue, bindProps);
318                         messages.Add(message);
319                         message.sendMessage(); // Now send message to server
320                         return ;
321                 }
322                 
323                 /// <summary> Returns a response queued, or waits if none queued
324                 /// 
325                 /// </summary>
326                 /* package */
327 //              internal System.Object getLdapMessage(System.Int32 msgId)
328                 internal System.Object getLdapMessage(System.Int32 msgId)
329                 {
330                         return (getLdapMessage(new Integer32(msgId)));
331                 }
332
333                 internal System.Object getLdapMessage(Integer32 msgId)
334                 {
335                         System.Object rfcMsg;
336                         // If no messages for this agent, just return null
337                         if (messages.Count == 0)
338                         {
339                                 return null;
340                         }
341                         if ( msgId != null)
342                         {
343                                 // Request messages for a specific ID
344                                 try
345                                 {
346                                         // Get message for this ID
347 //                                      Message info = messages.findMessageById(msgId);
348                                         Message info = messages.findMessageById(msgId.intValue);
349                                         rfcMsg = info.waitForReply(); // blocks for a response
350                                         if (!info.acceptsReplies() && !info.hasReplies())
351                                         {
352                                                 // Message complete and no more replies, remove from id list
353                                                 SupportClass.VectorRemoveElement(messages, info);
354                                                 info.Abandon(null, null); // Get rid of resources
355                                         }
356                                         else
357                                         {
358                                         }
359                                         return rfcMsg;
360                                 }
361                                 catch (System.FieldAccessException ex)
362                                 {
363                                         // no such message id
364                                         return null;
365                                 }
366                         }
367                         else
368                         {
369                                 // A msgId was NOT specified, any message will do
370                                 lock (messages.SyncRoot)
371                                 {
372                                         while (true)
373                                         {
374                                                 int next = indexLastRead + 1;
375                                                 Message info;
376                                                 for (int i = 0; i < messages.Count; i++)
377                                                 {
378                                                         if (next >= messages.Count)
379                                                         {
380                                                                 next = 0;
381                                                         }
382                                                         info = (Message) messages[next];
383                                                         indexLastRead = next++;
384                                                         rfcMsg = info.Reply;
385                                                         // Check this request is complete
386                                                         if (!info.acceptsReplies() && !info.hasReplies())
387                                                         {
388                                                                 // Message complete & no more replies, remove from id list
389                                                                 SupportClass.VectorRemoveElement(messages, info); // remove from list
390                                                                 info.Abandon(null, null); // Get rid of resources
391                                                                 // Start loop at next message that is now moved
392                                                                 // to the current position in the Vector.
393                                                                 i -= 1;
394                                                         }
395                                                         if (rfcMsg != null)
396                                                         {
397                                                                 // We got a reply
398                                                                 return rfcMsg;
399                                                         }
400                                                         else
401                                                         {
402                                                                 // We found no reply here
403                                                         }
404                                                 } // end for loop */
405                                                 // Messages can be removed in this loop, we we must
406                                                 // check if any messages left for this agent
407                                                 if (messages.Count == 0)
408                                                 {
409                                                         return null;
410                                                 }
411                                                 
412                                                 // No data, wait for something to come in.
413                                                 try
414                                                 {
415                                                         System.Threading.Monitor.Wait(messages.SyncRoot);
416                                                 }
417                                                 catch (System.Threading.ThreadInterruptedException ex)
418                                                 {
419                                                 }
420                                         } /* end while */
421                                 } /* end synchronized */
422                         }
423                 }
424                 
425                 /// <summary> Debug code to print messages in message vector</summary>
426                 private void  debugDisplayMessages()
427                 {
428                         return ;
429                 }
430                 static MessageAgent()
431                 {
432                         nameLock = new System.Object();
433                 }
434         }
435 }