001/* 002 * (C) Copyright 2006-2011 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 * Nuxeo - initial API and implementation 018 * 019 * $Id$ 020 */ 021 022package org.nuxeo.ecm.core.convert.extension; 023 024import java.io.Serializable; 025import java.util.ArrayList; 026import java.util.List; 027import java.util.Map; 028import java.util.Objects; 029 030import org.nuxeo.ecm.core.api.Blob; 031import org.nuxeo.ecm.core.api.blobholder.BlobHolder; 032import org.nuxeo.ecm.core.convert.api.ConversionException; 033import org.nuxeo.ecm.core.convert.api.ConversionService; 034import org.nuxeo.ecm.core.convert.service.ConversionServiceImpl; 035import org.nuxeo.runtime.api.Framework; 036 037/** 038 * Specific {@link Converter} implementation that acts as a converters chain. 039 * <p> 040 * The chain can be: 041 * <ul> 042 * <li>a chain of mime-types 043 * <li>a chain of converter names 044 * </ul> 045 * <p> 046 * This depends on the properties of the descriptor. 047 * 048 * @author tiry 049 */ 050public class ChainedConverter implements Converter { 051 052 protected boolean subConvertersBased; 053 054 protected List<String> steps = new ArrayList<>(); 055 056 protected List<String> subConverters = new ArrayList<>(); 057 058 public ChainedConverter() { 059 subConvertersBased = false; 060 subConverters = null; 061 } 062 063 public ChainedConverter(List<String> subConverters) { 064 subConvertersBased = true; 065 this.subConverters = subConverters; 066 steps = null; 067 } 068 069 @Override 070 public BlobHolder convert(BlobHolder blobHolder, Map<String, Serializable> parameters) throws ConversionException { 071 072 if (subConvertersBased) { 073 return convertBasedSubConverters(blobHolder, parameters); 074 } else { 075 return convertBasedOnMimeTypes(blobHolder, parameters); 076 } 077 } 078 079 protected BlobHolder convertBasedSubConverters(BlobHolder blobHolder, Map<String, Serializable> parameters) 080 throws ConversionException { 081 String srcMT = blobHolder.getBlob().getMimeType(); 082 BlobHolder result = blobHolder; 083 for (String converterName : subConverters) { 084 ConverterDescriptor desc = ConversionServiceImpl.getConverterDescriptor(converterName); 085 if (!desc.getSourceMimeTypes().contains(srcMT)) { 086 throw new ConversionException("Conversion Chain is not well defined", blobHolder); 087 } 088 Converter converter = ConversionServiceImpl.getConverter(converterName); 089 result = converter.convert(result, parameters); 090 // Mark for deletion intermediate results 091 if (subConverters.indexOf(converterName) != subConverters.size() - 1) { 092 result.getBlobs() 093 .stream() 094 .map(Blob::getFile) 095 .filter(Objects::nonNull) 096 .forEach(file -> Framework.trackFile(file, file)); 097 } 098 srcMT = desc.getDestinationMimeType(); 099 } 100 return result; 101 } 102 103 /** 104 * Tries to find a chain of converters that fits the mime-types chain. 105 */ 106 protected BlobHolder convertBasedOnMimeTypes(BlobHolder blobHolder, Map<String, Serializable> parameters) 107 throws ConversionException { 108 String srcMT = blobHolder.getBlob().getMimeType(); 109 BlobHolder result = blobHolder; 110 for (String dstMT : steps) { 111 String converterName = Framework.getService(ConversionService.class).getConverterName(srcMT, dstMT); 112 if (converterName == null) { 113 throw new ConversionException( 114 "Chained conversion error : unable to find converter between " + srcMT + " and " + dstMT, 115 blobHolder); 116 } 117 Converter converter = ConversionServiceImpl.getConverter(converterName); 118 result = converter.convert(result, parameters); 119 srcMT = dstMT; 120 } 121 return result; 122 } 123 124 @Override 125 public void init(ConverterDescriptor descriptor) { 126 if (!subConvertersBased) { 127 steps.addAll(descriptor.getSteps()); 128 steps.add(descriptor.getDestinationMimeType()); 129 } else { 130 ConverterDescriptor fconv = ConversionServiceImpl.getConverterDescriptor(subConverters.get(0)); 131 ConverterDescriptor lconv = ConversionServiceImpl.getConverterDescriptor( 132 subConverters.get(subConverters.size() - 1)); 133 134 descriptor.sourceMimeTypes = fconv.sourceMimeTypes; 135 descriptor.destinationMimeType = lconv.destinationMimeType; 136 } 137 } 138 139 public List<String> getSteps() { 140 return steps; 141 } 142 143 /** 144 * Returns the sub converters of this chained converter. 145 * 146 * @since 5.9.2 147 */ 148 public List<String> getSubConverters() { 149 return subConverters; 150 } 151 152 /** 153 * Returns true if this chained converter is sub converters based, false otherwise. 154 * 155 * @since 5.9.4 156 */ 157 public boolean isSubConvertersBased() { 158 return subConvertersBased; 159 } 160}