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