2018-10-07

10: 'Hi, GUI Java UNO Clients', a Sample

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

Connecting your program to the LibreOffice/OpenOffice instance (or any UNO server), and detecting the disconnection.

Topics


About: UNO (Universal Network Objects)
About: LibreOffice
About: Apache OpenOffice
About: Java programming language

The table of contents of this article


Starting Context



Target Context


  • The reader will know how to make his or her GUI Java program connect to any UNO server (for example, a LibreOffice or Apache OpenOffice instance) and detect the disconnection (if any).
Stage Direction
Here are Hypothesizer 7, Objector 10A, and Objector 10B in front of a computer.


Orientation


Hypothesizer 7
In this article, we will get, build, execute, and understand a GUI Java UNO client sample.

In fact, there is a previous article that is of a console Java UNO client sample, and this article omits what that previous article has explained.

Objector 10A
What has the previous article explained?

Hypothesizer 7
Sir, it has explained how to make your Java program connect to any UNO server (for example, a LibreOffice or Apache OpenOffice instance).

Objector 10A
I'm not interested in making my program connect to any UNO server, but in making my program read and write an office document file.

Hypothesizer 7
Actually, you have to make your program connect to a LibreOffice or Apache OpenOffice instance whether you are interested in it or not, as is explained in a previous article.

Objector 10A
. . . So, do you demand that I make my program connect to a LibreOffice or Apache OpenOffice instance?

Hypothesizer 7
I do not personally demand that, but UNO does.

Objector 10A
Anyway, I don't understand how a UNO client's being a GUI program is different from its being a console program, UNO-wise. Being a GUI program or a console program should be just a matter of Java programming, I think.

Hypothesizer 7
As any GUI program is meant to be up for comparatively long duration, the UNO connection in it may be broken halfway.

Objector 10A
The UNO connection in any console program can be also broken halfway . . .

Hypothesizer 7
Certainly. However, as the parameters to the console program are passed as command arguments, you can just execute the command again if the console program aborted because of the UNO disconnection, while your laborious input onto the GUI program would be lost if the GUI program just aborted.

Objector 10A
Your notion of 'console program' seems to be prejudiced. There are some console programs that take input interactively.

Hypothesizer 7
Ah, you are right. However, the topic of this article is detecting the UNO disconnection as an event, and we need the UNO client to be able to receive the event. Strictly speaking, the issue is not whether the program is a GUI program or not, but whether the program is event-driven or not.

Objector 10A
I don't understand the necessity of detecting the UNO disconnection as an event: the UNO disconnection will be inevitability detected anyway when the next UNO operation is tried.

Hypothesizer 7
The issue is whether the user can continue his or her operation without his or her input lost after the disconnection.

Objector 10A
Why not? The program can just establish a new connection, and the user will be able to continue his or her operation, won't he or she?

Hypothesizer 7
The status cannot always be reconstructed that easily, can it?

Objector 10A
What do you mean by "The status"?

Hypothesizer 7
For example, the disconnection may have been caused by the LibreOffice or Apache OpenOffice instance's aborting after your program had opend a document in the instance and had acquired a UNO proxy to the document, and your program has to reconstruct that status in order for the user to be able to continue his or her operation.

Objector 10A
Hmm . . ., then, the input will be lost anyway whether the disconnection is detected as an event or not.

Hypothesizer 7
It is not 'all or nothing'; the sooner the detection is, the harm can be less: if the user is not notified of the disconnection immediately, he or she would continue his or her input that is destined to be in vain, for a long time.

Objector 10A
Hmm . . .

Objector 10B
What is that damned your 'Starting Context'?

Hypothesizer 7
Madam, 'Starting Context' is the prerequisite for understanding this article: every technical document has one whether it is explicitly stated or not (and I strongly believe that it should be stated as explicitly as practically possible).

Objector 10B
I'm saying it's too much!

Hypothesizer 7
Being told "too much", what are necessary are necessary, and I have just honestly disclosed them . . .

Objector 10B
Nobody, except you, makes such a demand on the readers!

Hypothesizer 7
. . . As I said, every technical document has its prerequisite knowledge (unless it is targeted at some newborns), and if an author had not disclose the prerequisite knowledge, he or she would have been negligent, or dishonest.


Main Body


1: Getting and Building the GUI Java UNO Client Sample


Hypothesizer 7
Here is a GUI Java UNO client sample.

