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