1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 using System;
29 using unoidl.com.sun.star.lang;
30 
31 namespace uno.util
32 {
33 
34 /** This class can be used as a base class for UNO objects.
35     It implements the capability to be kept weakly
36     (unoidl.com.sun.star.uno.XWeak) and it implements
37     unoidl.com.sun.star.lang.XTypeProvider which is necessary for
38     using the object from StarBasic.
39     In addition, it implements the interface
40     unoidl.com.sun.star.lang.XComponent to be disposed explicitly.
41 */
42 public class WeakComponentBase : WeakBase, XComponent
43 {
44     private delegate void t_disposing( EventObject evt );
45     private t_disposing m_disposing = null;
46     private bool m_inDispose = false;
47     private bool m_disposed = false;
48 
49     /** Indicates whether object is alrady disposed.
50 
51         @return
52                 true, if object has been disposed
53     */
54     protected bool isDisposed()
55     {
56         lock (this)
57         {
58             return m_disposed;
59         }
60     }
61 
62     /** Checks whether this object is disposed and throws a DisposedException
63         if it is already disposed.
64     */
65     protected void checkUnDisposed()
66     {
67         if (! isDisposed())
68         {
69             throw new unoidl.com.sun.star.lang.DisposedException(
70                 "object already disposed!", this );
71         }
72     }
73 
74     ~WeakComponentBase()
75     {
76         bool doDispose;
77         lock (this)
78         {
79             doDispose = (!m_inDispose && !m_disposed);
80         }
81         if (doDispose)
82         {
83             dispose();
84         }
85     }
86 
87     /** Override to perform extra clean-up work. Provided for subclasses.
88         It is called during dispose()
89     */
90     protected void preDisposing()
91     {
92     }
93 
94     /** Override to become notified right before the disposing action is
95         performed.
96     */
97     protected void postDisposing()
98     {
99     }
100 
101     // XComponent impl
102     /** This method is called by the owner of this object to explicitly
103         dispose it.  This implementation of dispose() first notifies this object
104         via preDisposing(), then  all registered event listeners and
105         finally this object again calling postDisposing().
106     */
107     public void dispose()
108     {
109         // Determine in a thread-safe way if this is the first call to this
110         // method.  Only then we proceed with the notification of event
111         // listeners.  It is an error to call this method more then once.
112         bool doDispose = false;
113         t_disposing call = null;
114         lock (this)
115         {
116             if (! m_inDispose && !m_disposed)
117             {
118                 call = m_disposing;
119                 m_disposing = null;
120                 m_inDispose = true;
121                 doDispose = true;
122             }
123         }
124         // The notification occures in an unsynchronized block in order to avoid
125         // deadlocks if one of the listeners calls back in a different thread on
126         // a synchronized method which uses the same object.
127         if (doDispose)
128         {
129             try
130             {
131                 // call sub class
132                 preDisposing();
133                 // send disposing notifications to listeners
134                 if (null != call)
135                 {
136                     EventObject evt = new EventObject( this );
137                     call( evt );
138                 }
139                 // call sub class
140                 postDisposing();
141             }
142             finally
143             {
144                 // finally makes sure that the flags are set ensuring
145                 // that this function is only called once.
146                 m_disposed = true;
147                 m_inDispose = false;
148             }
149         }
150         else
151         {
152             // in a multithreaded environment, it can't be avoided,
153             // that dispose is called twice.
154             // However this condition is traced, because it MAY indicate an
155             // error.
156 #if DEBUG
157             Console.WriteLine(
158                 "WeakComponentBase.dispose() - dispose called twice" );
159 #endif
160 //             Debug.Fail( "WeakComponentBase.dispose() - dispose called twice" );
161         }
162     }
163     /** Registers an event listener being notified when this object is disposed.
164 
165         @param xListener event listener
166     */
167     public void addEventListener( XEventListener xListener )
168     {
169         bool add;
170         lock (this)
171         {
172             add = (! m_inDispose && !m_disposed);
173             if (add)
174                 m_disposing += new t_disposing( xListener.disposing );
175         }
176         if (! add)
177             xListener.disposing( new EventObject( this ) );
178     }
179     /** Revokes an event listener from being notified when this object
180         is disposed.
181 
182         @param xListener event listener
183     */
184     public void removeEventListener( XEventListener xListener )
185     {
186         lock (this)
187         {
188             if (! m_inDispose && !m_disposed)
189                 m_disposing -= new t_disposing( xListener.disposing );
190         }
191     }
192 }
193 
194 }
195