1 /*
2  * This file is part of the LibreOffice project.
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7  *
8  * This file incorporates work covered by the following license notice:
9  *
10  *   Licensed to the Apache Software Foundation (ASF) under one or more
11  *   contributor license agreements. See the NOTICE file distributed
12  *   with this work for additional information regarding copyright
13  *   ownership. The ASF licenses this file to you under the Apache
14  *   License, Version 2.0 (the "License"); you may not use this file
15  *   except in compliance with the License. You may obtain a copy of
16  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
17  */
18 
19 using System;
20 using unoidl.com.sun.star.lang;
21 
22 namespace uno.util
23 {
24 
25 /** This class can be used as a base class for UNO objects.
26     It implements the capability to be kept weakly
27     (unoidl.com.sun.star.uno.XWeak) and it implements
28     unoidl.com.sun.star.lang.XTypeProvider which is necessary for
29     using the object from StarBasic.
30     In addition, it implements the interface
31     unoidl.com.sun.star.lang.XComponent to be disposed explicitly.
32 */
33 public class WeakComponentBase : WeakBase, XComponent
34 {
t_disposing( EventObject evt )35     private delegate void t_disposing( EventObject evt );
36     private t_disposing m_disposing = null;
37     private bool m_inDispose = false;
38     private bool m_disposed = false;
39 
40     /** Indicates whether object is already disposed.
41 
42         @return
43                 true, if object has been disposed
44     */
isDisposed()45     protected bool isDisposed()
46     {
47         lock (this)
48         {
49             return m_disposed;
50         }
51     }
52 
53     /** Checks whether this object is disposed and throws a DisposedException
54         if it is already disposed.
55     */
checkUnDisposed()56     protected void checkUnDisposed()
57     {
58         if (! isDisposed())
59         {
60             throw new unoidl.com.sun.star.lang.DisposedException(
61                 "object already disposed!", this );
62         }
63     }
64 
~WeakComponentBase()65     ~WeakComponentBase()
66     {
67         bool doDispose;
68         lock (this)
69         {
70             doDispose = (!m_inDispose && !m_disposed);
71         }
72         if (doDispose)
73         {
74             dispose();
75         }
76     }
77 
78     /** Override to perform extra clean-up work. Provided for subclasses.
79         It is called during dispose()
80     */
preDisposing()81     protected void preDisposing()
82     {
83     }
84 
85     /** Override to become notified right before the disposing action is
86         performed.
87     */
postDisposing()88     protected void postDisposing()
89     {
90     }
91 
92     // XComponent impl
93     /** This method is called by the owner of this object to explicitly
94         dispose it.  This implementation of dispose() first notifies this object
95         via preDisposing(), then  all registered event listeners and
96         finally this object again calling postDisposing().
97     */
dispose()98     public void dispose()
99     {
100         // Determine in a thread-safe way if this is the first call to this
101         // method.  Only then we proceed with the notification of event
102         // listeners.  It is an error to call this method more than once.
103         bool doDispose = false;
104         t_disposing call = null;
105         lock (this)
106         {
107             if (! m_inDispose && !m_disposed)
108             {
109                 call = m_disposing;
110                 m_disposing = null;
111                 m_inDispose = true;
112                 doDispose = true;
113             }
114         }
115         // The notification occurs in an unsynchronized block in order to avoid
116         // deadlocks if one of the listeners calls back in a different thread on
117         // a synchronized method which uses the same object.
118         if (doDispose)
119         {
120             try
121             {
122                 // call sub class
123                 preDisposing();
124                 // send disposing notifications to listeners
125                 if (null != call)
126                 {
127                     EventObject evt = new EventObject( this );
128                     call( evt );
129                 }
130                 // call sub class
131                 postDisposing();
132             }
133             finally
134             {
135                 // finally makes sure that the flags are set ensuring
136                 // that this function is only called once.
137                 m_disposed = true;
138                 m_inDispose = false;
139             }
140         }
141         else
142         {
143             // in a multithreaded environment, it can't be avoided,
144             // that dispose is called twice.
145             // However this condition is traced, because it MAY indicate an
146             // error.
147 #if DEBUG
148             Console.WriteLine(
149                 "WeakComponentBase.dispose() - dispose called twice" );
150 #endif
151 //             Debug.Fail( "WeakComponentBase.dispose() - dispose called twice" );
152         }
153     }
154     /** Registers an event listener being notified when this object is disposed.
155 
156         @param xListener event listener
157     */
addEventListener( XEventListener xListener )158     public void addEventListener( XEventListener xListener )
159     {
160         bool add;
161         lock (this)
162         {
163             add = (! m_inDispose && !m_disposed);
164             if (add)
165                 m_disposing += new t_disposing( xListener.disposing );
166         }
167         if (! add)
168             xListener.disposing( new EventObject( this ) );
169     }
170     /** Revokes an event listener from being notified when this object
171         is disposed.
172 
173         @param xListener event listener
174     */
removeEventListener( XEventListener xListener )175     public void removeEventListener( XEventListener xListener )
176     {
177         lock (this)
178         {
179             if (! m_inDispose && !m_disposed)
180                 m_disposing -= new t_disposing( xListener.disposing );
181         }
182     }
183 }
184 
185 }
186