1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 package com.sun.star.lib.uno.helper;
25 import com.sun.star.lang.DisposedException;
26 import com.sun.star.lang.XComponent;
27 import com.sun.star.lang.XEventListener;
28 import com.sun.star.lang.EventObject;
29 import com.sun.star.uno.Type;
30 
31 /** This class can be used as the base class for UNO components. In addition to the functionality ,which
32  *  is inherited from WeakBase, it implements com.sun.star.lang.XComponent.
33  */
34 public class ComponentBase extends WeakBase implements XComponent
35 {
36     private final boolean DEBUG= false;
37     protected MultiTypeInterfaceContainer listenerContainer;
38     protected boolean bInDispose= false;
39     protected boolean bDisposed= false;
40     static final Type  EVT_LISTENER_TYPE= new Type(XEventListener.class);
41 
42 
43     /** Creates a new instance of CompBase */
ComponentBase()44     public ComponentBase()
45     {
46         super();
47         listenerContainer= new MultiTypeInterfaceContainer();
48     }
49 
50     /** Checks whether this component (which you should have locked, prior to this call, and until you are done using) is disposed.
51       * @return whether this component is disposed
52       */
isDisposed()53     protected synchronized final boolean isDisposed() {
54         return bInDispose || bDisposed;
55     }
56 
57     /** Checks whether this component (which you should have locked, prior to this call, and until you are done using) is disposed, throwing DisposedException if it is. */
checkDisposed()58     protected synchronized final void checkDisposed() {
59         if (bInDispose || bDisposed) {
60             throw new DisposedException();
61         }
62     }
63 
64     /** Override to perform extra clean-up work. Provided for subclasses. It is
65         called during dispose()
66      */
preDisposing()67     protected void preDisposing()
68     {
69     }
70     /** Override to become notified right before the disposing action is performed.
71      */
postDisposing()72     protected void postDisposing()
73     {
74     }
75 
76 
77     /** Method of XComponent. It is called by the owning client when the component is not needed
78      *  anymore. The registered listeners are notified that this method has been called.
79      */
dispose()80     public void dispose()
81     {
82         // Determine in a thread-safe way if this is the first call to this method.
83         // Only then we proceed with the notification of event listeners.
84         // It is an error to call this method more then once.
85         boolean bDoDispose= false;
86         synchronized (this)
87         {
88             if ( ! bInDispose && ! bDisposed)
89             {
90                 bDoDispose= true;
91                 bInDispose= true;
92             }
93         }
94         // The notification occurs in an unsynchronized block in order to avoid
95         // deadlocks if one of the listeners calls back in a different thread on
96         // a synchronized method which uses the same object.
97         if (bDoDispose)
98         {
99             try
100             {
101                 preDisposing();
102                 listenerContainer.disposeAndClear(new EventObject(this));
103                 //notify subclasses that disposing is in progress
104                 postDisposing();
105             }
106             finally
107             {
108                 // finally makes sure that the  flags are set even if a RuntimeException is thrown.
109                 // That ensures that this function is only called once.
110                 synchronized (this)
111                 {
112                     bDisposed= true;
113                     bInDispose= false;
114                 }
115             }
116         }
117         else
118         {
119             // in a multithreaded environment, it can't be avoided, that dispose is called twice.
120             // However this condition is traced, because it MAY indicate an error.
121             if (DEBUG)
122                 System.out.println("OComponentHelper::dispose() - dispose called twice" );
123         }
124     }
125 
126     /** Method of XComponent.
127      */
removeEventListener(XEventListener xEventListener)128     public void removeEventListener(XEventListener xEventListener)
129     {
130         listenerContainer.removeInterface( EVT_LISTENER_TYPE, xEventListener);
131     }
132 
addEventListener(XEventListener listener)133     public void addEventListener(XEventListener listener)
134     {
135         boolean bDoDispose= false;
136         synchronized (this)
137         {
138             if (bDisposed || bInDispose)
139                 bDoDispose= true;
140             else
141                listenerContainer.addInterface(EVT_LISTENER_TYPE, listener);
142         }
143         if (bDoDispose )
144         {
145             listener.disposing( new EventObject(this));
146         }
147     }
148 
finalize()149     protected void finalize() throws Throwable
150     {
151         if ( ! bInDispose && ! bDisposed)
152             dispose();
153         super.finalize();
154     }
155 }
156