/******************************************************************************
* 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();
}
}
}