'hiGuiJavaUnoClients' is the project directory of the sample program; the other two directories are of projects-common projects, which will be automatically built when you build the sample project.

How to build the sample project is described in a previous article, while how to build the development environment is described in two previous articles (here for Linux and here for Windows).

Stage Direction
Hypothesizer 7 opens a terminal and builds the sample project.


2: Executing the Sample Program


Hypothesizer 7
Before we execute the sample program, we have to have started a LibreOffice or Apache OpenOffice instance so that it accepts connections from clients, as we can know how in a previous article.

Stage Direction
Hypothesizer 7 starts a LibreOffice instance with the port number '2002'.

Hypothesizer 7
We can execute the sample program like this with the current directory positioned at the sample project directory.

@bash or cmd Source Code
gradle i_executeJarTask -Pc_mainClassName="theBiasPlanet.hiGuiJavaUnoClients.programs.HiGuiJavaUnoClients" -Pc_commandLineArguments="execution/Properties.xml"

Objector 10A
What is that XML file specified?

Hypothesizer 7
That is a configuration file from which the sample program gets some default values and the JavaFX stylesheet path.

Stage Direction
Hypothesizer 7 executes the command in the terminal with the current directory positioned at the sample project directory.

Objector 10A
What is that?

Hypothesizer 7
That is a JavaFX program which can connect to the UNO server specified by the URL, make the UNO server open the file specified by the path, and disconnect from the UNO server, while it detects any UNO disconnection.

Objector 10A
"it detects any UNO disconnection", and do what? Just its detecting surreptitiously doesn't make me believe its really detecting.

Hypothesizer 7
It changes the status that can be seen on the program: when it is connected, the 'Connect'/'Disconnect'/'Open' buttons are disabled/enabled/enabled, while when it is not connected, they are enabled/disabled/disabled.

Objector 10A
So, when I shut down the LibreOffice instance while it is connected, . . .

Hypothesizer 7
The sample program should change the status immediately, like this.

Stage Direction
Hypothesizer 7 connects the sample program to the LibreOffice instance, and then closes the LibreOffice window, but the sample program doesn't change the status.

Objector 10A
It doesn't detect anything!

Hypothesizer 7
. . . Well, the LibreOffice instance does not seem to have been terminated by just its window's being closed.

Stage Direction
Hypothesizer 7 kills the LibreOffice process, and the sample program changes the status.

Objector 10A
Ah.


3: Understanding the Sample Program



3-1: Understanding the Projects Structure


Hypothesizer 7
There are three projects: 'coreUtilitiesToBeDisclosed', 'unoUtilitiesToBeDisclosed', and 'hiGuiJavaUnoClients'. 'coreUtilitiesToBeDisclosed' contains some utility code pieces that are supposed to be commonly used in all kinds of projects; 'unoUtilitiesToBeDisclosed' contains some utility code pieces that are supposed to be commonly used in UNO program projects; 'hiGuiJavaUnoClients' is the sample project.


3-2: Registering any Listener for the UNO Disconnection Event


Hypothesizer 7
As I said in 'Orientation', I do not repeat what are explained in the previous article for the console Java UNO client sample; what is explained in this article is how to register any listener for the UNO disconnection event.

We create the UNO disconnection events listener class as an implementation of the 'com.sun.star.lang.XEventListener' interface, implementing the 'disposing' method.

The 'disposing' method has a single argument, which receives the event object of the type, 'com.sun.star.lang.EventObject'.

Objector 10A
What exactly can I get from the event object?

Hypothesizer 7
It has a member variable named 'Source', which contains the UNO bridge.

Objector 10A
Hmm . . ., that seems to be for the cases that the listener has been registered to some multiple connections.

Hypothesizer 7
I guess so.

Objector 10A
What else members?

Hypothesizer 7
Actually, there is no else.

Objector 10A
Huh? . . . Such a event usually has the cause of the disconnection, doesn't it?

Hypothesizer 7
I agree that it usually does, but this one somehow does not.

Objector 10A
. . .

Hypothesizer 7
Anyway, an instance of the listener class is registered into the UNO bridge UNO object with the 'addEventListener' method of the 'com.sun.star.lang.XComponent' UNO interface implemented by the UNO bridge UNO component.

Objector 10B
So, in the sample, which is the listener class and where is an instance of it registered?

Hypothesizer 7
Actually, 'theBiasPlanet.unoUtilities.connectionsHandling.UnoConnection' is the listener class, and it registers the instance of itself in the constructor that receives the bridge.

