001/* 002 * (C) Copyright 2006-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 * Tiago Cardoso <tcardoso@nuxeo.com> 018 */ 019package org.nuxeo.ecm.platform.threed.convert; 020 021import org.apache.commons.io.FileUtils; 022import org.nuxeo.common.utils.Path; 023import org.nuxeo.ecm.core.api.Blob; 024import org.nuxeo.ecm.core.api.blobholder.BlobHolder; 025import org.nuxeo.ecm.core.api.blobholder.SimpleBlobHolderWithProperties; 026import org.nuxeo.ecm.core.api.impl.blob.FileBlob; 027import org.nuxeo.ecm.core.convert.api.ConversionException; 028import org.nuxeo.ecm.platform.commandline.executor.api.CmdParameters; 029import org.nuxeo.ecm.platform.commandline.executor.api.CommandException; 030import org.nuxeo.ecm.platform.commandline.executor.api.CommandLineExecutorService; 031import org.nuxeo.ecm.platform.commandline.executor.api.CommandNotAvailable; 032import org.nuxeo.ecm.platform.commandline.executor.api.ExecResult; 033import org.nuxeo.ecm.platform.convert.plugins.CommandLineBasedConverter; 034import org.nuxeo.runtime.api.Framework; 035 036import java.io.File; 037import java.io.IOException; 038import java.io.Serializable; 039import java.io.UncheckedIOException; 040import java.util.*; 041import java.util.stream.Collectors; 042 043import static org.nuxeo.ecm.platform.threed.convert.Constants.*; 044 045/** 046 * Conversion from Collada to glTF format 047 * 048 * @since 8.4 049 */ 050public class Collada2glTFConverter extends CommandLineBasedConverter { 051 052 @Override 053 protected Map<String, Blob> getCmdBlobParameters(BlobHolder blobHolder, Map<String, Serializable> parameters) 054 throws ConversionException { 055 return null; 056 } 057 058 @Override 059 protected Map<String, String> getCmdStringParameters(BlobHolder blobHolder, Map<String, Serializable> parameters) 060 throws ConversionException { 061 return null; 062 } 063 064 // Let's override to make sure we keep the original blob names! 065 @Override 066 public BlobHolder convert(BlobHolder blobHolder, Map<String, Serializable> parameters) throws ConversionException { 067 068 String dataContainer = "data" + String.valueOf(Calendar.getInstance().getTime().getTime()); 069 String convertContainer = "convert" + String.valueOf(Calendar.getInstance().getTime().getTime()); 070 String commandName = getCommandName(blobHolder, parameters); 071 if (commandName == null) { 072 throw new ConversionException("Unable to determine target CommandLine name"); 073 } 074 075 CmdParameters params = new CmdParameters(); 076 List<String> filesToDelete = new ArrayList<>(); 077 078 try { 079 Path directory = new Path(getTmpDirectory(parameters)).append( 080 DAE2GLTF_PATH_PREFIX + UUID.randomUUID() + "_in"); 081 boolean dirCreated = new File(directory.toString()).mkdirs(); 082 if (!dirCreated) { 083 throw new ConversionException("Unable to create tmp dir: " + directory); 084 } 085 086 List<Blob> blobs = blobHolder.getBlobs(); 087 // Add the main and assets as params 088 // The params are not used by the command but the blobs are extracted to files and managed 089 filesToDelete = blobs.stream().map(blob -> { 090 File file = new File(directory.append(blob.getFilename()).toString()); 091 try { 092 blob.transferTo(file); 093 } catch (IOException e) { 094 throw new UncheckedIOException(e); 095 } 096 return file.getAbsolutePath(); 097 }).collect(Collectors.toList()); 098 Path inputFile = new Path(filesToDelete.get(0)); 099 params.addNamedParameter(INPUT_FILE_PARAMETER, inputFile.lastSegment()); 100 101 ExecResult createRes = DockerHelper.CreateContainer(dataContainer, "nuxeo/collada2gltf"); 102 if (createRes == null || !createRes.isSuccessful()) { 103 throw new ConversionException("Unable to create data volume : " + dataContainer, 104 (createRes != null) ? createRes.getError() : null); 105 } 106 ExecResult copyRes = DockerHelper.CopyData( 107 inputFile.removeLastSegments(1).toString() + File.separatorChar + ".", dataContainer + ":/in/"); 108 if (copyRes == null || !copyRes.isSuccessful()) { 109 throw new ConversionException("Unable to copy to data volume : " + dataContainer, 110 (copyRes != null) ? copyRes.getError() : null); 111 } 112 params.addNamedParameter(NAME_PARAM, convertContainer); 113 params.addNamedParameter(DATA_PARAM, dataContainer); 114 filesToDelete.add(directory.toString()); 115 116 String baseDir = getTmpDirectory(parameters); 117 Path outPath = new Path(baseDir).append(DAE2GLTF_OUTPUT_PATH_PREFIX + UUID.randomUUID() + "_out"); 118 File outDir = new File(outPath.toString()); 119 dirCreated = outDir.mkdir(); 120 if (!dirCreated) { 121 throw new ConversionException("Unable to create tmp dir for transformer output: " + outDir); 122 } 123 params.addNamedParameter(OUTPUT_FILE_PARAMETER, inputFile.removeFileExtension().lastSegment() + ".gltf"); 124 params.addNamedParameter(OUT_DIR_PARAMETER, outPath.toString()); 125 // params.addNamedParameter(USER_ID_PARAMETER, UserIdHelper.getUid()); 126 127 ExecResult result = Framework.getService(CommandLineExecutorService.class).execCommand(commandName, params); 128 if (!result.isSuccessful()) { 129 throw result.getError(); 130 } 131 132 copyRes = DockerHelper.CopyData(dataContainer + ":/out/.", outPath.toString()); 133 if (copyRes == null || !copyRes.isSuccessful()) { 134 throw new ConversionException("Unable to copy from data volume : " + dataContainer, 135 (copyRes != null) ? copyRes.getError() : null); 136 } 137 return buildResult(result.getOutput(), params); 138 } catch (CommandNotAvailable e) { 139 // XXX bubble installation instructions 140 throw new ConversionException("Unable to find targetCommand", e); 141 } catch (CommandException e) { 142 throw new ConversionException("Error while converting via CommandLineService", e); 143 } finally { 144 for (String fileToDelete : filesToDelete) { 145 FileUtils.deleteQuietly(new File(fileToDelete)); 146 } 147 DockerHelper.RemoveContainer(dataContainer); 148 DockerHelper.RemoveContainer(convertContainer); 149 } 150 } 151 152 @Override 153 protected BlobHolder buildResult(List<String> cmdOutput, CmdParameters cmdParameters) throws ConversionException { 154 File outputFile = new File(cmdParameters.getParameter(OUT_DIR_PARAMETER) + File.separator 155 + cmdParameters.getParameter(OUTPUT_FILE_PARAMETER)); 156 List<Blob> blobs = new ArrayList<>(); 157 blobs.add(new FileBlob(outputFile)); 158 Map<String, Serializable> properties = new HashMap<>(); 159 properties.put("cmdOutput", (Serializable) cmdOutput); 160 return new SimpleBlobHolderWithProperties(blobs, properties); 161 } 162 163}