// $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 } }