UNO objects in different environments connect via the interprocess bridge. You can execute calls on UNO object instances, that are located in a different process. This is done by converting the method name and the arguments into a byte stream representation, and sending this package to the remote process, for example, through a socket connection.
By default LO will not listen on a resource for security reasons. We can make LO listen for UNO connections from external processess by starting soffice with extra param :
$ $LOROOT/instdir/program/soffice --accept="socket,host=0,port=2002;urp;" --calc
After running, it can be verified using netstat -na, and it would show something like :
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:2002 0.0.0.0:* LISTEN
To import a reference to a UNO object from an exporting server(example : the LO instance), we use com::sun::star::bridge::UnoUrlResolver
service
which supports the interface com::sun::star::bridge::XUnoUrlResolver
. The interface definition is as follows :
interface XUnoUrlResolver: com::sun::star::uno::XInterface
{
/** resolves an object on the UNO URL */
com::sun::star::uno::XInterface resolve( [in] string sUnoUrl )
raises (com::sun::star::connection::NoConnectException,
com::sun::star::connection::ConnectionSetupException,
com::sun::star::lang::IllegalArgumentException);
};
The string passed to resolve()
method is called UNO URL with the following format :
uno:connection-type,params;protocol-name,params;ObjectName
| I | II | III | IV |
Example :
uno:socket,host=localhost,port=2002;urp;StarOffice.ServiceManager
The parts I to IV are :
I. This identifies the URL as UNO URL and distinguishes it from others, such as http: or ftp: URLs.
II. connection-type indicates the transport layer mechanism to be used to transfer the byte stream for example TCP/IP sockets or named pipes. Optionally after this string there can be key=value pairs separated by comma indicating the specifics of the transport layer mechanism to be used. Example for sockets, it needs host and port.
III. This indicates the application layer protocol to be used. Example : urp (UNO Remote Protocol). This string can be followed optionally be key=value pairs separated by comma to customize the protocol to specific needs.
IV. This specifies the distinct name of the UNO object the server has exported. Note that it is not possible to access an arbitraty UNO object like in CORBA.
Get local component context without attempting to invoke LO.
Reference< XComponentContext > xLocalComponentContext = cppu::defaultBootstrap_InitialComponentContext();
Note that this is different from calling cppu::bootstrap()
as in previous examples where it will start LO instance if not found running.
Where as here no connections to LO is made yet.
Get initial service manager from local component context.
Reference< XMultiComponentFactory > xServiceManager = xLocalComponentContext->getServiceManager();
Create UnoUrlResolver service locally and query for XUnoUrlResolver interface.
Reference< XInterface > xInstance =
xServiceManager->createInstanceWithContext(
"com.sun.star.bridge.UnoUrlResolver", xLocalComponentContext );
Reference< XUnoUrlResolver > xResolver( xInstance, UNO_QUERY );
Import the remote UNO object StarOffice.ServiceManager from port 2002 where soffice is listening.
xInstance = xResolver->resolve( OUString(
"uno:socket,host=localhost,port=2002;urp;StarOffice.ServiceManager" ) );
Note that the returned object is typed as Reference< XInterface >
so we need to query for the required interface to use it.
First run LO as :
$ $LOROOT/instdir/program/soffice --accept="socket,host=0,port=2002;urp;" --calc
Then the C++ code for this section can be downloaded and run as :
$ git clone https://github.com/niocs/ImportingUNOObject.git
$ cd ImportingUNOObject
$ make
$ make ImportUNOObject.run
If it worked, you will see the string "Connected successfully to the office" in the output of make ImportUNOObject.run
.
If you run the above before starting soffice with listen instructions for port 2002, the program will show the exception caught and will print something like :
Error: Connector : couldn't connect to socket
along with some warnings and make
errors which can be ignored. The above error means the program was not able to connect to soffice to import the UNO object.
Usage of UnoUrlResolver has some disadvantages :
This is the entity in any remote process responsible for remote connections. Bridge is threadsafe and allows multiple threads to execute remote calls. The main thread(dispatcher) inside bridge will not block as it passes requests to worker threads. There are however two types of remote calls :
Synchronous call : The request is sent through the connection and lets the requesting thread wait for the reply. Any calls that have a
return value or out parameter or throw exception other than RuntimeException
must be synchronous.
Asynchronous/oneway call : This sends the request throught the connection and returns immediately without waiting for reply.
In the IDL reference of all methods it will be indicated if the corresponding request is synchronous or asynchronous using the [oneway] modifier.
Note that there exists cases where oneway calls cause deadlocks in LO so we should not introduce new oneway methods when writing new components
Although the remote bridge supports asynchronous calls, this feature is disabled by default. Every call is executed synchronously. The oneway flag of UNO interface methods is ignored. However, the bridge can be started in a mode that enables the oneway feature and thus executes calls flagged with the [oneway] modifier as asynchronous calls. To do this, the protocol part of the connection string on both sides of the remote bridge must be extended by ',Negotiate=0,ForceSynchronous=0'
Example : use the below to start soffice with listening
$ soffice --accept="socket,host=0,port=2002;urp,Negotiate=0,ForceSynchronous=0;" --calc
and use the following UNO URL for connecting to soffice.
"uno:socket,host=localhost,port=2002;urp,Negotiate=0,ForceSynchronous=0;StarOffice.ServiceManager"
There is an alternative to using UnoUrlResolver using lower level interfaces described in the following OOO wiki pages :
The complete code for the above can be found at $LOROOT/instdir/sdk/examples/DevelopersGuide/ProfUNO/InterprocessConn
Since we focus on in-process calc extensions, discussion on the above is outside the scope of this series of posts.