为什么 libreoffice sdk 在通过 web 服务同时并发创建文档时崩溃?
why libreoffice sdk crash when simultaneosly and concurrently create documents through a webservice?
我是 运行 一个网络服务,可以替换 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 reached - socket,host=localhost,port=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.terminate(); ,所以我做了一个实验并删除了那个声明,所以现在没有引发异常,但正如我提到的我是一个初学者所以我不确定 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();但我不知道它是否会产生进一步的后果,例如覆盖内存或类似的东西。
提前致谢。
问题是 xDesktop.terminate() 请求关闭底层 soffice 进程(Java API 基本上只是它的包装器)。您有两个选择:
要么自己预先启动 libreoffice,这样您就不需要一直生成新的 soffice 进程,而只需连接到现有进程即可。这样做的好处是,如果您有很多小请求(无启动成本),性能会很好,但是您的转换不会太孤立(安全问题)并且实际上转换不会并行发生。在这种情况下,您启动了 soffice 进程,所以不要调用 xDesktop.terminate().
或者您使用专用的、唯一的 UserInstallation 目录(请参阅 libreoffice --help)启动每个 soffice 进程,然后 xDesktop.terminate() 不会有问题,因为一个转换是一个办公过程。
DisposedException 只是意味着您正在使用远程 UNO 协议与 soffice 进程通信,并且当您的请求正在进行时,其他人终止了 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 单例,因为那样会 "crash" 其他转换进程。
我是 运行 一个网络服务,可以替换 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 reached - socket,host=localhost,port=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.terminate(); ,所以我做了一个实验并删除了那个声明,所以现在没有引发异常,但正如我提到的我是一个初学者所以我不确定 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();但我不知道它是否会产生进一步的后果,例如覆盖内存或类似的东西。 提前致谢。
问题是 xDesktop.terminate() 请求关闭底层 soffice 进程(Java API 基本上只是它的包装器)。您有两个选择:
要么自己预先启动 libreoffice,这样您就不需要一直生成新的 soffice 进程,而只需连接到现有进程即可。这样做的好处是,如果您有很多小请求(无启动成本),性能会很好,但是您的转换不会太孤立(安全问题)并且实际上转换不会并行发生。在这种情况下,您启动了 soffice 进程,所以不要调用 xDesktop.terminate().
或者您使用专用的、唯一的 UserInstallation 目录(请参阅 libreoffice --help)启动每个 soffice 进程,然后 xDesktop.terminate() 不会有问题,因为一个转换是一个办公过程。
DisposedException 只是意味着您正在使用远程 UNO 协议与 soffice 进程通信,并且当您的请求正在进行时,其他人终止了 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 单例,因为那样会 "crash" 其他转换进程。