Developers Club geek daily blog

2 years, 6 months ago
Libre/Open Office give an opportunity of work with office through UNO API. In order that it was possible to address office it is necessary to start it in a listen mode.

For example:
soffice --accept="socket,host=localhost,port=2002;urp;"

This approach is quite logical and clear from the point of view of developers of office, but bears a number of inconveniences. In particular, it is necessary to start independently Libre/Open Office in a listen mode. Personally it is not clear to me why developers were too lazy and did not provide function of start of office. Well it is fine, everything would be made, programmers would not be necessary. Let's solve therefore a problem by own efforts.

The easiest way to solve this problem — to place a line of start of office in the scripting file. In it to start at first office, and then the application. But that if it is, for example, the library also is not present an opportunity to address it through the scripting file. Besides it is necessary not just to wait for start of office, but also it will wait in a listen mode so far. Generally this approach suits only for test problems, no more.
I stopped on the following implementation:
1. Fork of process which starts office in a listen mode.
2. With a certain frequency to try to address office until attempt is successful.
3. If through certain time connection attempt to office is not successful, then to generate an exception com.sun.star.connection.NoConnectException.

# -*- coding: utf-8 -*-

import os
import subprocess
import sys
import time
import uno

NoConnectException = uno.getClass(
        "com.sun.star.connection.NoConnectException")

###############################################################################
def init_office():
    """
    Test Libre/Open Office to be launched in the listening mode
    """
    connection_string = "uno:socket,host=localhost,port=2002;urp;\
StarOffice.ComponentContext"
    oLocal = uno.getComponentContext()
    oResolver = \
        oLocal.ServiceManager.createInstanceWithContext(
                        "com.sun.star.bridge.UnoUrlResolver", oLocal)
    if oResolver:
        oContext = oResolver.resolve(connection_string)
        oDesktop = oContext.ServiceManager.\
            createInstanceWithContext("com.sun.star.frame.Desktop",
                                      oContext)

###############################################################################
def start_office(timeout=30, attempt_period=0.1, office='soffice --accept="socket,host=localhost,port=2002;urp;"'):
    """
    Starts Libre/Open Office with a listening socket.

    @type  timeout: int
    @param timeout: Timeout for starting Libre/Open Office in seconds

    @type  attempt_period: int
    @param attempt_period: Timeout between attempts in seconds

    @type  office: string
    @param office: Libre/Open Office startup string
    """
    ###########################################################################
    def start_office_instance(office):
        """
        Starts Libre/Open Office with a listening socket.

        @type  office: string
        @param office: Libre/Open Office startup string
        """
        # Fork to execute Office
        if os.fork():
            return

        # Start OpenOffice.org and report any errors that occur.
        try:
            retcode = subprocess.call(office, shell=True)
            if retcode < 0:
                print (sys.stderr,
                       "Office was terminated by signal",
                       -retcode)
            elif retcode > 0:
                print (sys.stderr,
                       "Office returned",
                       retcode)
        except OSError as e:
            print (sys.stderr, "Execution failed:", e)

        # Terminate this process when Office has closed.
        raise SystemExit()

    ###########################################################################
    waiting = False
    try:
        init_office()
    except NoConnectException as e:
        waiting = True
        start_office_instance(office)

    if waiting:
        steps = int(timeout/attempt_period)
        exception = None
        for i in range(steps + 1):
            try:
                init_office()
                break
            except NoConnectException as e:
                exception = e
                time.sleep(attempt_period)
        else:
            if exception:
                raise NoConnectException(exception)
            else:
                raise NoConnectException()

###############################################################################

start_office()


This example will try to start Libre/Open Office with frequency 0.1 second for 30 seconds.
As the test for existence of the office started in a listen mode the init_office function is used (). Instead of it it can be used any other of your library.

Earlier, in the article "PyOOCalc — Library for reports generation, accounts of Libre/Open Office Calc on Python", I described as it is simpler to work with Libre/OpenOffice for a certain category of tasks. But the PyOOCalc library on had possibilities of automatic start of office in a listen mode, and the above-stated code can be rewritten as follows.
Instead of the init_office function () it is possible to write:
import pyoocalc
pyoocalc.Document()

It can also be any other library. It is necessary to call a method which will try to be connected to Libre/Open Office.

Also I added a feature for automatic start of office in PyOOCalc library.
Example of use:
import pyoocalc
doc = pyoocalc.Document(autostart=True)
doc.new_document()

This article is a translation of the original post at habrahabr.ru/post/274775/
If you have any questions regarding the material covered in the article above, please, contact the original author of the post.
If you have any complaints about this article or you want this article to be deleted, please, drop an email here: sysmagazine.com@gmail.com.

We believe that the knowledge, which is available at the most popular Russian IT blog habrahabr.ru, should be accessed by everyone, even though it is poorly translated.
Shared knowledge makes the world better.
Best wishes.

comments powered by Disqus