<The previous article in this series | The table of contents of this series | The next article in this series>
To Know How to Handle (Read or Write) LibreOffice or Apache OpenOffice Writer or Calc Documents via Extensions from Java or Macro Programs
Proceeding to the item, No. 6, in order to create a UNO old-style service, we create two UNO interfaces, 'thebiasplanet.uno.hiunoextensionsunoextension.XScolder' and 'thebiasplanet.uno.hiunoextensionsunoextension.XPraiser'.
The UNO old-style service is a UNO service of a UNO component that implements multiple UNO interfaces, right?
Strictly speaking, the UNO new-style service also implements multiple UNO interfaces including 'com.sun.star.lang.XServiceInfo'. The UNO old-style service implements multiple UNO interfaces that are meant to be directly used by users of the UNO old-style service.
I see.
In the UNO data types project, we create UNOIDL files, 'unoIdl/thebiasplanet/uno/heyunoextensionsunoextension/XScolder.idl' and 'unoIdl/thebiasplanet/uno/heyunoextensionsunoextension/XPraiser.idl' under the 'source' directory, and write these in them.
// # Change the defined variable name START
#ifndef __thebiasplanet_uno_hiunoextensionsunoextension_XScolder_idl__
#define __thebiasplanet_uno_hiunoextensionsunoextension_XScolder_idl__
// # Change the defined variable name END
#include <com/sun/star/uno/XInterface.idl>
// # Add necessary idls START
#include <com/sun/star/lang/IllegalArgumentException.idl>
// # Add necessary idls END
// # Change the module name
module thebiasplanet { module uno { module heyunoextensionsunoextension {
// # Change the interface name and the parent interface
interface XScolder: com::sun::star::uno::XInterface
{
// # Add methods START
string scold ( [in] string p_name)
raises (com::sun::star::lang::IllegalArgumentException);
// # Add methods END
};
}; }; };
#endif
// # Change the defined variable name START
#ifndef __thebiasplanet_uno_hiunoextensionsunoextension_XPraiser_idl__
#define __thebiasplanet_uno_hiunoextensionsunoextension_XPraiser_idl__
// # Change the defined variable name END
#include <com/sun/star/uno/XInterface.idl>
// # Add necessary idls START
#include <com/sun/star/lang/IllegalArgumentException.idl>
// # Add necessary idls END
// # Change the module name
module thebiasplanet { module uno { module heyunoextensionsunoextension {
// # Change the interface name and the parent interface
interface XPraiser: com::sun::star::uno::XInterface
{
// # Add methods START
string praise ( [in] string p_name)
raises (com::sun::star::lang::IllegalArgumentException);
// # Add methods END
};
}; }; };
#endif
Ah-ha.
Then, in the UNO extension project, we create a UNO component Java source file, 'java/thebiasplanet/uno/heyunoextensionsunoextension/ScolderPraiserUnoComponent.java', and write this in it.
// # Change the package name
package thebiasplanet.uno.heyunoextensionsunoextension;
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 java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import com.sun.star.lang.IllegalArgumentException;
import thebiasplanet.coreutilities.messaging.Publisher;
// # Add necessary classes and interfaces END
// # Change the class name
public class ScolderPraiserUnoComponent
extends WeakBase
implements XServiceInfo, XInitialization,
// # Specify the UNO interface to implement
XScolder, XPraiser {
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.heyunoextensionsunoextension.ScolderPraiserService");
// # 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_unoComponentClassNameToUnoComponentClassAndServiceNamesArrayMap) {
p_unoComponentClassNameToUnoComponentClassAndServiceNamesArrayMap.put (thisClass.getName (), new Object [] {thisClass, SERVICE_NAMES_ARRAY});
}
// # Change the class name
public ScolderPraiserUnoComponent (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.format ("%s (%d %s)", (String) p_arguments[0], System.identityHashCode (this), DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").format (LocalDateTime.now()));
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 scold (String p_name)
throws IllegalArgumentException {
if (p_name == null) {
throw new IllegalArgumentException ("The first argument can't be null.");
}
return String.format ("Don't do that! %s, %s!", message, p_name);
}
public String praise (String p_name)
throws IllegalArgumentException {
if (p_name == null) {
throw new IllegalArgumentException ("The first argument can't be null.");
}
return Publisher.getMessage (String.format ("Wonderful! %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;
}
}
Um, it implements those two UNO interfaces.
Then, we add the UNO old-style service into the 'global UNO services' provider, 'thebiasplanet.uno.heyunoextensionsunoextension.HeyUnoExtensionsUnoExtensionGlobalServicesProvider'. In the static block, we add this.
ScolderPraiserUnoComponent.setThisClassToServicesProvider (UNO_COMPONENT_CLASS_NAME_TO_UNO_COMPONENT_CLASS_AND_SERVICE_NAMES_ARRAY_MAP);
OK.
Then, we add this code into the UNO components setting file to set the third UNO component.
<implementation name="thebiasplanet.uno.heyunoextensionsunoextension.ScolderPraiserUnoComponent">
<!-- # Add service names -->
<service name="thebiasplanet.uno.heyunoextensionsunoextension.ScolderPraiserService"/>
</implementation>
OK.
We create a 'global UNO service' instances factory for the UNO old-style service.
In the UNO data types project, we create a UNOIDL file, 'unoIdl/thebiasplanet/uno/heyunoextensionsunoextension/ScolderPraiserService.idl' under the 'source' directory, and write this in it.
// # Change the defined variable name START
#ifndef __thebiasplanet_uno_heyunoextensionsunoextension_ScolderPraiserService_idl__
#define __thebiasplanet_uno_heyunoextensionsunoextension_ScolderPraiserService_idl__
// # Change the defined variable name END
// # Change the interface idl
#include "thebiasplanet/uno/heyunoextensionsunoextension/XScolder.idl"
// # Change the module name
module thebiasplanet { module uno { module heyunoextensionsunoextension {
// # Change the service name and the interface name
service ScolderPraiserService: XScolder {
// # Add constructors START
create1 ( [in] string p_message)
raises (com::sun::star::lang::IllegalArgumentException);
// # Add constructors END
};
}; }; };
#endif
Um, we specified one of the two UNO interfaces, 'thebiasplanet.uno.hiunoextensionsunoextension.XScolder'.
Yes. That determines the return type of all of the factory methods. We can't specify the return type per factory method.
Ah-ha. So, we can create the 'global UNO service' instances factory for the UNO old-style service, just by choosing a UNO interface to be used as the return type of the factory methods.
That's right.
Now, we can build the UNO data types project, and build and register the UNO extension.
They have been built and registered successfully.
To test that we can create instances of the UNO old-style service by the 'global UNO service' instances factory, we add this code at the last of the previous LibreOffice Basic Sub.
Dim l_scolderPraiserService1 As Variant
l_scolderPraiserService1 = thebiasplanet.uno.heyunoextensionsunoextension.ScolderPraiserService.create1 ("Well")
Msgbox (l_scolderPraiserService1.scold ("guys"))
Msgbox (l_scolderPraiserService1.praise ("guys"))
The Sub worked as expected.
Thus, we have demonstrated how we can create a UNO old-style service, create a 'global UNO service' instances factory for the UNO old-style service, and create instances of the UNO old-style service by the 'global UNO service' instances factory.
Let's proceed to the item, No. 7. When we have a UNO proxy for a UNO object in another language environment, in order to get a UNO proxy of another UNO interface of the same UNO object, we have to use the 'UnoRuntime.queryInterface' method. However, when we get a reference to a UNO object in the language environment of our code, the reference isn't to a UNO proxy, but to the original UNO object. So, we can just cast the reference to another UNO interface without using the 'UnoRuntime.queryInterface' method.
That sounds reasonable.
In the UNO data types project, we modify the UNOIDL file, 'unoIdl/thebiasplanet/uno/heyunoextensionsunoextension/XHeyUnoExtensions.idl' and add a method, 'getInnerPraiser' like this.
XPraiser getInnerPraiser ( [in] string p_message)
raises (com::sun::star::lang::IllegalArgumentException);
This method creates an instance of the aforementioned old-style UNO service, and return the instance in the type, 'thebiasplanet.uno.heyunoextensionsunoextension.XPraiser'.
I see.
Then, in the UNO extension project, we implement the method in the UNO component, 'thebiasplanet.uno.heyunoextensionsunoextension.HeyUnoExtensionsUnoComponent', like this.
public XPraiser getInnerPraiser (String p_message)
throws IllegalArgumentException {
XScolder l_innerScolderPraiser1 = null;
XPraiser l_innerScolderPraiser2 = null;
try {
l_innerScolderPraiser1 = ScolderPraiserService.create1 (componentContext, p_message);
l_innerScolderPraiser2 = (XPraiser) l_innerScolderPraiser1;
}
catch (IllegalArgumentException l_exception) {
throw l_exception;
}
return l_innerScolderPraiser2;
}
The 'global UNO service' instances factory for the UNO old-style service returns the instance of the old-style UNO service in the type, 'thebiasplanet.uno.heyunoextensionsunoextension.XScolder', and the instance is directly cast to the UNO interface, 'thebiasplanet.uno.heyunoextensionsunoextension.XPraiser', by the Java cast.
Yes.
Let's build the UNO data types project, and build and register the UNO extension.
To test, we add this code at the last of the previous LibreOffice Basic Sub.
Dim l_scolderPraiserService2 As Variant
l_scolderPraiserService2 = l_heyUnoExtensionsService.getInnerPraiser ("Well")
Msgbox (l_scolderPraiserService2.scold ("guys"))
Msgbox (l_scolderPraiserService2.praise ("guys"))
Ah-ha, it works fine.
Thus, we have demonstrated that we can directly cast an instance of a made-in-Java UNO object into a UNO interface without using the 'UnoRuntime.queryInterface' method.
<The previous article in this series | The table of contents of this series | The next article in this series>