The XComponent Interface

From Apache OpenOffice Wiki
Jump to: navigation, search



A central problem of reference counting systems is cyclic references. Assume Object A keeps a reference on object B and B keeps a direct or indirect reference on object A. Even if all the external references to A and B are released, the objects are not destroyed, which results in a resource leak.

Cyclic Reference
Documentation note.png In general, a Java developer does not have to be concerned about this kind of issue, as the garbage collector algorithm detects ring references. However, in the UNO world one never knows, whether object A and object B really live in the same Java virtual machine. If they do, the ring reference is really garbage collected. If they do not, the object leaks, because the Java VM is not able to inspect the object outside of the VM for its references.

In UNO, the developer must explicitly decide when to the break cyclic references. To support this concept, the interface com.sun.star.lang.XComponent exists. When an XComponent is disposed of, it can inform other objects that have expressed interest to be notified.

  // within the module com::sun::star::lang
  // when dispose() is called, previously added XEventListeners are notified
  interface XComponent: com::sun::star::uno::XInterface
  { 
       void dispose(); 
       void addEventListener( [in] XEventListener xListener ); 
       void removeEventListener( [in] XEventListener aListener ); 
  };
 
  // An XEventListener is notified by calling its disposing() method
  interface XEventListener: com::sun::star::uno::XInterface
  { 
     void disposing( [in] com::sun::star::lang::EventObject Source ); 
  };

Other objects can add themselves as com.sun.star.lang.XEventListener to an XComponent. When the dispose() method is called, the object notifies all XEventListeners through the disposing() method and releases all interface references, thus breaking the cyclic reference.

Object C calls dispose() on XComponent of Object B

A disposed object is unable to comply with its specification, so it is necessary to ensure that an object is not disposed of before calling it. UNO uses an owner/userconcept for this purpose. Only the owner of an object is allowed to call dispose and there can only be one owner per object. The owner is always free to dispose of the object. The user of an object knows that the object may be disposed of at anytime. The user adds an event listener to discover when an object is being disposed. When the user is notified, the user releases the interface reference to the object. In this case, the user should not call removeEventListener(), because the disposed object releases the reference to the user.

Documentation caution.png One major problem of the owner/user concept is that there always must be someone who calls dispose(). This must be considered at the design time of the services and interfaces, and be specified explicitly.


This solves the problem described above. However, there are a few conditions which still have to be met.

B releases all interface references, which leads to destruction of Object A, which then releases its reference to B, thus the cyclic reference is broken.

If an object is called while it is disposed of, it should behave passively. For instance, if removeListener() is called, the call should be ignored. If methods are called while the object is no longer able to comply with its interface specification, it should throw a com.sun.star.lang.DisposedException, derived from com.sun.star.uno.RuntimeException. This is one of the rare situations in which an implementation should throw a RuntimeException. The situation described above can always occur in a multithreaded environment, even if the caller has added an event listener to avoid calling objects which were disposed of by the owner.

The owner/user concept may not always be appropriate, especially when there is more than one possible owner. In these cases, there should be no owner but only users. In a multithreaded scenario, dispose() might be called several times. The implementation of an object should be able to cope with such a situation.

The XComponent implementation should always notify the disposing() listeners that the object is being destroyed, not only when dispose() is called, but when the object is deleted. When the object is deleted, the reference count of the object drops to zero. This may happen when the listeners do not hold a reference on the broadcaster object.

The XComponent does not have to be implemented when there is only one owner and no further users.

Content on this page is licensed under the Public Documentation License (PDL).
Personal tools
In other languages