2017-04-02

15: To Understand the Sample UNO Extension (LibreOffice Extension or Apache OpenOffice Extension), Part Two

<The previous article in this series | The table of contents of this series | The next article in this series>

Main body START

To Know How to Handle (Read or Write) LibreOffice or Apache OpenOffice Writer or Calc Documents via Extensions from Java or Macro Programs

We Create a UNO Component

-Hypothesizer

Now, we will create a UNO component. As our UNO component is 'thebiasplanet.uno.hiunoextensionsunoextension.HiUnoExtensionsImplementation', we create a Java source file, 'source/java/thebiasplanet/uno/hiunoextensionsunoextension/HiUnoExtensionsImplementation.java', under the project directory, and write this in the file.

// # Change the package name
package thebiasplanet.uno.hiunoextensionsunoextension;

import java.util.Set;
import java.util.HashSet;
import java.util.Map;
import com.sun.star.lib.uno.helper.WeakBase;
import com.sun.star.lang.XServiceInfo;
import com.sun.star.lang.XInitialization;
import com.sun.star.uno.XComponentContext;
// # Add necessary classes and interfaces START
import com.sun.star.lang.IllegalArgumentException;
// # Add necessary classes and interfaces END

// # Change the class name
public class HiUnoExtensionsImplementation
  extends WeakBase
  implements XServiceInfo, XInitialization,
  // # Specify the UNO interface to implement
  XHiUnoExtensions {
 private static final Set <String> SERVICE_NAMES_SET = new HashSet <String> ();
 private static final Class thisClass = new Object () { }.getClass ().getEnclosingClass ();
 static {
  // # Add service names START
  SERVICE_NAMES_SET.add ("thebiasplanet.uno.hiunoextensionsunoextension.HiUnoExtensions");
  // # Add service names END
 }
 static final String [] SERVICE_NAMES_ARRAY = SERVICE_NAMES_SET.toArray (new String [SERVICE_NAMES_SET.size ()]);
 private XComponentContext componentContext = null;
 // # Add member variables START
 private String message = null;
 // # Add member variables END
 
 static void setThisClassToServicesProvider (Map <String, Object []> p_implementationClassNameToImplementationClassAndServiceNamesArrayMap) {
  p_implementationClassNameToImplementationClassAndServiceNamesArrayMap.put (thisClass.getName (), new Object [] {thisClass, SERVICE_NAMES_ARRAY});
 }
 
 // # Change the class name
 public HiUnoExtensionsImplementation (XComponentContext p_componentContext)
   throws IllegalArgumentException {
  componentContext = p_componentContext;
 }
 
 public final void initialize (java.lang.Object [] p_arguments)
   throws com.sun.star.uno.Exception {
  // # Write the initialization START
  if (p_arguments != null && p_arguments.length == 1) {
   if (p_arguments[0] instanceof String) {
    message = (String) p_arguments[0];
    if (message == null) {
     throw new IllegalArgumentException ("The first argument can't be null.");
    }
   }
   else {
    throw new IllegalArgumentException("The first argument must be a String instance.");
   }
  }
  else {
   throw new IllegalArgumentException("The number of arguments must be 1.");
  }
  // # Write the initialization END
 }
 
 // # Add methods of the implemented UNO interface START
 public String sayHi (String p_name)
   throws IllegalArgumentException {
  if (p_name == null) {
   throw new IllegalArgumentException ("The first argument can't be null.");
  }
  return String.format ("%s, %s!", message, p_name);
 }
 // # Add methods of the implemented UNO interface END
 
 // # Add other member methods START
 // # Add other member methods END
 
 public String getImplementationName () {
  return thisClass.getName ();
 }
 
 public final boolean supportsService (String p_serviceName) {
  return SERVICE_NAMES_SET.contains (p_serviceName);
 }
 
 public final String [] getSupportedServiceNames () {
  return SERVICE_NAMES_ARRAY;
 }
}
-Rebutter

Hmm, . . .

-Hypothesizer

The class extends 'com.sun.star.lib.uno.helper.WeakBase', which is a UNO helper class that has implemented interfaces, 'com.sun.star.lang.XTypeProvider' and 'com.sun.star.uno.XWeak'.

'com.sun.star.lang.XTypeProvider' is required to be implemented if our UNO component will be accessed from LibreOffice Basic macros. LibreOffice Basic macros have to know what UNO interfaces the UNO component implements through 'com.sun.star.lang.XTypeProvider'.

-Rebutter

Why do LibreOffice Basic macros have to know them while Java programs don't have to?

-Hypothesizer

