001/*
002 * (C) Copyright 2014-2016 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Thomas Roger
018 */
019
020package org.nuxeo.ecm.platform.convert.plugins;
021
022import java.io.File;
023import java.io.IOException;
024import java.io.Serializable;
025import java.nio.file.Files;
026import java.nio.file.Path;
027import java.nio.file.Paths;
028import java.util.ArrayList;
029import java.util.Arrays;
030import java.util.HashMap;
031import java.util.List;
032import java.util.Map;
033
034import org.nuxeo.common.utils.FileUtils;
035import org.nuxeo.ecm.core.api.Blob;
036import org.nuxeo.ecm.core.api.Blobs;
037import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
038import org.nuxeo.ecm.core.convert.api.ConversionException;
039import org.nuxeo.ecm.core.convert.cache.SimpleCachableBlobHolder;
040import org.nuxeo.ecm.platform.commandline.executor.api.CmdParameters;
041import org.nuxeo.runtime.api.Framework;
042
043/**
044 * Generic converter executing a contributed command line.
045 * <p>
046 * The command line to call is stored in the {@code CommandLineName} parameter.
047 * <p>
048 * The target file name is in the {@code targetFileName} parameter. If it's null, a temporary one will be created.
049 * <p>
050 * All the converter parameters are passed to the command line.
051 * <p>
052 * A sample contribution using this converter:
053 *
054 * <pre>
055 * {@code
056 *     <converter name="pdf2image" class="org.nuxeo.ecm.platform.convert.plugins.CommandLineConverter">
057 *       <sourceMimeType>application/pdf</sourceMimeType>
058 *       <destinationMimeType>image/jpeg</destinationMimeType>
059 *       <destinationMimeType>image/png</destinationMimeType>
060 *       <destinationMimeType>image/gif</destinationMimeType>
061 *       <parameters>
062 *         <parameter name="CommandLineName">pdftoimage</parameter>
063 *       </parameters>
064 *     </converter>
065 * }
066 * </pre>
067 *
068 * @since 7.1
069 */
070public class CommandLineConverter extends CommandLineBasedConverter {
071
072    public static final String SOURCE_FILE_PATH_KEY = "sourceFilePath";
073
074    public static final String OUT_DIR_PATH_KEY = "outDirPath";
075
076    public static final String TARGET_FILE_NAME_KEY = "targetFileName";
077
078    public static final String TARGET_FILE_PATH_KEY = "targetFilePath";
079
080    public static final List<String> RESERVED_PARAMETERS = Arrays.asList(SOURCE_FILE_PATH_KEY, OUT_DIR_PATH_KEY,
081            TARGET_FILE_PATH_KEY, CMD_NAME_PARAMETER);
082
083    @Override
084    protected Map<String, Blob> getCmdBlobParameters(BlobHolder blobHolder, Map<String, Serializable> parameters)
085            throws ConversionException {
086        Map<String, Blob> cmdBlobParams = new HashMap<>();
087        cmdBlobParams.put(SOURCE_FILE_PATH_KEY, blobHolder.getBlob());
088        return cmdBlobParams;
089    }
090
091    @Override
092    protected Map<String, String> getCmdStringParameters(BlobHolder blobHolder, Map<String, Serializable> parameters)
093            throws ConversionException {
094        String tmpDir = getTmpDirectory(parameters);
095        Path tmpDirPath = tmpDir != null ? Paths.get(tmpDir) : null;
096        try {
097            String prefix = String.format("clc-%s-", FileUtils.getSafeFilename(getCommandName(blobHolder, parameters)));
098            Path outDirPath = tmpDirPath != null ? Files.createTempDirectory(tmpDirPath, prefix)
099                    : Framework.createTempDirectory(prefix);
100
101            Map<String, String> cmdStringParams = new HashMap<>();
102            cmdStringParams.put(OUT_DIR_PATH_KEY, outDirPath.toString());
103
104            String targetFileName = (String) parameters.get(TARGET_FILE_NAME_KEY);
105            Path targetFilePath;
106            if (targetFileName == null) {
107                targetFilePath = Files.createTempFile(outDirPath, null, null);
108            } else {
109                targetFilePath = Paths.get(outDirPath.toString(), targetFileName);
110            }
111            cmdStringParams.put(TARGET_FILE_PATH_KEY, targetFilePath.toString());
112            if (targetFileName == null) {
113                // do not keep a temporary file, just created to get a path
114                Files.delete(targetFilePath);
115            }
116
117            // pass all converter parameters to the command line
118            for (Map.Entry<String, Serializable> entry : parameters.entrySet()) {
119                if (!RESERVED_PARAMETERS.contains(entry.getKey())) {
120                    cmdStringParams.put(entry.getKey(), (String) entry.getValue());
121                }
122            }
123            // pass all the converter descriptor parameters to the commandline
124            for (Map.Entry<String, String> entry : initParameters.entrySet()) {
125                if (!RESERVED_PARAMETERS.contains(entry.getKey())) {
126                    cmdStringParams.put(entry.getKey(), entry.getValue());
127                }
128            }
129
130            return cmdStringParams;
131        } catch (IOException e) {
132            throw new ConversionException(e.getMessage(), blobHolder, e);
133        }
134    }
135
136    @Override
137    protected BlobHolder buildResult(List<String> cmdOutput, CmdParameters cmdParams) throws ConversionException {
138        String outputPath = cmdParams.getParameter(OUT_DIR_PATH_KEY);
139        List<Blob> blobs = new ArrayList<>();
140        File outputDir = new File(outputPath);
141        if (outputDir.exists() && outputDir.isDirectory()) {
142            File[] files = outputDir.listFiles();
143            if (files != null) {
144                for (File file : files) {
145                    try {
146                        Blob blob = Blobs.createBlob(file);
147                        blob.setFilename(file.getName());
148                        blobs.add(blob);
149                    } catch (IOException e) {
150                        throw new ConversionException("Cannot create blob", e);
151                    }
152                }
153            }
154        }
155        Framework.trackFile(outputDir, blobs); // Mark the temporary folder for deletion
156        return new SimpleCachableBlobHolder(blobs);
157    }
158
159}