b30d33ecd109cec2ac0c351d767062ef25e196d1
[mono.git] / mcs / class / RabbitMQ.Client / src / client / impl / SessionBase.cs
1 // This source code is dual-licensed under the Apache License, version
2 // 2.0, and the Mozilla Public License, version 1.1.
3 //
4 // The APL v2.0:
5 //
6 //---------------------------------------------------------------------------
7 //   Copyright (C) 2007-2009 LShift Ltd., Cohesive Financial
8 //   Technologies LLC., and Rabbit Technologies Ltd.
9 //
10 //   Licensed under the Apache License, Version 2.0 (the "License");
11 //   you may not use this file except in compliance with the License.
12 //   You may obtain a copy of the License at
13 //
14 //       http://www.apache.org/licenses/LICENSE-2.0
15 //
16 //   Unless required by applicable law or agreed to in writing, software
17 //   distributed under the License is distributed on an "AS IS" BASIS,
18 //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 //   See the License for the specific language governing permissions and
20 //   limitations under the License.
21 //---------------------------------------------------------------------------
22 //
23 // The MPL v1.1:
24 //
25 //---------------------------------------------------------------------------
26 //   The contents of this file are subject to the Mozilla Public License
27 //   Version 1.1 (the "License"); you may not use this file except in
28 //   compliance with the License. You may obtain a copy of the License at
29 //   http://www.rabbitmq.com/mpl.html
30 //
31 //   Software distributed under the License is distributed on an "AS IS"
32 //   basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
33 //   License for the specific language governing rights and limitations
34 //   under the License.
35 //
36 //   The Original Code is The RabbitMQ .NET Client.
37 //
38 //   The Initial Developers of the Original Code are LShift Ltd,
39 //   Cohesive Financial Technologies LLC, and Rabbit Technologies Ltd.
40 //
41 //   Portions created before 22-Nov-2008 00:00:00 GMT by LShift Ltd,
42 //   Cohesive Financial Technologies LLC, or Rabbit Technologies Ltd
43 //   are Copyright (C) 2007-2008 LShift Ltd, Cohesive Financial
44 //   Technologies LLC, and Rabbit Technologies Ltd.
45 //
46 //   Portions created by LShift Ltd are Copyright (C) 2007-2009 LShift
47 //   Ltd. Portions created by Cohesive Financial Technologies LLC are
48 //   Copyright (C) 2007-2009 Cohesive Financial Technologies
49 //   LLC. Portions created by Rabbit Technologies Ltd are Copyright
50 //   (C) 2007-2009 Rabbit Technologies Ltd.
51 //
52 //   All Rights Reserved.
53 //
54 //   Contributor(s): ______________________________________.
55 //
56 //---------------------------------------------------------------------------
57 using System;
58
59 using RabbitMQ.Client;
60 using RabbitMQ.Client.Events;
61 using RabbitMQ.Client.Exceptions;
62
63 namespace RabbitMQ.Client.Impl
64 {
65     public abstract class SessionBase: ISession
66     {
67         private CommandHandler m_commandReceived;
68
69         private readonly object m_shutdownLock = new object();
70         private SessionShutdownEventHandler m_sessionShutdown;
71         public ShutdownEventArgs m_closeReason = null;
72
73         public readonly ConnectionBase m_connection;
74         public readonly int m_channelNumber;
75
76         public SessionBase(ConnectionBase connection, int channelNumber)
77         {
78             m_connection = connection;
79             m_channelNumber = channelNumber;
80             if (channelNumber != 0)
81                 connection.ConnectionShutdown +=
82                     new ConnectionShutdownEventHandler(this.OnConnectionShutdown);
83         }
84
85         public virtual void OnCommandReceived(Command cmd)
86         {
87             CommandHandler handler = CommandReceived;
88             if (handler != null)
89             {
90                 handler(this, cmd);
91             }
92         }
93
94         public virtual void OnConnectionShutdown(IConnection conn, ShutdownEventArgs reason)
95         {
96             Close(reason);
97         }
98
99         public virtual void OnSessionShutdown(ShutdownEventArgs reason)
100         {
101             //Console.WriteLine("Session shutdown "+ChannelNumber+": "+reason);
102             m_connection.ConnectionShutdown -=
103                 new ConnectionShutdownEventHandler(this.OnConnectionShutdown);
104             SessionShutdownEventHandler handler;
105             lock (m_shutdownLock)
106             {
107                 handler = m_sessionShutdown;
108                 m_sessionShutdown = null;
109             }
110             if (handler != null)
111             {
112                 handler(this, reason);
113             }
114         }
115
116         public override string ToString()
117         {
118             return this.GetType().Name+"#" + m_channelNumber + ":" + m_connection;
119         }
120
121         //---------------------------------------------------------------------------
122         // ISession implementation
123
124         public CommandHandler CommandReceived
125         {
126             get { return m_commandReceived; }
127             set { m_commandReceived = value; }
128         }
129
130         public event SessionShutdownEventHandler SessionShutdown
131         {
132             add
133             {
134                 bool ok = false;
135                 lock (m_shutdownLock)
136                 {
137                     if (m_closeReason == null)
138                     {
139                         m_sessionShutdown += value;
140                         ok = true;
141                     }
142                 }
143                 if (!ok)
144                 {
145                     value(this, m_closeReason);
146                 }
147             }
148             remove
149             {
150                 lock (m_shutdownLock)
151                 {
152                     m_sessionShutdown -= value;
153                 }
154             }
155         }
156
157         public int ChannelNumber { get { return m_channelNumber; } }
158
159         IConnection ISession.Connection { get { return m_connection; } }
160         public ConnectionBase Connection { get { return m_connection; } }
161
162         public ShutdownEventArgs CloseReason { get { return m_closeReason; } }
163
164         public bool IsOpen { get { return m_closeReason == null; } }
165
166         public abstract void HandleFrame(Frame frame);
167
168         public virtual void Transmit(Command cmd)
169         {
170             lock (m_shutdownLock)
171             {
172                 if (m_closeReason != null)
173                 {
174                     if (!m_connection.Protocol.CanSendWhileClosed(cmd))
175                             throw new AlreadyClosedException(m_closeReason);
176                 }
177                 // We transmit *inside* the lock to avoid interleaving
178                 // of frames within a channel.
179                 cmd.Transmit(m_channelNumber, m_connection);
180             }
181         }
182
183         public void Close(ShutdownEventArgs reason)
184         {
185             Close(reason, true);
186         }
187         
188         public void Close(ShutdownEventArgs reason, bool notify)
189         {
190             lock (m_shutdownLock)
191             {
192                 if (m_closeReason == null)
193                 {
194                     m_closeReason = reason;
195                 }
196             }
197             if (notify)
198                 OnSessionShutdown(m_closeReason);
199         }
200         
201         public void Notify()
202         {
203             // Ensure that we notify only when session is already closed
204             // If not, throw exception, since this is a serious bug in the library
205             lock (m_shutdownLock)
206             {
207                     if (m_closeReason == null)
208                     throw new Exception("Internal Error in Session.Close");     
209             }
210             OnSessionShutdown(m_closeReason);
211         }
212     }
213 }