001/*
002 * (C) Copyright 2006-2014 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 */
020package org.nuxeo.ecm.core.convert.extension;
021
022import java.util.ArrayList;
023import java.util.HashMap;
024import java.util.List;
025import java.util.Map;
026
027import org.apache.commons.logging.Log;
028import org.apache.commons.logging.LogFactory;
029import org.nuxeo.common.xmap.annotation.XNode;
030import org.nuxeo.common.xmap.annotation.XNodeList;
031import org.nuxeo.common.xmap.annotation.XNodeMap;
032import org.nuxeo.common.xmap.annotation.XObject;
033
034/**
035 * XMap descriptor for the contribution of a new {@link Converter}.
036 *
037 * @author tiry
038 */
039@XObject("converter")
040public class ConverterDescriptor {
041
042    protected final Log log = LogFactory.getLog(ConverterDescriptor.class);
043
044    public static final String CUSTOM_CONVERTER_TYPE = "Custom";
045
046    public static final String CHAINED_CONVERTER_TYPE = "Chain";
047
048    protected Converter instance;
049
050    @XNode("@name")
051    protected String converterName;
052
053    @XNodeList(value = "sourceMimeType", type = ArrayList.class, componentType = String.class)
054    protected List<String> sourceMimeTypes = new ArrayList<>();
055
056    @XNode("destinationMimeType")
057    protected String destinationMimeType;
058
059    @XNode("@class")
060    protected Class<?> className;
061
062    @XNode("@type")
063    protected String converterType = CUSTOM_CONVERTER_TYPE;
064
065    @XNode("@bypassIfSameMimeType")
066    protected Boolean bypassIfSameMimeType;
067
068    protected boolean wrappedTransformer = false;
069
070    @XNodeMap(value = "parameters/parameter", key = "@name", type = HashMap.class, componentType = String.class)
071    protected Map<String, String> parameters = new HashMap<>();
072
073    @XNodeList(value = "conversionSteps/step", type = ArrayList.class, componentType = String.class)
074    protected List<String> steps = new ArrayList<>();
075
076    @XNodeList(value = "conversionSteps/subconverter", type = ArrayList.class, componentType = String.class)
077    protected List<String> subConverters = new ArrayList<>();
078
079    /**
080     * Returns whether the conversion should be bypassed if the input blob mime type equals the converter destination mime type.
081     *
082     * @since 11.1
083     */
084    public boolean isBypassIfSameMimeType() {
085        return Boolean.TRUE.equals(bypassIfSameMimeType);
086    }
087
088    public String getConverterName() {
089        return converterName;
090    }
091
092    public List<String> getSourceMimeTypes() {
093        return sourceMimeTypes;
094    }
095
096    public List<String> getSteps() {
097        return steps;
098    }
099
100    public String getDestinationMimeType() {
101        return destinationMimeType;
102    }
103
104    public void initConverter() {
105        if (instance == null) {
106            if (className == null || converterType.equals(CHAINED_CONVERTER_TYPE)) {
107
108                if (subConverters == null || subConverters.isEmpty()) {
109                    // create a Chained converter based on mimetypes
110                    instance = new ChainedConverter();
111                } else {
112                    // create a Chained converter based on converter chain
113                    instance = new ChainedConverter(subConverters);
114                }
115                converterType = CHAINED_CONVERTER_TYPE;
116            } else {
117                try {
118                    instance = (Converter) className.getDeclaredConstructor().newInstance();
119                } catch (ReflectiveOperationException e) {
120                    throw new RuntimeException(e);
121                }
122            }
123            instance.init(this);
124        }
125    }
126
127    public Converter getConverterInstance() {
128        initConverter();
129        return instance;
130    }
131
132    public Map<String, String> getParameters() {
133        return parameters;
134    }
135
136    public ConverterDescriptor merge(ConverterDescriptor other) {
137
138        if (!other.converterName.equals(converterName)) {
139            throw new UnsupportedOperationException("Can not merge ConverterDesciptors with different names");
140        }
141
142        if (wrappedTransformer) {
143            // converter completely override wrapped transformers
144            return other;
145        }
146
147        if (other.parameters != null) {
148            parameters.putAll(other.parameters);
149        }
150        if (other.className != null) {
151            instance = null;
152            className = other.className;
153        }
154        if (other.sourceMimeTypes != null) {
155            for (String mt : other.sourceMimeTypes) {
156                if (!sourceMimeTypes.contains(mt)) {
157                    sourceMimeTypes.add(mt);
158                }
159
160            }
161            // sourceMimeTypes.addAll(other.sourceMimeTypes);
162        }
163        if (other.destinationMimeType != null) {
164            destinationMimeType = other.destinationMimeType;
165        }
166        if (other.converterType != null) {
167            converterType = other.converterType;
168        }
169        if (other.steps != null && !other.steps.isEmpty()) {
170            steps = other.steps;
171        }
172        if (other.bypassIfSameMimeType != null) {
173            bypassIfSameMimeType = other.bypassIfSameMimeType;
174        }
175
176        return this;
177    }
178
179    public String getConverterType() {
180        return converterType;
181    }
182
183}