001/*
002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     Nuxeo - initial API and implementation
011 *
012 * $Id$
013 */
014
015package org.nuxeo.ecm.core.convert.extension;
016
017import java.io.Serializable;
018import java.util.ArrayList;
019import java.util.List;
020import java.util.Map;
021
022import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
023import org.nuxeo.ecm.core.convert.api.ConversionException;
024import org.nuxeo.ecm.core.convert.service.ConversionServiceImpl;
025import org.nuxeo.ecm.core.convert.service.MimeTypeTranslationHelper;
026import org.nuxeo.runtime.api.Framework;
027
028/**
029 * Specific {@link Converter} implementation that acts as a converters chain.
030 * <p>
031 * The chain can be:
032 * <ul>
033 * <li>a chain of mime-types
034 * <li>a chain of converter names
035 * </ul>
036 * <p>
037 * This depends on the properties of the descriptor.
038 *
039 * @author tiry
040 */
041public class ChainedConverter implements Converter {
042
043    protected boolean subConvertersBased = false;
044
045    protected List<String> steps = new ArrayList<String>();
046
047    protected List<String> subConverters = new ArrayList<String>();
048
049    public ChainedConverter() {
050        subConvertersBased = false;
051        subConverters = null;
052    }
053
054    public ChainedConverter(List<String> subConverters) {
055        subConvertersBased = true;
056        this.subConverters = subConverters;
057        steps = null;
058    }
059
060    @Override
061    public BlobHolder convert(BlobHolder blobHolder, Map<String, Serializable> parameters) throws ConversionException {
062
063        if (subConvertersBased) {
064            return convertBasedSubConverters(blobHolder, parameters);
065        } else {
066            return convertBasedOnMimeTypes(blobHolder, parameters);
067        }
068    }
069
070    protected BlobHolder convertBasedSubConverters(BlobHolder blobHolder, Map<String, Serializable> parameters)
071            throws ConversionException {
072        String srcMT = blobHolder.getBlob().getMimeType();
073        BlobHolder result = blobHolder;
074        for (String converterName : subConverters) {
075            ConverterDescriptor desc = ConversionServiceImpl.getConverterDescriptor(converterName);
076            if (!desc.getSourceMimeTypes().contains(srcMT)) {
077                throw new ConversionException("Conversion Chain is not well defined");
078            }
079            Converter converter = ConversionServiceImpl.getConverter(converterName);
080            result = converter.convert(result, parameters);
081            srcMT = desc.getDestinationMimeType();
082        }
083        return result;
084    }
085
086    /**
087     * Tries to find a chain of converters that fits the mime-types chain.
088     */
089    protected BlobHolder convertBasedOnMimeTypes(BlobHolder blobHolder, Map<String, Serializable> parameters)
090            throws ConversionException {
091        String srcMT = blobHolder.getBlob().getMimeType();
092        BlobHolder result = blobHolder;
093        for (String dstMT : steps) {
094            String converterName = Framework.getService(MimeTypeTranslationHelper.class).getConverterName(srcMT, dstMT);
095            if (converterName == null) {
096                throw new ConversionException(
097                        "Chained conversion error : unable to find converter between " + srcMT + " and " + dstMT);
098            }
099            Converter converter = ConversionServiceImpl.getConverter(converterName);
100            result = converter.convert(result, parameters);
101            srcMT = dstMT;
102        }
103        return result;
104    }
105
106    @Override
107    public void init(ConverterDescriptor descriptor) {
108        if (!subConvertersBased) {
109            steps.addAll(descriptor.getSteps());
110            steps.add(descriptor.getDestinationMimeType());
111        } else {
112            ConverterDescriptor fconv = ConversionServiceImpl.getConverterDescriptor(subConverters.get(0));
113            ConverterDescriptor lconv = ConversionServiceImpl.getConverterDescriptor(subConverters.get(subConverters.size() - 1));
114
115            descriptor.sourceMimeTypes = fconv.sourceMimeTypes;
116            descriptor.destinationMimeType = lconv.destinationMimeType;
117        }
118    }
119
120    public List<String> getSteps() {
121        return steps;
122    }
123
124    /**
125     * Returns the sub converters of this chained converter.
126     *
127     * @since 5.9.2
128     */
129    public List<String> getSubConverters() {
130        return subConverters;
131    }
132
133    /**
134     * Returns true if this chained converter is sub converters based, false otherwise.
135     *
136     * @since 5.9.4
137     */
138    public boolean isSubConvertersBased() {
139        return subConvertersBased;
140    }
141}