Remember that the UNO proxy is created for a UNO interface. In Java, if we want a UNO proxy for another UNO interface, we have to explicitly get the UNO proxy by specifying the UNO interface. In LibreOffice Basic macros, that process is handled by the LibreOffice Basic runtime, which knows what UNO interfaces to be queried through 'com.sun.star.lang.XTypeProvider'.

-Rebutter

So, in LibreOffice Basic macros, we don't have to explicitly get UNO proxies per UNO interface.

-Hypothesizer

That's right.

As for 'com.sun.star.uno.XWeak', actually, we don't particularly need to implement it: we use that helper class because the helper class implements 'com.sun.star.lang.XTypeProvider', and there is no helper class that implements only 'com.sun.star.lang.XTypeProvider'.

-Rebutter

What is the role of 'com.sun.star.uno.XWeak'?

-Hypothesizer

When a UNO component implements 'com.sun.star.uno.XWeak', the UNO component can be referred by weak references. The weak reference is a reference to an object, that doesn't prevent the object from being garbage collected.

-Rebutter

So, if an instance of our UNO component is referred by weak references and is not referred by any normal (strong) reference, the instance will be garbage collected eventually.

-Hypothesizer

Yes.

And our UNO component implements 'com.sun.star.lang.XServiceInfo', 'com.sun.star.lang.XInitialization', and 'thebiasplanet.uno.hiunoextensionsunoextension.XHiUnoExtensions'.

Our UNO component implements 'com.sun.star.lang.XServiceInfo' because it will be registered as a UNO service. Otherwise, it doesn't have to implement 'com.sun.star.lang.XServiceInfo'.

The methods, 'getImplementationName', 'supportsService', and 'getSupportedServiceNames', are the methods of the interface.

The method, 'getImplementationName', returns the full name of the UNO component class.

The method, 'supportsService', takes a String instance, and judges whether the String instance equals one of UNO service names by which the UNO component is registered.

The method, 'getSupportedServiceNames', returns an array of UNO service names by which the UNO component is registered.

-Rebutter

The UNO component seems to be able to be registered in multiple UNO service names. Is that useful?

-Hypothesizer

I don't know. Anyway, the mechanism allows us to register the UNO component in multiple UNO service names.

-Rebutter

I see.

-Hypothesizer

As for 'com.sun.star.lang.XInitialization', when our UNO component is instantiated through a UNO service manager, the interface allows us to customize the initialization of those instances.

The method, 'initialize', is the method of the interface. When our UNO component is instantiated through a UNO service manager, the Java constructor of the UNO component is called with the component context passed as the argument. Then, the 'initialize' method is called with an array of parameters passed as the argument.

-Rebutter

Ah-ha.

-Hypothesizer

And obviously, our UNO component implements the interface, 'thebiasplanet.uno.hiunoextensionsunoextension.XHiUnoExtensions'.

-Rebutter

Of course.

-Hypothesizer

The static final members, 'SERVICE_NAMES_SET', 'thisClass', and 'SERVICE_NAMES_ARRAY', contain information that is required for the UNO component to be registered as UNO services. The information doesn't particularly have to be contained as those members: it's OK if aforementioned interfaces are implemented appropriately.

-Rebutter

We can just change the UNO service name that is added to 'SERVICE_NAMES_SET'.

-Hypothesizer

Yes.

The member, 'componentContext', contains the component context, which doesn't necessarily have to be saved in the UNO object, but in many cases, it's useful to save it there. We can get the global UNO service manager from it. So, we make it a default to save the component context passed as the argument in the Java constructor there.

-Rebutter

All right.

-Hypothesizer

The member, 'message', is a 'this UNO component'-specific member. For other UNO components, we will replace it with their necessary members.

-Rebutter

I see.

-Hypothesizer

The static method, 'setThisClassToServicesProvider', is a method that provides this UNO component's information to the 'global UNO services' provider. The information doesn't have to be provided by that method: it's OK if the 'global UNO services' provider can know what it has to know.

-Rebutter

OK.

-Hypothesizer

And the method, 'sayHi', is the method of the interface, 'thebiasplanet.uno.hiunoextensionsunoextension.XHiUnoExtensions'.

-Rebutter

That's the place where we write 'our UNO component'-specific algorithm.

Main body END

References

  • Apache OpenOffice Wiki. (2014/01/02). Apache OpenOffice Developer's Guide. Retrieved from https://wiki.openoffice.org/wiki/Documentation/DevGuide/OpenOffice.org_Developers_Guide

<The previous article in this series | The table of contents of this series | The next article in this series>