Objector 10B
Huh? The UNO connection's receiving the disconnection event doesn't make sense; usually, a window receives the disconnection event . . .

Hypothesizer 7
In fact, 'theBiasPlanet.unoUtilities.connectionsHandling.UnoConnection' receives the disconnection event as a proxy to such windows: some instances of 'theBiasPlanet.unoUtilities.connectionsHandling.UnoConnectionEventsListener' are registered to the instance of 'theBiasPlanet.unoUtilities.connectionsHandling.UnoConnection', which calls those listeners after it receives the disconnection event.

Objector 10B
. . . Why is such a proxy useful? It seems just vain, and you are vain of a totally useless trick . . .

Hypothesizer 7
. . . Madam, it is done for a purpose that the listeners receive also the UNO connection event, not just the UNO disconnection event, and they receive the 'theBiasPlanet.unoUtilities.connectionsHandling.UnoConnection' instance, not the UNO bridge, in the event object.

Objector 10B
. . . What is good about receiving the UNO connection event and receiving the 'theBiasPlanet.unoUtilities.connectionsHandling.UnoConnection' instance?

Hypothesizer 7
Each listener needs the UNO objects context, not the UNO bridge, in order to do its UNO operations.

Objector 10B
So? Can't I get the UNO objects context from the UNO bridge?

Hypothesizer 7
Certainly you can, but each listener has to get a reference to the UNO objects context when the UNO connection is established, and starting from the UNO bridge, each listener has to get the reference from the UNO server, while the reference is already stored in the 'theBiasPlanet.unoUtilities.connectionsHandling.UnoConnection' instance and can be gotten with a getter method.

Objector 10A
So, is 'theBiasPlanet.hiGuiJavaUnoClients.displaysHandling.HiGuiJavaUnoClientsMainScene' the listener, after all?

Hypothesizer 7
Yes, 'theBiasPlanet.unoUtilities.connectionsHandling.UnoConnectionEventsListener' is implemented by 'theBiasPlanet.unoUtilities.displaysHandling.UnoConnectionBaseScene' (which, as an abstract class, does not really implement it), which is extended by 'theBiasPlanet.unoUtilities.displaysHandling.UnoConnectionConnectorScene', which is extended by 'theBiasPlanet.hiGuiJavaUnoClients.displaysHandling.HiGuiJavaUnoClientsMainScene'.

Objector 10B
I don't understand why such a classes hierarchy is necessary (why doesn't 'theBiasPlanet.hiGuiJavaUnoClients.displaysHandling.HiGuiJavaUnoClientsMainScene' just implement 'theBiasPlanet.unoUtilities.connectionsHandling.UnoConnectionEventsListener'?). You must be vain of introducing such unnecessary classes.

Hypothesizer 7
. . . There are some purposes: 'theBiasPlanet.unoUtilities.displaysHandling.UnoConnectionBaseScene' is for containing the common logics for 'theBiasPlanet.unoUtilities.displaysHandling.UnoConnectionConnectorScene' (a base UNO client scene) and 'theBiasPlanet.unoUtilities.displaysHandling.UnoConnectionAcceptorScene' (a base UNO server scene); 'theBiasPlanet.unoUtilities.displaysHandling.UnoConnectionConnectorScene' is for containing the common logics for various UNO client scenes (of which, 'theBiasPlanet.hiGuiJavaUnoClients.displaysHandling.HiGuiJavaUnoClientsMainScene' is one).

Objector 10B
You are vain! You are vain! You are vain!

Hypothesizer 7
. . . The interface, 'theBiasPlanet.unoUtilities.connectionsHandling.UnoConnectionEventsListener', has two methods: 'connected' and 'disconnected', which each listener is supposed to implement (as 'theBiasPlanet.unoUtilities.displaysHandling.UnoConnectionConnectorScene' has already implemented the interface, strictly speaking, any descendant of 'theBiasPlanet.unoUtilities.displaysHandling.UnoConnectionConnectorScene' does not have to implement it although the descendant will usually have some extra things to do in the methods).


4: The Conclusion and Beyond


Hypothesizer 7
Now, we can make our GUI Java UNO client decently take some actions against any UNO disconnection.

You are not any Java programmer? We will create some UNO clients in some other program languages (C++ and C#) in future articles.

And we will create also some UNO servers in future articles.


References


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