Почему происходит сбой libreoffice sdk при одновременном и одновременном создании документов через веб-сервис? - PullRequest
0 голосов
/ 11 апреля 2019

Я использую веб-сервис, который заменяет текст в шаблоне docx, а затем преобразовывает его в pdf.Я использую Ubuntu 18.04 и сервер Glassfish для его развертывания, когда я сделал один запрос на услугу конвертации, все в порядке, но когда я сделал двойной запрос слишком быстро, как вопрос двойного щелчка или параллельный запрос, я получил это исключение:

com.sun.star.lang.DisposedException на com.sun.star.lib.uno.environments.remote.JobQueue.removeJob (JobQueue.java:201).,Предоставлено: java.io.IOException: EOF достигнуто - сокет, хост = localhost, порт = 8100, localHost = localhost, localPort = 58494, peerHost = localhost, peerPort = 8100 на com.sun.star.lib.uno.bridges.java_remote.XConnectionInputStream_Adapter.read (XConnectionInputStream_Adapter.java:50)

Я строю код, руководствуясь примерами, я новичок в openoffice и LibreOffice, я увидел, что строка исключения указывает на xDesktop.прекратить ();, поэтому я провел эксперимент и удалил это утверждение, так что теперь исключение не возникает, но, как я уже говорил, я начинающий, поэтому я не уверен, что xDesktop.terminate ();делает и каковы последствия его удаления?

вот код, который я выполняю:

    public Response getFilePdf(Integer idqueja) {       
        try {

                    // Initialise
       String oooExeFolder = "/opt/libreoffice6.1/program";
       XComponentContext xContext = BootstrapSocketConnector.bootstrap(oooExeFolder);
    //XComponentContext xContext = Bootstrap.bootstrap();

    XMultiComponentFactory xMCF = xContext.getServiceManager();

    Object oDesktop = xMCF.createInstanceWithContext(
         "com.sun.star.frame.Desktop", xContext);

    XDesktop xDesktop = (XDesktop) UnoRuntime.queryInterface(
         XDesktop.class, oDesktop);

    // Load the Document
    String workingDir = "/home/somePath/";
    String myTemplate = workingDir + "template.docx";

    if (!new File(myTemplate).canRead()) {
        throw new RuntimeException("Cannotix load template:" + new File(myTemplate));
    }

    XComponentLoader xCompLoader = (XComponentLoader) UnoRuntime
        .queryInterface(com.sun.star.frame.XComponentLoader.class, xDesktop);

    String sUrl = "file:///" + myTemplate;

    PropertyValue[] propertyValues = new PropertyValue[0];

    propertyValues = new PropertyValue[1];
    propertyValues[0] = new PropertyValue();
    propertyValues[0].Name = "Hidden";
    propertyValues[0].Value = new Boolean(true);

    XComponent xComp = xCompLoader.loadComponentFromURL(
        sUrl, "_blank", 0, propertyValues);


    // Manipulate
    XReplaceDescriptor xReplaceDescr = null;
    XReplaceable xReplaceable = null;

    XTextDocument xTextDocument = (XTextDocument) UnoRuntime
            .queryInterface(XTextDocument.class, xComp);

    xReplaceable = (XReplaceable) UnoRuntime
            .queryInterface(XReplaceable.class,
                    xTextDocument);

    xReplaceDescr = (XReplaceDescriptor) xReplaceable
            .createReplaceDescriptor();


        xReplaceDescr.setSearchString("<version>");
    xReplaceDescr.setReplaceString("1.x");
    xReplaceable.replaceAll(xReplaceDescr);
    // mail merge the date
    xReplaceDescr.setSearchString("<number>");
    xReplaceDescr.setReplaceString("12345677");
    xReplaceable.replaceAll(xReplaceDescr);


        OOoOutputStream output= new OOoOutputStream();

    // save as a PDF 
    XStorable xStorable = (XStorable) UnoRuntime
            .queryInterface(XStorable.class, xComp);

    propertyValues = new PropertyValue[2];
    // Setting the flag for overwriting
    propertyValues[0] = new PropertyValue();
        propertyValues[1] = new PropertyValue();

    propertyValues[0].Name = "OutputStream";
    propertyValues[0].Value = output;
    // Setting the filter name

    propertyValues[1].Name = "FilterName";
    propertyValues[1].Value = "writer_pdf_Export";

    // Appending the favoured extension to the origin document name
    //String myResult = workingDir + "fileConverted.pdf";
    xStorable.storeToURL("private:stream", propertyValues);


    // shutdown
    xDesktop.terminate();

         ByteArrayInputStream inStream = new ByteArrayInputStream(output.toByteArray());



                  ResponseBuilder response = Response.ok((Object) inStream);
                            response.header("Content-Disposition", "attachment;filename=template.pdf");
                            return response.build();   


        } catch (Exception e) {
            e.printStackTrace();
                        ResponseBuilder response = Response.serverError();
                        return response.build();
        }       
    }

Так что этот метод веб-сервиса планируется обслуживать документы МНОЖУЮ пользователей, так что если яполучил петицию одновременно или слишком последовательно, это вызовет исключение, если я не удалю xDesktop.terminate ();но я не знаю, будет ли это иметь дальнейшие последствия, такие как переопределение памяти или тому подобное.заранее спасибо.

1 Ответ

1 голос
/ 19 апреля 2019

Проблема в том, что xDesktop.terminate () запрашивает завершение базового процесса soffice (Java API - просто оболочка вокруг него). У вас есть два варианта:

  1. Либо предварительно запустите libreoffice самостоятельно, так что вам не нужно все время создавать новый процесс soffice, а просто подключиться к существующему. Преимущество в том, что производительность будет отличной, если у вас много небольших запросов (без затрат на запуск), но тогда ваши преобразования не слишком изолированы (из соображений безопасности), и на практике преобразования не будут выполняться параллельно. В этом случае вы запустили процесс soffice, поэтому просто не вызывайте xDesktop.terminate ().

  2. Или вы запускаете каждый процесс soffice, используя выделенный, уникальный каталог UserInstallation (см. Libreoffice --help), и тогда xDesktop.terminate () не будет проблемой, поскольку одно преобразование - это один процесс soffice.

DisposedException просто означает, что вы общались с процессом soffice, используя удаленный протокол UNO, и пока ваш запрос выполнялся, кто-то другой убил процесс soffice.

Вам необходимо изучить, как Java API позволяет передавать пользовательские параметры soffice, но в худшем случае вы можете сделать что-то вроде soffice "--accept=socket,host=localhost,port=9999;urp;StarOffice.ServiceManager" -env:UserInstallation=file:///tmp/test, где вам нужно убедиться, что 9999 и /tmp/test уникальны, если вы делаете два преобразования в параллели. (Опять же, см. Документацию, можно использовать unix-сокеты вместо TCP-портов, если вы найдете это лучше.)

Итак, суть: если вы разделяете процесс soffice между несколькими конверсиями, не прерывайте синглтон xDesktop, так как это приведет к "аварийному завершению" другого процесса конвертации.

...