diff --git a/libreoffice/griffin b/libreoffice/griffin index 603a84d..b96af17 100755 --- a/libreoffice/griffin +++ b/libreoffice/griffin @@ -1,3 +1,5 @@ #!/usr/bin/env bash -java -Dfile.encoding=UTF-8 -jar /vitam/bin/worker/griffins/libreoffice-griffin/libreoffice-jar-with-dependencies.jar $1 \ No newline at end of file +LIBREOFFICE_HOME=$(dirname $(dirname $(readlink -f $(which $(compgen -c | grep libreoffice | head -1))))) + +java -Doffice.home="$LIBREOFFICE_HOME" -Dfile.encoding=UTF-8 -jar /vitam/bin/worker/griffins/libreoffice-griffin/libreoffice-jar-with-dependencies.jar $1 \ No newline at end of file diff --git a/libreoffice/libreoffice b/libreoffice/libreoffice deleted file mode 100644 index 8b7af42..0000000 --- a/libreoffice/libreoffice +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -$(compgen -c | grep libreoffice | head -1) --accept="socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp;StarOffice.ServiceManager" --headless --invisible --nodefault --nofirststartwizard --nolockcheck --nologo --norestore \ No newline at end of file diff --git a/libreoffice/pom.xml b/libreoffice/pom.xml index c658dee..dc4deae 100755 --- a/libreoffice/pom.xml +++ b/libreoffice/pom.xml @@ -99,28 +99,6 @@ /vitam/bin/worker/griffins/${unix.name} - - ${basedir}/libreoffice - file - - perm - ${unix.user} - ${unix.group} - 750 - /vitam/bin/worker/griffins/${unix.name} - - - - ${basedir}/soffice.service - file - - perm - ${unix.user} - ${unix.group} - 0755 - /lib/systemd/system - - @@ -190,33 +168,12 @@ ${project.basedir}/griffin - - ${project.basedir}/libreoffice - ${project.build.directory}/libreoffice-jar-with-dependencies.jar - - /usr/lib/systemd/system/ - 644 - root - root - false - - - ${project.basedir}/soffice.service - - - - - - - - - diff --git a/libreoffice/soffice.service b/libreoffice/soffice.service deleted file mode 100644 index 5e4bc74..0000000 --- a/libreoffice/soffice.service +++ /dev/null @@ -1,13 +0,0 @@ -[Unit] -Description=Control headless soffice instance -After=network.target - -[Service] -User=vitam -Group=vitam -Type=simple -ExecStart=/vitam/bin/worker/griffins/libreoffice-griffin/libreoffice -Restart=always - -[Install] -WantedBy=multi-user.target \ No newline at end of file diff --git a/libreoffice/src/deb/control/postinst b/libreoffice/src/deb/control/postinst deleted file mode 100755 index 609330f..0000000 --- a/libreoffice/src/deb/control/postinst +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -if [ -x /bin/systemctl ]; then - systemctl daemon-reload - systemctl enable soffice.service - systemctl start soffice.service -fi \ No newline at end of file diff --git a/libreoffice/src/deb/control/prerm b/libreoffice/src/deb/control/prerm deleted file mode 100644 index 5c9664f..0000000 --- a/libreoffice/src/deb/control/prerm +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -if [ -x /bin/systemctl ]; then - systemctl stop soffice.service - systemctl disable soffice.service -fi \ No newline at end of file diff --git a/libreoffice/src/main/java/fr/gouv/vitam/griffins/libreoffice/AutoClosableOfficeManager.java b/libreoffice/src/main/java/fr/gouv/vitam/griffins/libreoffice/AutoClosableOfficeManager.java new file mode 100644 index 0000000..307463e --- /dev/null +++ b/libreoffice/src/main/java/fr/gouv/vitam/griffins/libreoffice/AutoClosableOfficeManager.java @@ -0,0 +1,80 @@ +/* + * Copyright French Prime minister Office/SGMAP/DINSIC/Vitam Program (2015-2019) + * + * contact.vitam@culture.gouv.fr + * + * This software is a computer program whose purpose is to implement a digital archiving back-office system managing + * high volumetry securely and efficiently. + * + * This software is governed by the CeCILL 2.1 license under French law and abiding by the rules of distribution of free + * software. You can use, modify and/ or redistribute the software under the terms of the CeCILL 2.1 license as + * circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, modify and redistribute granted by the license, + * users are provided only with a limited warranty and the software's author, the holder of the economic rights, and the + * successive licensors have only limited liability. + * + * In this respect, the user's attention is drawn to the risks associated with loading, using, modifying and/or + * developing or reproducing the software by the user in light of its specific status of free software, that may mean + * that it is complicated to manipulate, and that also therefore means that it is reserved for developers and + * experienced professionals having in-depth computer knowledge. Users are therefore encouraged to load and test the + * software's suitability as regards their requirements in conditions enabling the security of their systems and/or data + * to be ensured and, more generally, to use and operate it in the same conditions as regards security. + * + * The fact that you are presently reading this means that you have had knowledge of the CeCILL 2.1 license and that you + * accept its terms. + */ +package fr.gouv.vitam.griffins.libreoffice; + +import org.jodconverter.office.LocalOfficeManager; +import org.jodconverter.office.OfficeException; +import org.jodconverter.office.OfficeManager; +import org.jodconverter.task.OfficeTask; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.ServerSocket; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Files; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class AutoClosableOfficeManager implements AutoCloseable, OfficeManager { + + private final OfficeManager manager; + + public AutoClosableOfficeManager(int libreOffice) throws IOException { + this.manager = LocalOfficeManager.builder() + .portNumbers(libreOffice) + .workingDir(Files.createTempDirectory("griffin-libreoffice-").toFile()) + .install() + .build(); + } + + @Override + public void close() throws Exception { + this.stop(); + } + + @Override + public void execute(OfficeTask task) throws OfficeException { + manager.execute(task); + } + + @Override + public boolean isRunning() { + return manager.isRunning(); + } + + @Override + public void start() throws OfficeException { + manager.start(); + } + + @Override + public void stop() throws OfficeException { + manager.stop(); + } +} diff --git a/libreoffice/src/main/java/fr/gouv/vitam/griffins/libreoffice/BatchProcessor.java b/libreoffice/src/main/java/fr/gouv/vitam/griffins/libreoffice/BatchProcessor.java index 52f9686..53343fd 100755 --- a/libreoffice/src/main/java/fr/gouv/vitam/griffins/libreoffice/BatchProcessor.java +++ b/libreoffice/src/main/java/fr/gouv/vitam/griffins/libreoffice/BatchProcessor.java @@ -35,8 +35,6 @@ import fr.gouv.vitam.griffins.libreoffice.pojo.Result; import fr.gouv.vitam.griffins.libreoffice.status.GriffinStatus; import org.jodconverter.LocalConverter; -import org.jodconverter.office.ExternalOfficeManagerBuilder; -import org.jodconverter.office.OfficeException; import org.jodconverter.office.OfficeManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,7 +63,6 @@ public class BatchProcessor { public static final String parametersFileName = "parameters.json"; public static final String resultFileName = "result.json"; public static final String inputFilesDirName = "input-files"; - private static final String FILTER_DATA = "FilterData"; private static final String FILTER_NAME = "FilterName"; private static final String FILTER_OPTIONS = "FilterOptions"; @@ -83,9 +80,9 @@ public BatchStatus execute() { long startTime = System.currentTimeMillis(); String batchProcessingId = batchDirectory.getFileName().toString(); - OfficeManager officeManager = new ExternalOfficeManagerBuilder().build(); + try (PortReserver portReserver = new PortReserver(); + AutoClosableOfficeManager officeManager = new AutoClosableOfficeManager(portReserver.getLibreOfficePort())) { - try { File file = batchDirectory.resolve(parametersFileName).toFile(); parameters = mapper.readValue(file, Parameters.class); @@ -112,8 +109,6 @@ public BatchStatus execute() { } catch (Exception e) { logger.error("{}", e); return BatchStatus.error(batchProcessingId, startTime, e); - } finally { - stopOfficeManager(officeManager); } } @@ -215,12 +210,4 @@ private boolean isInteger(String value) { return false; } } - - private void stopOfficeManager(OfficeManager manager) { - try { - manager.stop(); - } catch (OfficeException ex) { - logger.error("{}", ex); - } - } } diff --git a/libreoffice/src/main/java/fr/gouv/vitam/griffins/libreoffice/PortReserver.java b/libreoffice/src/main/java/fr/gouv/vitam/griffins/libreoffice/PortReserver.java new file mode 100644 index 0000000..fdd3c76 --- /dev/null +++ b/libreoffice/src/main/java/fr/gouv/vitam/griffins/libreoffice/PortReserver.java @@ -0,0 +1,86 @@ +/* + * Copyright French Prime minister Office/SGMAP/DINSIC/Vitam Program (2015-2019) + * + * contact.vitam@culture.gouv.fr + * + * This software is a computer program whose purpose is to implement a digital archiving back-office system managing + * high volumetry securely and efficiently. + * + * This software is governed by the CeCILL 2.1 license under French law and abiding by the rules of distribution of free + * software. You can use, modify and/ or redistribute the software under the terms of the CeCILL 2.1 license as + * circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, modify and redistribute granted by the license, + * users are provided only with a limited warranty and the software's author, the holder of the economic rights, and the + * successive licensors have only limited liability. + * + * In this respect, the user's attention is drawn to the risks associated with loading, using, modifying and/or + * developing or reproducing the software by the user in light of its specific status of free software, that may mean + * that it is complicated to manipulate, and that also therefore means that it is reserved for developers and + * experienced professionals having in-depth computer knowledge. Users are therefore encouraged to load and test the + * software's suitability as regards their requirements in conditions enabling the security of their systems and/or data + * to be ensured and, more generally, to use and operate it in the same conditions as regards security. + * + * The fact that you are presently reading this means that you have had knowledge of the CeCILL 2.1 license and that you + * accept its terms. + */ +package fr.gouv.vitam.griffins.libreoffice; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class PortReserver implements AutoCloseable { + private static final Logger LOGGER = LoggerFactory.getLogger(PortReserver.class); + private static final Path LOCK_DIRECTORY = Paths.get(System.getProperty("java.io.tmpdir"), "griffin-libre-office-locks"); + private static final int MAX_ATTEMPT_NUMBER = 4; + + private final int libreOfficePort; + + public PortReserver() throws IOException { + createLockDirectory(); + this.libreOfficePort = findAvailablePort(MAX_ATTEMPT_NUMBER); + } + + private void createLockDirectory() throws IOException { + if (Files.notExists(LOCK_DIRECTORY)) { + try { + Files.createDirectory(LOCK_DIRECTORY); + } catch (FileAlreadyExistsException e) { + LOGGER.info("ignore error {}", e); + } + } + } + + private int findAvailablePort(int numberOfAttempt) throws IOException { + try (ServerSocket socket = new ServerSocket(0, 1, InetAddress.getLocalHost())) { + int localPort = socket.getLocalPort(); + Files.createFile(LOCK_DIRECTORY.resolve(String.format("%d.lock", localPort))); + return localPort; + } catch (FileAlreadyExistsException e) { + LOGGER.warn("{}", e); + + if (numberOfAttempt > MAX_ATTEMPT_NUMBER) { + throw new RuntimeException("Reach max retries for find available port and yet there is still:", e); + } + + return findAvailablePort(numberOfAttempt + 1); + } + } + + @Override + public void close() throws Exception { + Files.delete(LOCK_DIRECTORY.resolve(String.format("%d.lock", this.libreOfficePort))); + } + + public int getLibreOfficePort() { + return libreOfficePort; + } +} diff --git a/libreoffice/src/test/java/fr/gouv/vitam/griffins/libreoffice/MainTest.java b/libreoffice/src/test/java/fr/gouv/vitam/griffins/libreoffice/MainTest.java index daa3d98..784c09b 100755 --- a/libreoffice/src/test/java/fr/gouv/vitam/griffins/libreoffice/MainTest.java +++ b/libreoffice/src/test/java/fr/gouv/vitam/griffins/libreoffice/MainTest.java @@ -35,10 +35,6 @@ import fr.gouv.vitam.griffins.libreoffice.pojo.Result; import fr.gouv.vitam.griffins.libreoffice.pojo.Values; import fr.gouv.vitam.griffins.libreoffice.status.GriffinStatus; -import org.jodconverter.office.LocalOfficeManager; -import org.jodconverter.office.OfficeException; -import org.junit.AfterClass; -import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -78,19 +74,6 @@ public class MainTest { @Rule public TemporaryFolder tmpGriffinFolder = new TemporaryFolder(); - private static LocalOfficeManager officeManager; - - @BeforeClass - public static void setup() throws OfficeException { - officeManager = LocalOfficeManager.install(); - officeManager.start(); - } - - @AfterClass - public static void clean() throws OfficeException { - officeManager.stop(); - } - @Test public void should_GENERATE_DOC_file_from_odt() { // Given @@ -174,13 +157,14 @@ public void should_GENERATE_for_multiple_instance() { assertThat(actual).hasSize(4); assertThat(actual).extracting(Output::getAction).allMatch(a -> a.equals(GENERATE)); assertThat(actual).extracting(Output::getStatus).allMatch(s -> s.equals(OK)); - assertThat(actual).extracting(Output::getOutputName).containsExactlyElementsOf(names.stream().map(s -> String.format("%s.pdf", s)).collect(Collectors.toList())); + assertThat(actual).extracting(Output::getOutputName) + .containsExactlyElementsOf(names.stream().map(s -> String.format("%s.pdf", s)).collect(Collectors.toList())); } @Test public void should_GENERATE_for_big_number_of_file() { String sourceName = "test.odt"; - List names = IntStream.range(0, 400) + List names = IntStream.range(0, 30) .mapToObj(i -> String.format("%d_%s", i, sourceName)) .collect(Collectors.toList()); @@ -207,7 +191,7 @@ public void should_GENERATE_for_big_number_of_file() { // Then assertThat(actual).extracting(Output::getAction).allMatch(a -> a.equals(GENERATE)); assertThat(actual).extracting(Output::getStatus).allMatch(s -> s.equals(OK)); - assertThat(actual).hasSize(400); + assertThat(actual).hasSize(names.size()); } @Test @@ -336,7 +320,8 @@ private Parameters generateBatch(Action action, Input input, String sourceName) parameters.setActions(Collections.singletonList(action)); parameters.setInputs(Collections.singletonList(input)); - FileAttribute> setFileAttribute = PosixFilePermissions.asFileAttribute(Files.getPosixFilePermissions(batchFolder, NOFOLLOW_LINKS)); + FileAttribute> setFileAttribute = + PosixFilePermissions.asFileAttribute(Files.getPosixFilePermissions(batchFolder, NOFOLLOW_LINKS)); File parametersFile = Files.createFile(Paths.get(batchFolder.toString(), parametersFileName), setFileAttribute).toFile(); objectMapper.writer().writeValue(parametersFile, parameters);