如果超过最大允许时间,如何取消将 ms office 文件转换为 PDF 的 Libreoffice UNO API 库过程
Posted
技术标签:
【中文标题】如果超过最大允许时间,如何取消将 ms office 文件转换为 PDF 的 Libreoffice UNO API 库过程【英文标题】:How to cancel Libreoffice UNO API Library process of convertion of ms office files to PDF in case it is over maximum permitted time 【发布时间】:2019-05-09 21:08:20 【问题描述】:我正在使用 Libreoffice 6.0 中的 UNO API 库 (Soffice) 将 ms office 格式转换为 PDF,Soffice 进程在服务器模式下处理多个 sumultanious 请求。 通常转换速度很快,但在转换一些大文件时,例如xlsx 或 pptx,Soffice 进程使用 100% CPU,转换最多需要几分钟。 这是不可接受的,因为在此期间并发请求不会被处理。
为了处理这种情况,我尝试使用 java.util.concurrent 将一些子任务作为线程执行,并通过未来接口进行超时控制。但只有在转换的原始 ms office 文档加载阶段发生挂起时,它才能正常工作。 如果转换过程已经开始,即使发生超时异常,Soffice 进程也不会立即退出 100% 加载,而是继续将文档转换为 pdf。 程序执行暂停尝试处理加载的文档。
linux下通过命令启动SOffice进程:
Runtime.getRuntime().exec("/usr/lib64/libreoffice/program/soffice, --nologo, --nodefault, --norestore, --nocrashreport, --nolockcheck, --accept=socket,host=localhost,port=8100;urp;");
ms office 文件转换为简体pdf的代码为:
public void convertFile()
xRemoteContext = BootstrapSocketConnector.bootstrap(oooPath);
xRemoteServiceManager = xRemoteContext.getServiceManager();
Object desktop = null;
desktop = xRemoteServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", xRemoteContext);
xComponentLoader = (XComponentLoader) UnoRuntime.queryInterface(XComponentLoader.class, desktop);
File mfile = new File(workingDir + myTemplate);
String sUrl = pathToURL(workingDir + myTemplate);
PropertyValue[] propertiesIn;
propertiesIn = new PropertyValue[2];
propertiesIn[0] = property("ReadOnly", Boolean.TRUE);
propertiesIn[1] = property("Hidden", Boolean.TRUE);
XComponent xComp = null;
try
//xComp = xComponentLoader.loadComponentFromURL(sUrl, "_blank", 0, propertiesIn);
//The same via timeout control
xComp = callLibreLoad(sUrl, propertiesIn);
catch (TimeoutException ex)
if(xComp!= null)
xComp.dispose();
...
// save as a PDF
XStorable xStorable = (XStorable) UnoRuntime.queryInterface(XStorable.class, xComp);
PropertyValue[] propertiesOut = new PropertyValue[2];
propertiesOut[0] = property("FilterName", formatfilter);
propertiesOut[1] = property("Overwrite", Boolean.TRUE);
String myResult = workingDir + fileNameOut;
try
//xStorable.storeToURL(pathToURL(myResult), propertiesOut);
//The same via timeout control
callLibreStore(xStorable,pathToURL(myResult), propertiesOut);
catch (TimeoutException ex)
if(xComp!= null)
xComp.dispose();
...
if(xComp!= null)
xComp.dispose();
函数 callLibreLoad 和 callLibreStore 使用 Future 接口进行超时控制:
private XComponent callLibreLoad(String sUrl, PropertyValue[] propertiesIn) throws Exception
XComponent result = null;
ExecutorService executor = Executors.newCachedThreadPool();
Callable<Object> task = new Callable<Object>()
public Object call() throws IllegalArgumentException, com.sun.star.io.IOException
return xComponentLoader.loadComponentFromURL(sUrl, "_blank", 0, propertiesIn);
;
Future<Object> future = executor.submit(task);
try
result = (XComponent) future.get(maxTimeout, TimeUnit.SECONDS);
finally
future.cancel(true);
return result;
private void callLibreStore(XStorable xStorable, String sUrl, PropertyValue[] propertiesOut) throws Exception
Integer result = null;
ExecutorService executor = Executors.newCachedThreadPool();
Runnable task = new Runnable()
public void run()
try
xStorable.storeToURL(sUrl, propertiesOut);
catch (com.sun.star.io.IOException e)
log.error(e);
;
Future future = executor.submit(task);
try
future.get(maxTimeout, TimeUnit.SECONDS);
finally
future.cancel(true); // may or may not desire this
所以,当函数 callLibreLoad 发生超时异常时,SOffice 进程立即恢复到工作状态。 但是当稍后发生超时时,在函数 callLibreStore 中,即使发生超时并且转换线程被中断后,SOffice 进程仍处于 100% 加载状态超过一分钟,试图处理加载的文档,执行代码 xComp.dispose()。 此时Java线程与SOffice进程的堆栈跟踪包含以下内容:
State: WAITING on com.sun.star.lib.uno.environments.remote.JobQueue@30af74b8
Total blocked: 455 Total waited: 1 967
Stack trace:
java.lang.Object.wait(Native Method)
com.sun.star.lib.uno.environments.remote.JobQueue.removeJob(JobQueue.java:207)
com.sun.star.lib.uno.environments.remote.JobQueue.enter(JobQueue.java:316)
com.sun.star.lib.uno.environments.remote.JobQueue.enter(JobQueue.java:289)
com.sun.star.lib.uno.environments.remote.JavaThreadPool.enter(JavaThreadPool.java:81)
com.sun.star.lib.uno.bridges.java_remote.java_remote_bridge.sendRequest(java_remote_bridge.java:618)
com.sun.star.lib.uno.bridges.java_remote.ProxyFactory$Handler.request(ProxyFactory.java:145)
com.sun.star.lib.uno.bridges.java_remote.ProxyFactory$Handler.invoke(ProxyFactory.java:129)
com.sun.proxy.$Proxy211.close(Unknown Source)
com.componentplus.prom.libreoffice.LibreOfficeStationary.closeDocument(LibreOfficeStationary.java:425)
com.componentplus.prom.libreoffice.LibreOfficeStationary.convertFile(LibreOfficeStationary.java:393)
...
如果需要超过最大允许时间,如何强制 Soffice 取消转换为 pdf。
【问题讨论】:
很明显,文件转换线程是在另一个进程(soffice.bin)上启动的,不可能中断外部进程的那个线程。所以我想这个问题没有决定性。 【参考方案1】:一种可能性可能是保存Runtime.getRuntime().exec
返回的Process
实例,例如在变量myProc
中,然后在需要时调用myProc.destroy()
杀死进程。
【讨论】:
我试图销毁 Process=Runtime.getRuntime().exec(/usr/lib64/libreoffice/program/soffice, --nologo, --nodefault, --norestore, --nocrashreport, - -nolockcheck, --accept=socket,host=localhost,port=8100;urp;) Soffice.bin 保留在进程列表中,并且在被杀死之前无法使用。 无赖。您可能会在其中找到其他有用的信息,但答案基于 Oracle 页面上的 Runtime 和 Process 类信息。 刚刚意识到一些事情...我认为应该是Process myProc = Runtime.getRuntime().exec(...)
而不是Process=Runtime...
,然后是myProc.destroy()
。但这可能是您已经尝试过的,我只是误解了您的评论。
如你所见,soffice.bin 进程以套接字模式启动。另外soffice.bin不是java进程,当你调用Process myProc = Runtime.getRuntime().exec(...)启动libreoffice时,myProc变量不是soffice.bin进程,而是一些辅助进程,我们在破坏myProc不要破坏 soffice.bin 进程。
但最糟糕的是,在通过 xComponentLoader.loadComponentFromURL 加载文档并通过 xStorable.storeToURL 开始文档转换后,soffice.bin 进程仍然忙于转换,直到它完成,即使您尝试以所有可能的方式中止它,包括销毁 myProc 或通过可用的接口方法关闭文档。以上是关于如果超过最大允许时间,如何取消将 ms office 文件转换为 PDF 的 Libreoffice UNO API 库过程的主要内容,如果未能解决你的问题,请参考以下文章
OpenOffice 和 MS Office 格式转换为 TIFF
Microsoft office2016版产品密钥的激活次数达到了最大允许次数'这应该怎么解决啊