// $Id$
//
// Copyright 2007-2008 Cisco Systems Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
using System;
using System.Collections.Generic;
using Etch.Msg;
using Etch.Support;
using Etch.Util;
namespace Etch.Transport
{
///
/// MailboxManager is a MessageHandler which accepts packets for
/// possible delivery to a mailbox, or to another message handler
/// if an appropriate mailbox cannot be found. MailboxManager is
/// forwarding them to another MessageSource. If requested, a
/// mailbox is created with a message's msgid and added to the
/// set of mailboxes waiting for messages.
///
public class PlainMailboxManager : MailboxManager
{
///
/// Constructs the PlainMailboxManager.
///
/// a transport to send messages
/// the uri of this transport stack
/// the resources of this transport stack
public PlainMailboxManager(TransportMessage transport, string uri, Resources resources)
: this(transport, new URL(uri), resources)
{
// nothing else.
}
///
/// Constructs the PlainMailboxManager.
///
/// a transport to send messages
/// the uri of this transport stack
/// the resources of this transport stack
public PlainMailboxManager(TransportMessage transport, URL uri, Resources resources)
{
this.transport = transport;
transport.SetSession(this);
}
private readonly TransportMessage transport;
public override string ToString()
{
return String.Format( "PlainMailboxManager/{0} ", transport );
}
private readonly IdGenerator idGen = new IdGenerator( DateTime.Now.Ticks, 37 );
/////////////////////
// Mailbox methods //
/////////////////////
private Dictionary mailboxes =
new Dictionary();
///
/// Adds a mailbox to the set of mailbox receiving responses
/// to messages.
///
///
public void Register( Mailbox mb )
{
long msgid = mb.GetMessageId();
lock (mailboxes)
{
if (!up)
throw new InvalidOperationException("connection down");
if (mailboxes.ContainsKey( msgid ))
throw new ArgumentException( "dup msgid in mailboxes" );
mailboxes.Add( msgid, mb );
}
}
public void Unregister( Mailbox mb )
{
lock ( mailboxes )
{
mailboxes.Remove( mb.GetMessageId() );
}
}
private Mailbox GetMailbox( long msgid )
{
lock ( mailboxes )
{
return mailboxes[msgid];
}
}
public void Redeliver( Who sender, Message msg )
{
session.SessionMessage(sender, msg);
}
public Object SessionQuery( Object query )
{
return session.SessionQuery( query );
}
public void SessionControl( Object control, Object value )
{
session.SessionControl( control, value );
}
public void SessionNotify( Object eventObj )
{
if(eventObj.Equals(SessionConsts.UP))
{
up = true;
}
else if (eventObj.Equals(SessionConsts.DOWN))
{
up = false;
UnRegisterAll();
}
session.SessionNotify(eventObj);
}
private bool up;
public Object TransportQuery( Object query )
{
return transport.TransportQuery( query );
}
public void TransportControl( Object control, Object value )
{
transport.TransportControl( control, value );
}
public void TransportNotify( Object eventObj )
{
transport.TransportNotify( eventObj );
}
public void UnRegisterAll()
{
Mailbox[] mbs;
lock (mailboxes)
{
mbs = new Mailbox[mailboxes.Values.Count];
mailboxes.Values.CopyTo(mbs, 0);
}
foreach (Mailbox mb in mbs)
{
mb.CloseDelivery();
}
}
#region SessionMessage Members
public bool SessionMessage(Who sender, Message msg)
{
long? msgid = msg.InReplyTo;
if (msgid != null)
{
Mailbox mb;
try
{
mb = GetMailbox(msgid.Value);
}
catch
{
mb = null;
}
if (mb != null)
{
try
{
return mb.Message(sender, msg);
}
catch (Exception)
{
// timeout or mailbox closed - fall through
}
}
// no such mailbox - fall through
return false;
}
// no such mailbox or no msgid - fall through
return session.SessionMessage(sender, msg);
}
#endregion
#region MailboxManager Members
public Mailbox TransportCall(Who recipient, Message msg)
{
if (msg.MessageId != null)
throw new Exception(" message has already been sent");
if (msg.InReplyTo != null)
throw new Exception(" message is marked as a reply");
long mid = idGen.Next();
msg.MessageId = mid;
Mailbox mb = new PlainMailbox(this, mid);
Register(mb);
try
{
transport.TransportMessage(recipient, msg);
}
catch(Exception e)
{
Unregister(mb);
throw e;
}
return mb;
}
#endregion
#region TransportMessage Members
public void TransportMessage(Who recipient, Message msg)
{
transport.TransportMessage(recipient,msg);
}
#endregion
#region Transport Members
public void SetSession(SessionMessage session)
{
this.session = session;
}
public SessionMessage GetSession()
{
return this.session;
}
private SessionMessage session;
#endregion
}
}