lifetime of UNO objects, writing Java exception-safe code

Lionel Elie Mamane lionel at mamane.lu
Fri Sep 13 02:07:38 PDT 2013


On Wed, Sep 11, 2013 at 12:35:15PM +0200, Stephan Bergmann wrote:

> First, note that we don't have reference-counting garbage collection
> in general in UNO.  For example, Java-UNO doesn't use
> reference-counting.

> Second, note that there needs to be code (the "owner" in the jargon
> of the udkapi/com/sun/star/lang/XComponent.idl documentation) that
> explicitly calls dispose on a UNO object.  It is not magically
> called when a UNO object becomes unreachable.

So let's take the concrete example of
 reportbuilder/java/org/libreoffice/report/SDBCReportDataFactory.java
 around line 233:
 private String getOrderStatement(final int commandType, final String command, final List sortExpressions)

It makes use of

 ::com::sun::star::container::XNameAccess
 com.sun.star.sdb.tools.XConnectionTools.getFieldsByCommandDescriptor(
   [in] long commandType,
   [in] string command,
   [out] ::com::sun::star::lang::XComponent	keepFieldsAlive)

The documentation of this
http://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1sdb_1_1tools_1_1XConnectionTools.html#ab96cfd3f9e8facbd9ebe98aa41a684fd
says:
parameter keepFieldsAlive
  the fields collection which is returned by this function here is a
  temporary object. It is kept alive by another object, which is to be
  created temporarily, too. To ensure that the fields you get are
  valid as long as you need them, the owner which controls their life
  time is transfered to this parameter upon return.

  Your fields live as long as this component lives.

  Additionally, you are encouraged to dispose this component as soon as
  you don't need the fields anymore. It depends on the connection's
  implementation if this is necessary, but the is no guarantee, so to be
  on the safe side with respect to resource leaks, you should dispose
  the component.


Concretely, the Java code does:

  final XComponent[] hold = new XComponent[1];
  final XNameAccess columns = getFieldsByCommandDescriptor(commandType, command, hold);

I assume this whole rigmarole with "hold" is to ensure that
"dispose()" is called on "columns", providing an owner for it.
(I assume it uses this round-about way instead of just declaring the
 caller the owner of columns because in some conditions columns will be
 a temporary and in other conditions, it will not; with this setup,
 this is testable with (hold[0] == null)).

So, now the question: I assume that hold[0] itself needs to be
disposed so that it calls dispose on columns. I need to do that in an
exception-safe way, that is even if this function exits by an uncaught
exception.

So I need to do something like:

  final XComponent[] hold = new XComponent[1];
  try
  {
    (...)
    final XNameAccess columns = getFieldsByCommandDescriptor(commandType, command, hold);
    (...)
    if(hold[0] != null)
       hold[0].dispose();
  }
  catch (SQLException ex)
  {
     if(hold[0] != null)
       hold[0].dispose();
     LOGGER.error("ReportProcessing failed", ex);
  }
  catch(java.lang.Exception e)
  {
    if(hold[0] != null)
      hold.dispose();
    throw e;
  }


Did I understand what you were saying correctly? This function (and
_any_ code getting a fresh/temporary UNO object) needs to clean up
after itself manually in this pedestrian, error-prone way? Do we get a
cop-out in C++ because of the use of com::sun::star::uno::Reference
which calls _pInterface->release()? Do we get a cop-out in any other
UNO language? (Python? Basic?)

In the above Java example, it wants me to add "throws Exception"
before it compiles that. I'm confused because usually it won't let me
put a catch clause if the body of the try cannot possibly throw that
exception, but here it lets me but the catch clause. So there must be
some way that the body of the try throws an Exception (other than
SQLException), but then why does it let me get away without the
"throws Exception" in the current version of the code?

Is there any way to make the clean-up completely exception-safe, but
without mucking with Exception specifiers (with, I assume, domino
effect on all the code that will suddenly need "throws Exception")?

-- 
Lionel


More information about the LibreOffice mailing list