Я использую UNO API Library (Soffice) из Libreoffice 6.0 для преобразования офисных форматов ms в PDF, процесс Soffice обслуживает несколько случайных запросов в режиме сервера.Обычно преобразование выполняется быстро, но при преобразовании некоторых больших файлов, например, xlsx или pptx, процесс Soffice использует 100% ЦП, и преобразование занимает до нескольких минут.Это неприемлемо, потому что в это время параллельные запросы не обрабатываются.
Чтобы справиться с этой ситуацией, я попытался использовать java.util.concurrent для выполнения некоторых подзадач в виде потоков с контролем времени ожидания через будущий интерфейс.Но он работает хорошо только в том случае, если произошла зависание на этапе преобразования исходного документа MS Office.Если процесс конвертации уже запущен, даже несмотря на то, что возникает исключение тайм-аута, процесс Soffice не сразу завершает загрузку на 100%, а требует преобразования документа в pdf.Выполнение программы приостанавливается при попытке удалить загруженный документ.
Процесс SOffice запускается под linux с помощью команды:
Runtime.getRuntime().exec("/usr/lib64/libreoffice/program/soffice, --nologo, --nodefault, --norestore, --nocrashreport, --nolockcheck, --accept=socket,host=localhost,port=8100;urp;");
Код для преобразования ms office file в 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, если для этого требуется больше, чем максимально допустимое время.