2022年7月31日日曜日

69: LibreOffice/OpenOffice内に任意のUNOオブジェクトシングルトンを作成する

<このシリーズの前の記事 | このシリーズの目次 | このシリーズの次の記事>

'singleton' UNOIDLエンティティを作成しても、シングルトンは作成されず、シングルトンgetterが作られるだけです。それでは、シングルトンはどうすれば作成できるのか?ここにその方法があります。

話題


About: UNO (Universal Network Objects)
About: LibreOffice
About: Apache OpenOffice
About: Java
About: C++
About: C#
About: Python

この記事の目次


開始コンテキスト



ターゲットコンテキスト



  • 読者は、任意のUNOオブジェクトシングルトンを、Java、C++、C#、Pythonで作成する方法を知る。

オリエンテーション


  • LibreOfficeまたはApache OpenOfficeインスタンスをUNOサーバーにする方法の記事があります。
  • コネクションアウェアでない、JavaC++C#Python外部UNOクライアントを作成する方法の記事があります。
  • コネクションアウェアな、JavaC++C#Python外部UNOクライアントを作成することについての記事があります。
  • 任意のJava UNOサービスを作成する方法の記事があります。

  • 本体

    ト書き
    Special-Student-7、Objector 69A、Objector 69Bがコンピュータの前にいる。


    1: 'singleton' UNOIDLエンティティはシングルトンを作成しない


    Objector 69B
    オフィシャルドキュメントは'singleton' UNOIDLエンティティを作成せよと言ってるけど、それってシングルトンなんか作成してないようなのよね。どうなってるの?

    Special-Student-7
    ああ、マダム、以下のようなエンティティのことを言われてますよね。

    @UNOIDL ソースコード
    #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
    ええ。そんなやつを作ったんだけど、それでどうなるの?シングルトンクラスの実装はどこに書けばいいわけ?意味わからない!

    Special-Student-7
    オフィシャルドキュメントは実に用語体系がゆるんでいます。この場合、それは、'シングルトンgetter'を'シングルトン'から区別していません。

    Objector 69B
    "シングルトンgetter"?

    Special-Student-7
    任意のシングルトンは、あるシステム内におけるあるクラスの唯一インスタンスです。つまり、そのシステム内にその同一クラスの別インスタンスはないということです。

    Objector 69B
    シングルトンが何かは知ってるわよ。

    Special-Student-7
    任意のシングルトンgetterは、そのシングルトンを取り出すものです。

    そのUNOIDLエンティティは、シングルトンgetterを作成するのであって、何らのシングルトンも作成しません。

    オフィシャルドキュメントは本当に誤解を招くものです、と言わざるを得ません。

    Objector 69B
    えーと、それじゃあ、私はどうすればシングルトンを作成できるわけ?

    Special-Student-7
    私が読む限りでは、オフィシャルドキュメントはそれについて何も言いません。そこで、私が知っている方法を見ましょう、それが想定されている方法なのか私には定かではありませんが。


    2: UNOオブジェクトシングルトンとは本当には何であるか


    Special-Student-7
    任意のUNOオブジェクトシングルトンは本当には何であるかを理解しましょう。

    任意のUNOオブジェクトシングルトンは、実のところ、単に、あるUNOオブジェクト群コンテキストの1プロパティです。 .

    Objector 69A
    "あるUNOオブジェクト群コンテキスト"?どのUNOオブジェクト群コンテキストだ?

    Special-Student-7
    サー、確かに、複数のUNOオブジェクト群コンテキストがあり得ます(それが、UNOオブジェクト群コンテキストというコンセプトが導入されたそもそもの理由です)が、1つのデフォルトUNOオブジェクト群コンテキストがあり、他のものはそれの派生であって、おそらくは、シングルトンは、通常はデフォルトUNOオブジェクト群コンテキストへ入れられ、全てのUNOオブジェクト群コンテキストに共有されることになりますが、ある特定の系統にのみへ入れられることはできないという理由はありません。

    Objector 69A
    えーと、どんなプロパティでもいいのかね?

    Special-Student-7
    メカニズム上は、どんなプロパティでもかまいません、もしも、上に記されたようなUNOIDLベースシングルトンgetterを用いることに固執されないのでしたら。しかし、慣習として、プロパティは/singletons/%the singleton specific name%'と名付けられ、それは、対応するUNOIDLベースシングルトンgetterを介して取得できます。


    3: 任意のUNOオブジェクトシングルトンを作成するの方法


    Objector 69B
    それで、どうすれば私はシングルトンをUNOオブジェクト群コンテキストへ入れられるの?

    Special-Student-7
    それは、オフィシャルドキュメントが説明していないように思われることですが、任意のUNOオブジェクト群コンテキストは'com.sun.star.container.XNameContainer' UNOインターフェイスを実装してあるので、それを介して私たちはプロパティをセットできます。

    Objector 69B
    うん?UNOオブジェクト群コンテキストは変更できないものと思ってた、だって、'::com::sun.star::uno::XComponentContext'インターフェイスにはsetterメソッドがないから、でも、そんな方法があるのね . . .


    4: 任意のUNOオブジェクトシングルトンを取得する方法


    Special-Student-7
    UNOオブジェクトシングルトンを取得するために、UNOIDLベースgetterは特に必要ありません、実のところ。

    Objector 69A
    そのはずだ: 単にUNOオブジェクト群コンテキストの1プロパティとして取得できるはずだ。

    Special-Student-7
    そして、私自身はUNOIDLベースシングルトンgetterたちを全然用いません、なぜなら、その方法はPythonには適用できませんから。

    Objector 69A
    できないの?

    Special-Student-7
    私が知る限りでは、というのは、対応するPythonマッピングイメージを生成する既存ツールがありませんから。

    しかし、UNOオブジェクトシングルトンたちをPythonで問題なく使用できます。


    5: サンプルコード、プログラミング言語毎に


    Special-Student-7
    以下は、UNOオブジェクトシングルトンをJavaにて作成・取得・削除するサンプルコードです('l_underlyingRemoteUnoObjectsContext'はUNOオブジェクト群コンテキスト)。

    @Java ソースコード
    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
    'TestUnoComponent'はどこから来たの?

    Special-Student-7
    それは、別の記事から来たUNOコンポーネントです。普通は、あなたはあなた自身のUNOコンポーネントを持っていて、そのインスタンスがシングルトンになります、なんらかその他の形で取ってきたオブジェクトをシングルトンとして登録できないとは申しませんが。

    Objector 69B
    えーと。

    Special-Student-7
    以下は、C++コードです('l_underlyingRemoteUnoObjectsContext'はUNOオブジェクト群コンテキスト)。

    @C++ ソースコード
    #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'は、別の記事から来たUNOコンポーネントです。

    Objector 69B
    'UnoExtendedStringHandler'って何?

    Special-Student-7
    ああ . . .、'UnoExtendedStringHandler::getOustring'は私のユーティリティメソッドであり、'::rtl::OUString'(C++ UNO文字列クラス)インスタンスを、指定された'string'インスタンスから生成するものです。あなたは、そのメソッドを使う必要はありません、ご自身の方法で'::rtl::OUString'インスタンスを取得されればよいだけです。

    Objector 69B
    . . .

    Special-Student-7
    以下は、C#コードです('l_underlyingRemoteUnoObjectsContext'はUNOオブジェクト群コンテキスト)。

    @C# ソースコード
    			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'は、別の記事から来たUNOコンポーネントです。

    以下は、Pythonコードです('l_underlyingRemoteUnoObjectsContext'はUNOオブジェクト群コンテキスト)。

    @Python ソースコード
    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'は、別の記事から来たUNOコンポーネントです。


    6: 利用方法


    Objector 69B
    問題は、私はシングルトンをどこからセットするか?

    Special-Student-7
    それは全くあなた依存です。

    Objector 69B
    "あなた依存"と言われても、そんなに依存されたくないんだけど。

    Special-Student-7
    シングルトンUNOオブジェクトは、オフィスJVM内に生存してもよいですが、あなたの外部Javaプログラム内に存在してもよいです。

    Objector 69B
    後者は可能なの?つまり、そのUNOオブジェクトは外部プログラム内にいて、あるPythonマクロは、外部プログラム内のUNOオブジェクトを、何も特別なことはないかのように使えるの?

    Special-Student-7
    はい。それがUNOです。

    しかし、勿論、その外部プログラムは稼働し続けておく必要があります。

    Objector 69B
    それは当然のことね。

    Special-Student-7
    したがって、C#プログラマーで、できるだけC#で何でも書きたい方は、いくつかのシングルトンを登録するC#外部UNOクライアントを書き、当該C#コードをPythonマクロたちに使わせることができます。そうすると、C#プログラマーはマクロをC#で書けませんが、彼または彼女のC#コードはマクロから使用できます。

    Objector 69B
    ああ、そのC#外部クライアントはWindowsサービスでもいいのよね、例えば。

    Objector 69A
    はあ?でも、オフィスインスタンスは上がったり落ちたりするかもしれないだろう。そのWindowsサービスはどうやってシングルトンたちをサービスし続けるんだ?

    Special-Student-7
    そのWindowsサービスはコネクションアウェアUNOクライアントにできます、それは、任意のオフィスインスタンスへ、そのオフィスインスタンスが起動したらコネクトし、そのオフィスインスタンスがシャットダウンする時にはそのオフィスインスタンスから切断します。

    Objector 69A
    えーと、俺はJavaプログラマーなんだがな。どうすれば、俺のJavaシングルトンたちは、オフィスインスタンスが起動したら自動的にオフィスインスタンスにセットされるようにできるんだ?

    Special-Student-7
    あなたはオフィスインスタンス起動イベントリスナーをセットすることができます、それは将来の記事にて説明されます。


    参考資料


    <このシリーズの前の記事 | このシリーズの目次 | このシリーズの次の記事>