Creating any 'singleton' UNOIDL entity does not create any singleton, but a singleton getter. Then, how can any singleton be created? Here is how.
Topics
About: UNO (Universal Network Objects)
About: LibreOffice
About: Apache OpenOffice
About: Java
About: C++
About: C#
About: Python
The table of contents of this article
- Starting Context
- Target Context
- Orientation
- Main Body
- 1: Any 'singleton' UNOIDL Entity Does Not Create Any Singleton
- 2: What UNO Object Singleton Really Is
- 3: How to Create Any UNO Object Singleton
- 4: How to Get Any UNO Object Singleton
- 5: A Piece of Sample Code per Programming Language
- 6: Some Usage
Starting Context
- The reader has a knowledge on what UNO is and how it is related to LibreOffice or Apache OpenOffice.
- The reader has a knowledge on basic elements of UNO and the terminology used for them in this series.
- The reader has a knowledge on how to create and register any UNO interface and generate its mapping images.
- The reader has a knowledge on how to create any UNO component in Java, in C++, in C#, or in Python.
Target Context
- The reader will know how to create any UNO object singleton in Java, C++, C#, or Python.
Orientation
Main Body
Stage DirectionHere are Special-Student-7, Objector 69A, and Objector 69B in front of a computer.
1: Any 'singleton' UNOIDL Entity Does Not Create Any Singleton
Objector 69B
The official document tells me to create a 'singleton' UNOIDL entity, but it doesn't seem to create any singleton. What's going on?
Special-Student-7
Ah, madam, you should mean an entity like this.
@UNOIDL Source Code
#ifndef __theBiasPlanet_unoDatumTypes_heyUnoExtensions_ScolderPraiserUnoServiceSingleton_idl__
#define __theBiasPlanet_unoDatumTypes_heyUnoExtensions_ScolderPraiserUnoServiceSingleton_idl__
#include "theBiasPlanet/unoDatumTypes/heyUnoExtensions/XScolder.idl"
module theBiasPlanet {
module unoDatumTypes {
module heyUnoExtensions {
singleton ScolderPraiserUnoServiceSingleton: XScolder;
};
};
};
#endif
Objector 69B
Yes. I have created one like that, but so what? Where should I write the implementation of the singleton class? It doesn't make sense!
Special-Student-7
The official document is really lax in terminology; in this case, it does not distinguish 'singleton getter' from 'singleton'.
Objector 69B
"singleton getter"?
Special-Student-7
Any singleton is the sole instance of a class in a system; I mean that there is no other instance of the same class in the system.
Objector 69B
I know what singleton is.
Special-Student-7
Any singleton getter is something that takes out the singleton.
That UNOIDL entity creates a singleton getter, not any singleton.
The official document is really misleading, I have to say.
Objector 69B
Well, then, how can I create a singleton?
Special-Student-7
As far as I read, the official document does not say anything about it. So, let us see a way I know, although I am not sure whether that is the supposed way.
2: What UNO Object Singleton Really Is
Special-Student-7
Let us understand what any UNO object singleton really is.
Any UNO object singleton is in fact just a property of a UNO objects context.
Objector 69A
"a UNO objects context"? Which UNO objects context?
Special-Student-7
Sir, certainly, there can be multiple UNO objects contexts (which is the reason why the concept of UNO objects context has been introduced in the first place), but there is the default UNO objects context of which the other ones are descendants; I guess that a singleton is usually put into the default UNO objects context such that it is shared by all the UNO objects contexts, but there is no reason why it cannot be put only into a specific sub-lineage.
Objector 69A
Well, can it be any property?
Special-Student-7
Mechanism-wise, it can be any property if you do not persist to use a UNOIDL-based singleton getter as has been shown above. But conventionally, the property is named '/singletons/%the singleton specific name%', which can be gotten via the corresponding UNOIDL-based singleton getter.
3: How to Create Any UNO Object Singleton
Objector 69B
Then, how can I put a singleton into a UNO objects context?
Special-Student-7
That is what the official document does not seem to explain, but as any UNO objects context has implemented the 'com.sun.star.container.XNameContainer' UNO interface, we can set the property via it.
Objector 69B
Um? I thought I could not changed the UNO objects context because the '::com::sun.star::uno::XComponentContext' interface has no setter method, but there is such a way . . .
4: How to Get Any UNO Object Singleton
Special-Student-7
In order to get a UNO object singleton, you do not particularly need the UNOIDL-based getter, in fact.
Objector 69A
That should be so: it should be able to be gotten just as a property of a UNO objects context.
Special-Student-7
And I personally rather do not use UNOIDL-based singleton getters at all, because that way is not applicable to Python.
Objector 69A
Is it not?
Special-Student-7
As far as I know, as there is no existing tool that generates Python mapping images.
But we can use UNO object singletons in Python all right.
5: A Piece of Sample Code per Programming Language
Special-Student-7
This is a piece of sample code that creates, gets, and remove a UNO object singleton in Java, where 'l_underlyingRemoteUnoObjectsContext' is a UNO objects context.
@Java Source Code
import com.sun.star.container.ElementExistException;
import com.sun.star.container.NoSuchElementException;
import com.sun.star.container.XNameContainer;
import com.sun.star.lang.XUnoTunnel;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XInterface;
import theBiasPlanet.unoUtilitiesTests.localUnoObjectsTest1.TestUnoComponent;
String l_testUnoComponentSingletonUrl = "/singletons/theBiasPlanet.unoUtilitiesTests.localUnoObjectsTest1.TestUnoComponent";
// creating a singleton Start
try {
UnoRuntime.queryInterface (XNameContainer.class, l_underlyingRemoteUnoObjectsContext).insertByName (l_testUnoComponentSingletonUrl, new TestUnoComponent ());
}
catch (ElementExistException l_exception) {
}
// creating a singleton End
// getting the singleton Start
Object l_testUnoComponent = l_underlyingRemoteUnoObjectsContext.getValueByName (l_testUnoComponentSingletonUrl);
if (l_testUnoComponent instanceof XInterface) {
System.out.println (String.format ("### getSomething: %d.", UnoRuntime.queryInterface (XUnoTunnel.class, (XInterface) l_testUnoComponent).getSomething (null)));
}
else {
System.out.println (String.format ("### the singleton is not there."));
}
// getting the singleton End
// removing the singleton Start
try {
UnoRuntime.queryInterface (XNameContainer.class, l_underlyingRemoteUnoObjectsContext).removeByName (l_testUnoComponentSingletonUrl);
}
catch (NoSuchElementException l_exception) {
}
// removing the singleton End
Objector 69B
Where has 'TestUnoComponent' come from?
Special-Student-7
That is a UNO component that has come from another article. Usually, you have your own UNO component whose instance becomes the singleton, although I do not say that you cannot resister an object that has been fetched somehow otherwise as a singleton.
Objector 69B
Well.
Special-Student-7
This is a C++ piece of code, where 'l_underlyingRemoteUnoObjectsContext' is a UNO objects context.
@C++ Source Code
#include <iostream>
#include <osl/mutex.hxx>
#include <string>
#include <com/sun/star/container/ElementExistException.hpp>
#include <com/sun/star/container/NoSuchElementException.hpp>
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/lang/XUnoTunnel.hpp>
#include <com/sun/star/uno/Any.hxx>
#include <com/sun/star/uno/Reference.hxx>
#include <com/sun/star/uno/Sequence.hxx>
#include "theBiasPlanet/unoUtilities/stringsHandling/UnoExtendedStringHandler.hpp"
#include "theBiasPlanet/unoUtilitiesTests/localUnoObjectsTest1/Option4UnoComponent.hpp"
using namespace ::osl;
using namespace ::std;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::uno;
using namespace ::theBiasPlanet::unoUtilities::stringsHandling;
using namespace ::theBiasPlanet::unoUtilitiesTests::localUnoObjectsTest1;
string l_testUnoComponentSingletonUrl ("/singletons/theBiasPlanet.unoUtilitiesTests.localUnoObjectsTest1.TestUnoComponent");
// creating a singleton Start
try {
Mutex l_unoMutex;
Reference <XNameContainer> (l_underlyingRemoteUnoObjectsContext, UNO_QUERY)->insertByName (UnoExtendedStringHandler::getOustring (l_testUnoComponentSingletonUrl), Any (Reference <XUnoTunnel> (new Option4UnoComponent (l_unoMutex))));
}
catch (ElementExistException l_exception) {
}
// creating a singleton End
// getting the singleton Start
Any l_testUnoComponent (l_underlyingRemoteUnoObjectsContext->getValueByName (UnoExtendedStringHandler::getOustring (l_testUnoComponentSingletonUrl)));
if (l_testUnoComponent.hasValue ()) {
Sequence <sal_Int8> l_datumIdentification;
cout << string ("### getSomething: ") << Reference <XUnoTunnel> (* ( (Reference <XInterface> *) l_testUnoComponent.getValue ()), UNO_QUERY)->getSomething (l_datumIdentification) << endl << flush;
}
else {
cout << string ("### the singleton is not there.") << endl << flush;
}
// getting the singleton End
// removing the singleton Start
try {
Reference <XNameContainer> (l_underlyingRemoteUnoObjectsContext, UNO_QUERY)->removeByName (UnoExtendedStringHandler::getOustring (l_testUnoComponentSingletonUrl));
}
catch (NoSuchElementException l_exception) {
}
// removing the singleton End
'Option4UnoComponent' is a UNO component that has come from another article.
Objector 69B
What is 'UnoExtendedStringHandler'?
Special-Student-7
Ah . . ., 'UnoExtendedStringHandler::getOustring' is my utility method that creates a '::rtl::OUString' (which is the C++ UNO string class) instance from the specified 'string' instance; you do not need to use the method; you can just get a '::rtl::OUString' instance by your way.
Objector 69B
. . .
Special-Student-7
This is a C# piece of code, where 'l_underlyingRemoteUnoObjectsContext' is a UNO objects context.
@C# Source Code
using uno;
using unoidl.com.sun.star.lang;
using unoidl.com.sun.star.container;
using unoidl.com.sun.star.uno;
using theBiasPlanet.unoUtilitiesTests.localUnoObjectsTest1;
String l_testUnoComponentSingletonUrl = "/singletons/theBiasPlanet.unoUtilitiesTests.localUnoObjectsTest1.TestUnoComponent";
// creating a singleton Start
try {
( (XNameContainer) l_underlyingRemoteUnoObjectsContext).insertByName (l_testUnoComponentSingletonUrl, new Any (l_underlyingRemoteUnoObjectsContext.GetType (), new TestUnoComponent ()));
}
catch (ElementExistException l_exception) {
}
// creating a singleton End
// getting the singleton Start
Any l_testUnoComponent = l_underlyingRemoteUnoObjectsContext.getValueByName (l_testUnoComponentSingletonUrl);
if (l_testUnoComponent.Value != null) {
Console.Out.WriteLine (String.Format ("### getSomething: {0:d}.", ( (XUnoTunnel) l_testUnoComponent.Value).getSomething (null)));
}
else {
Console.Out.WriteLine (String.Format ("### the singleton is not there."));
}
// getting the singleton End
// removing the singleton Start
try {
( (XNameContainer) l_underlyingRemoteUnoObjectsContext).removeByName (l_testUnoComponentSingletonUrl);
}
catch (NoSuchElementException l_exception) {
}
// removing the singleton End
'TestUnoComponent' is a UNO component that has come from another article.
This is a Python piece of code, where 'l_underlyingRemoteUnoObjectsContext' is a UNO objects context.
@Python Source Code
from typing import cast
import sys
import uno
from com.sun.star.container import ElementExistException
from com.sun.star.container import NoSuchElementException
from com.sun.star.container import XNameContainer
from com.sun.star.lang import XUnoTunnel
from com.sun.star.uno import XComponentContext
from com.sun.star.uno import XInterface
from theBiasPlanet.unoUtilitiesTests.localUnoObjectsTest1.TestUnoComponent import TestUnoComponent
l_testUnoComponentSingletonUrl: str = "/singletons/theBiasPlanet.unoUtilitiesTests.localUnoObjectsTest1.TestUnoComponent"
# creating a singleton Start
try:
cast (XNameContainer, l_underlyingRemoteUnoObjectsContext).insertByName (l_testUnoComponentSingletonUrl, TestUnoComponent ())
except (ElementExistException) as l_exception:
None
# creating a singleton End
# getting the singleton Start
l_testUnoComponent: object = l_underlyingRemoteUnoObjectsContext.getValueByName (l_testUnoComponentSingletonUrl)
if l_testUnoComponent is not None:
sys.stdout.write ("### getSomething: {0:d}.\n".format (cast (XUnoTunnel, l_testUnoComponent).getSomething ([])))
else:
sys.stdout.write ("### the singleton is not there.\n")
# getting the singleton End
# removing the singleton Start
try:
cast (XNameContainer, l_underlyingRemoteUnoObjectsContext).removeByName (l_testUnoComponentSingletonUrl)
except (NoSuchElementException) as l_exception:
None
# removing the singleton End
'TestUnoComponent' is a UNO component that has come from another article.
6: Some Usage
Objector 69B
The issue is from where am I setting the singleton?
Special-Student-7
That depends totally on you.
Objector 69B
Being told "depends ~ on you", I don't want to be depended on so.
Special-Student-7
The singleton UNO object may live in the office JVM, but may live in your external Java program.
Objector 69B
Is the latter possible? I mean, the UNO object is in the external program, and a Python macro can use the UNO object in the external program as though nothing is special?
Special-Student-7
Yes; that is UNO.
But, of course, the external program has to keep being up.
Objector 69B
That is a matter of course.
Special-Student-7
So, a C# programmer who wants to write things in C# as much as possible can write a C# external UNO client that registers some singletons, and can let the C# code be used from Python macros; that way, the C# programmer cannot write macros in C#, but his or her C# code can be used from macros.
Objector 69B
Ah, the C# external client can be a Windows service, for example.
Objector 69A
Huh? But office instances may be up and down; how can the Windows service keep servicing the singletons?
Special-Student-7
The Windows service can be a connection-aware UNO client, which connects to any office instance as the office instance starts up and disconnects from the office instance when the office instance shuts down.
Objector 69A
Well, I'm a Java programmer; how can my Java singletons be set into an office instance automatically as the office instance starts up?
Special-Student-7
You can set an office-instance-startup-event-listener, which will be explained in a future article.