/****************************************************************************** * The MIT License * Copyright (c) 2003 Novell Inc. www.novell.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the Software), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. *******************************************************************************/ // // Novell.Directory.Ldap.MessageAgent.cs // // Author: // Sunil Kumar (Sunilk@novell.com) // // (C) 2003 Novell, Inc (http://www.novell.com) // using System; using Novell.Directory.Ldap.Utilclass; namespace Novell.Directory.Ldap { /* package */ class MessageAgent { private void InitBlock() { messages = new MessageVector(5, 5); } /// empty and return all messages owned by this agent /// /// /// virtual internal System.Object[] MessageArray { /* package */ get { return messages.ObjectArray; } } /// Get a list of message ids controlled by this agent /// /// /// an array of integers representing the message ids /// virtual internal int[] MessageIDs { /* package */ get { int size = messages.Count; int[] ids = new int[size]; Message info; for (int i = 0; i < size; i++) { info = (Message) messages[i]; ids[i] = info.MessageID; } return ids; } } /// Get the maessage agent number for debugging /// /// /// the agent number /// virtual internal System.String AgentName { /*packge*/ get { return name; } } /// Get a count of all messages queued virtual internal int Count { /* package */ get { int count = 0; System.Object[] msgs = messages.ToArray(); for (int i = 0; i < msgs.Length; i++) { Message m = (Message) msgs[i]; count += m.Count; } return count; } } private MessageVector messages; private int indexLastRead = 0; private static System.Object nameLock; // protect agentNum private static int agentNum = 0; // Debug, agent number private System.String name; // String name for debug /* package */ internal MessageAgent() { InitBlock(); // Get a unique agent id for debug } /// merges two message agents /// /// /// the agent to be merged into this one /// /* package */ internal void merge(MessageAgent fromAgent) { System.Object[] msgs = fromAgent.MessageArray; for (int i = 0; i < msgs.Length; i++) { messages.Add(msgs[i]); ((Message) (msgs[i])).Agent = this; } lock (messages) { if (msgs.Length > 1) { System.Threading.Monitor.PulseAll(messages); // wake all threads waiting for messages } else if (msgs.Length == 1) { System.Threading.Monitor.Pulse(messages); // only wake one thread } } return ; } /// Wakes up any threads waiting for messages in the message agent /// /// /* package */ internal void sleepersAwake(bool all) { lock (messages) { if (all) System.Threading.Monitor.PulseAll(messages); else System.Threading.Monitor.Pulse(messages); } return ; } /// Returns true if any responses are queued for any of the agent's messages /// /// return false if no responses are queued, otherwise true /// /* package */ internal bool isResponseReceived() { int size = messages.Count; int next = indexLastRead + 1; Message info; for (int i = 0; i < size; i++) { if (next == size) { next = 0; } info = (Message) messages[next]; if (info.hasReplies()) { return true; } } return false; } /// Returns true if any responses are queued for the specified msgId /// /// return false if no responses are queued, otherwise true /// /* package */ internal bool isResponseReceived(int msgId) { try { Message info = messages.findMessageById(msgId); return info.hasReplies(); } catch (System.FieldAccessException ex) { return false; } } /// Abandon the request associated with MsgId /// /// /// the message id to abandon ///

/// /// constraints associated with this request /// /* package */ internal void Abandon(int msgId, LdapConstraints cons) //, boolean informUser) { Message info = null; try { // Send abandon request and remove from connection list info = messages.findMessageById(msgId); SupportClass.VectorRemoveElement(messages, info); // This message is now dead info.Abandon(cons, null); return ; } catch (System.FieldAccessException ex) { } return ; } /// Abandon all requests on this MessageAgent /* package */ internal void AbandonAll() { int size = messages.Count; Message info; for (int i = 0; i < size; i++) { info = (Message) messages[i]; // Message complete and no more replies, remove from id list SupportClass.VectorRemoveElement(messages, info); info.Abandon(null, null); } return ; } /// Indicates whether a specific operation is complete /// /// /// true if a specific operation is complete /// /* package */ internal bool isComplete(int msgid) { try { Message info = messages.findMessageById(msgid); if (!info.Complete) { return false; } } catch (System.FieldAccessException ex) { ; // return true, if no message, it must be complete } return true; } /// Returns the Message object for a given messageID /// /// /// the message ID. /// /* package */ internal Message getMessage(int msgid) { return messages.findMessageById(msgid); } /// Send a request to the server. A Message class is created /// for the specified request which causes the message to be sent. /// The request is added to the list of messages being managed by /// this agent. /// /// /// the connection that identifies the server. ///

/// /// the LdapMessage to send ///

/// /// the interval to wait for the message to complete or /// null if infinite. /// /// the LdapMessageQueue associated with this request. /// /* package */ internal void sendMessage(Connection conn, LdapMessage msg, int timeOut, LdapMessageQueue queue, BindProperties bindProps) { // creating a messageInfo causes the message to be sent // and a timer to be started if needed. Message message = new Message(msg, timeOut, conn, this, queue, bindProps); messages.Add(message); message.sendMessage(); // Now send message to server return ; } /// Returns a response queued, or waits if none queued /// /// /* package */ // internal System.Object getLdapMessage(System.Int32 msgId) internal System.Object getLdapMessage(System.Int32 msgId) { return (getLdapMessage(new Integer32(msgId))); } internal System.Object getLdapMessage(Integer32 msgId) { System.Object rfcMsg; // If no messages for this agent, just return null if (messages.Count == 0) { return null; } if ( msgId != null) { // Request messages for a specific ID try { // Get message for this ID // Message info = messages.findMessageById(msgId); Message info = messages.findMessageById(msgId.intValue); rfcMsg = info.waitForReply(); // blocks for a response if (!info.acceptsReplies() && !info.hasReplies()) { // Message complete and no more replies, remove from id list SupportClass.VectorRemoveElement(messages, info); info.Abandon(null, null); // Get rid of resources } else { } return rfcMsg; } catch (System.FieldAccessException ex) { // no such message id return null; } } else { // A msgId was NOT specified, any message will do lock (messages) { while (true) { int next = indexLastRead + 1; Message info; for (int i = 0; i < messages.Count; i++) { if (next >= messages.Count) { next = 0; } info = (Message) messages[next]; indexLastRead = next++; rfcMsg = info.Reply; // Check this request is complete if (!info.acceptsReplies() && !info.hasReplies()) { // Message complete & no more replies, remove from id list SupportClass.VectorRemoveElement(messages, info); // remove from list info.Abandon(null, null); // Get rid of resources // Start loop at next message that is now moved // to the current position in the Vector. i -= 1; } if (rfcMsg != null) { // We got a reply return rfcMsg; } else { // We found no reply here } } // end for loop */ // Messages can be removed in this loop, we we must // check if any messages left for this agent if (messages.Count == 0) { return null; } // No data, wait for something to come in. try { System.Threading.Monitor.Wait(messages); } catch (System.Threading.ThreadInterruptedException ex) { } } /* end while */ } /* end synchronized */ } } /// Debug code to print messages in message vector private void debugDisplayMessages() { return ; } static MessageAgent() { nameLock = new System.Object(); } } }