001/*
002 * (C) Copyright 2006-2012 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.template.adapters.source;
021
022import java.io.IOException;
023import java.io.Serializable;
024import java.util.ArrayList;
025import java.util.Arrays;
026import java.util.List;
027
028import org.dom4j.DocumentException;
029import org.nuxeo.ecm.core.api.Blob;
030import org.nuxeo.ecm.core.api.DocumentModel;
031import org.nuxeo.ecm.core.api.NuxeoException;
032import org.nuxeo.ecm.core.api.PropertyException;
033import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
034import org.nuxeo.runtime.api.Framework;
035import org.nuxeo.template.XMLSerializer;
036import org.nuxeo.template.adapters.AbstractTemplateDocument;
037import org.nuxeo.template.api.TemplateInput;
038import org.nuxeo.template.api.TemplateProcessor;
039import org.nuxeo.template.api.TemplateProcessorService;
040import org.nuxeo.template.api.adapters.TemplateBasedDocument;
041import org.nuxeo.template.api.adapters.TemplateSourceDocument;
042
043/**
044 * Default implementation of {@link TemplateSourceDocument}. It mainly expect from the underlying DocumentModel to have
045 * the "Template" facet.
046 *
047 * @author Tiry (tdelprat@nuxeo.com)
048 */
049public class TemplateSourceDocumentAdapterImpl extends AbstractTemplateDocument implements Serializable,
050        TemplateSourceDocument {
051
052    public static final String TEMPLATE_DATA_PROP = "tmpl:templateData";
053
054    public static final String TEMPLATE_NAME_PROP = "tmpl:templateName";
055
056    public static final String TEMPLATE_TYPE_PROP = "tmpl:templateType";
057
058    public static final String TEMPLATE_TYPE_AUTO = "auto";
059
060    public static final String TEMPLATE_APPLICABLE_TYPES_PROP = "tmpl:applicableTypes";
061
062    public static final String TEMPLATE_APPLICABLE_TYPES_ALL = "all";
063
064    public static final String TEMPLATE_FORCED_TYPES_PROP = "tmpl:forcedTypes";
065
066    public static final String TEMPLATE_FORCED_TYPES_ITEM_PROP = "tmpl:forcedTypes/*";
067
068    public static final String TEMPLATE_FORCED_TYPES_NONE = "none";
069
070    public static final String TEMPLATE_RENDITION_NONE = "none";
071
072    public static final String TEMPLATE_OUTPUT_PROP = "tmpl:outputFormat";
073
074    public static final String TEMPLATE_OVERRIDE_PROP = "tmpl:allowOverride";
075
076    public static final String TEMPLATE_USEASMAIN_PROP = "tmpl:useAsMainContent";
077
078    public static final String TEMPLATE_RENDITION_PROP = "tmpl:targetRenditionName";
079
080    public static final String TEMPLATE_FACET = "Template";
081
082    private static final long serialVersionUID = 1L;
083
084    public TemplateSourceDocumentAdapterImpl(DocumentModel doc) {
085        this.adaptedDoc = doc;
086    }
087
088    protected String getTemplateParamsXPath() {
089        return TEMPLATE_DATA_PROP;
090    }
091
092    public List<TemplateInput> getParams() {
093        String dataPath = getTemplateParamsXPath();
094
095        if (adaptedDoc.getPropertyValue(dataPath) == null) {
096            return new ArrayList<TemplateInput>();
097        }
098        String xml = adaptedDoc.getPropertyValue(dataPath).toString();
099
100        try {
101            return XMLSerializer.readFromXml(xml);
102        } catch (DocumentException e) {
103            log.error("Unable to parse parameters", e);
104            return new ArrayList<TemplateInput>();
105        }
106    }
107
108    public boolean hasEditableParams() {
109        for (TemplateInput param : getParams()) {
110            if (!param.isReadOnly()) {
111                return true;
112            }
113        }
114        return false;
115    }
116
117    public DocumentModel saveParams(List<TemplateInput> params, boolean save) {
118        String dataPath = getTemplateParamsXPath();
119        String xml = XMLSerializer.serialize(params);
120        adaptedDoc.setPropertyValue(dataPath, xml);
121        adaptedDoc.putContextData(TemplateSourceDocument.INIT_DONE_FLAG, true);
122        if (save) {
123            doSave();
124        }
125        return adaptedDoc;
126    }
127
128    protected TemplateProcessor getTemplateProcessor() {
129        TemplateProcessorService tps = Framework.getLocalService(TemplateProcessorService.class);
130        return tps.getProcessor(getTemplateType());
131    }
132
133    public String getParamsAsString() throws PropertyException {
134        String dataPath = getTemplateParamsXPath();
135
136        if (adaptedDoc.getPropertyValue(dataPath) == null) {
137            return null;
138        }
139        return adaptedDoc.getPropertyValue(dataPath).toString();
140    }
141
142    public List<TemplateInput> addInput(TemplateInput input) {
143
144        List<TemplateInput> params = getParams();
145        if (input == null) {
146            return params;
147        }
148
149        boolean newParam = true;
150        if (params == null) {
151            params = new ArrayList<TemplateInput>();
152        }
153        for (TemplateInput param : params) {
154            if (param.getName().equals(input.getName())) {
155                newParam = false;
156                param.update(input);
157                break;
158            }
159        }
160        if (newParam) {
161            params.add(input);
162        }
163        saveParams(params, false);
164
165        return params;
166    }
167
168    public String getTemplateType() {
169        String ttype = (String) getAdaptedDoc().getPropertyValue(TEMPLATE_TYPE_PROP);
170        if (TEMPLATE_TYPE_AUTO.equals(ttype)) {
171            return null;
172        }
173        return ttype;
174    }
175
176    public void initTemplate(boolean save) {
177        // avoid duplicate init
178        if (getAdaptedDoc().getContextData(TemplateSourceDocument.INIT_DONE_FLAG) == null) {
179            Blob blob = getTemplateBlob();
180            if (blob != null) {
181                if (getTemplateType() == null) {
182                    TemplateProcessorService tps = Framework.getLocalService(TemplateProcessorService.class);
183                    String templateType = tps.findProcessorName(blob);
184                    if (templateType != null) {
185                        getAdaptedDoc().setPropertyValue(TEMPLATE_TYPE_PROP, templateType);
186                    }
187                }
188
189                String tmplName = (String) getAdaptedDoc().getPropertyValue(TEMPLATE_NAME_PROP);
190                if (tmplName == null || tmplName.isEmpty()) {
191                    tmplName = computeTemplateName();
192                    getAdaptedDoc().setPropertyValue(TEMPLATE_NAME_PROP, tmplName);
193                }
194
195                TemplateProcessor processor = getTemplateProcessor();
196                if (processor != null) {
197                    List<TemplateInput> params;
198                    try {
199                        params = processor.getInitialParametersDefinition(blob);
200                    } catch (IOException e) {
201                        throw new NuxeoException(e);
202                    }
203                    saveParams(params, save);
204                }
205                getAdaptedDoc().getContextData().put(TemplateSourceDocument.INIT_DONE_FLAG, true);
206            }
207        }
208    }
209
210    protected String computeTemplateName() {
211        return getAdaptedDoc().getTitle();
212    }
213
214    public boolean allowInstanceOverride() {
215        Boolean allowOverride = (Boolean) getAdaptedDoc().getPropertyValue(TEMPLATE_OVERRIDE_PROP);
216        if (allowOverride == null) {
217            allowOverride = true;
218        }
219        return allowOverride;
220    }
221
222    public void initTypesBindings() {
223
224        // manage applicable types
225        String[] applicableTypesArray = (String[]) getAdaptedDoc().getPropertyValue(TEMPLATE_APPLICABLE_TYPES_PROP);
226
227        String[] newApplicableTypesArray = null;
228
229        if (applicableTypesArray == null || applicableTypesArray.length == 0) {
230            newApplicableTypesArray = new String[] { TEMPLATE_APPLICABLE_TYPES_ALL };
231        } else if (applicableTypesArray.length > 1) {
232            if (TEMPLATE_APPLICABLE_TYPES_ALL.equals(applicableTypesArray[0])) {
233                List<String> at = Arrays.asList(applicableTypesArray);
234                at.remove(0);
235                newApplicableTypesArray = at.toArray(new String[at.size()]);;
236            }
237        }
238        if (newApplicableTypesArray != null) {
239            getAdaptedDoc().setPropertyValue(TEMPLATE_APPLICABLE_TYPES_PROP, newApplicableTypesArray);
240        }
241
242        // manage forcedTypes
243        String[] forcedTypesArray = (String[]) getAdaptedDoc().getPropertyValue(TEMPLATE_FORCED_TYPES_PROP);
244        String[] newForcedTypesArray = null;
245        if (forcedTypesArray == null || forcedTypesArray.length == 0) {
246            newForcedTypesArray = new String[] { TEMPLATE_FORCED_TYPES_NONE };
247        } else if (forcedTypesArray.length > 1) {
248            if (TEMPLATE_FORCED_TYPES_NONE.equals(forcedTypesArray[0])) {
249                List<String> ft = Arrays.asList(forcedTypesArray);
250                ft.remove(0);
251                newForcedTypesArray = ft.toArray(new String[ft.size()]);;
252            }
253        }
254        if (newForcedTypesArray != null) {
255            getAdaptedDoc().setPropertyValue(TEMPLATE_FORCED_TYPES_PROP, newForcedTypesArray);
256        }
257
258    }
259
260    public List<String> getApplicableTypes() {
261        String[] applicableTypesArray = (String[]) getAdaptedDoc().getPropertyValue(TEMPLATE_APPLICABLE_TYPES_PROP);
262        List<String> applicableTypes = new ArrayList<String>();
263        if (applicableTypesArray != null) {
264            applicableTypes.addAll((Arrays.asList(applicableTypesArray)));
265        }
266        if (applicableTypes.size() > 0 && applicableTypes.get(0).equals(TEMPLATE_APPLICABLE_TYPES_ALL)) {
267            applicableTypes.remove(0);
268        }
269        return applicableTypes;
270    }
271
272    public List<String> getForcedTypes() {
273        String[] forcedTypesArray = (String[]) getAdaptedDoc().getPropertyValue(TEMPLATE_FORCED_TYPES_PROP);
274        List<String> applicableTypes = new ArrayList<String>();
275        if (forcedTypesArray != null) {
276            applicableTypes.addAll((Arrays.asList(forcedTypesArray)));
277        }
278        if (applicableTypes.size() > 0 && applicableTypes.get(0).equals(TEMPLATE_FORCED_TYPES_NONE)) {
279            applicableTypes.remove(0);
280        }
281        return applicableTypes;
282    }
283
284    public void removeForcedType(String type, boolean save) {
285        List<String> types = getForcedTypes();
286        if (types.contains(type)) {
287            types.remove(type);
288            String[] typesArray = types.toArray(new String[types.size()]);
289            getAdaptedDoc().setPropertyValue(TemplateSourceDocumentAdapterImpl.TEMPLATE_FORCED_TYPES_PROP, typesArray);
290            if (save) {
291                adaptedDoc = getAdaptedDoc().getCoreSession().saveDocument(getAdaptedDoc());
292            }
293        }
294    }
295
296    public void setForcedTypes(String[] forcedTypes, boolean save) {
297        getAdaptedDoc().setPropertyValue(TemplateSourceDocumentAdapterImpl.TEMPLATE_FORCED_TYPES_PROP, forcedTypes);
298        if (save) {
299            adaptedDoc = getAdaptedDoc().getCoreSession().saveDocument(getAdaptedDoc());
300        }
301    }
302
303    public List<TemplateBasedDocument> getTemplateBasedDocuments() {
304        return Framework.getLocalService(TemplateProcessorService.class).getLinkedTemplateBasedDocuments(adaptedDoc);
305    }
306
307    public String getOutputFormat() {
308        return (String) getAdaptedDoc().getPropertyValue(TEMPLATE_OUTPUT_PROP);
309    }
310
311    public void setOutputFormat(String mimetype, boolean save) {
312        getAdaptedDoc().setPropertyValue(TEMPLATE_OUTPUT_PROP, mimetype);
313        if (save) {
314            doSave();
315        }
316    }
317
318    public boolean useAsMainContent() {
319        Boolean useAsMain = (Boolean) getAdaptedDoc().getPropertyValue(TEMPLATE_USEASMAIN_PROP);
320        if (useAsMain == null) {
321            useAsMain = false;
322        }
323        return useAsMain;
324    }
325
326    public Blob getTemplateBlob() {
327        BlobHolder bh = getAdaptedDoc().getAdapter(BlobHolder.class);
328        if (bh != null) {
329            return bh.getBlob();
330        }
331        return null;
332    }
333
334    public void setTemplateBlob(Blob blob, boolean save) {
335        BlobHolder bh = getAdaptedDoc().getAdapter(BlobHolder.class);
336        if (bh != null) {
337            bh.setBlob(blob);
338            initTemplate(false);
339            if (save) {
340                doSave();
341            }
342        }
343    }
344
345    public String getName() {
346        String name = (String) getAdaptedDoc().getPropertyValue(TEMPLATE_NAME_PROP);
347        if (name == null) {
348            name = getAdaptedDoc().getTitle();
349        }
350        return name;
351    }
352
353    public String getFileName() {
354        Blob blob = getTemplateBlob();
355        if (blob != null) {
356            return blob.getFilename();
357        }
358        return null;
359    }
360
361    public String getTitle() {
362        return getAdaptedDoc().getTitle();
363    }
364
365    public String getVersionLabel() {
366        return getAdaptedDoc().getVersionLabel();
367    }
368
369    public String getId() {
370        return getAdaptedDoc().getId();
371    }
372
373    public String getLabel() {
374        StringBuffer sb = new StringBuffer(getTitle());
375        if (!getTitle().equals(getFileName())) {
376            sb.append(" (" + getFileName() + ")");
377        }
378        if (getVersionLabel() != null) {
379            sb.append(" [" + getVersionLabel() + "]");
380        }
381        return sb.toString();
382    }
383
384    @Override
385    public String getTargetRenditionName() {
386        String targetRendition = (String) getAdaptedDoc().getPropertyValue(TEMPLATE_RENDITION_PROP);
387        if (TEMPLATE_RENDITION_NONE.equals(targetRendition)) {
388            return null;
389        }
390        return targetRendition;
391    }
392
393    public void setTargetRenditioName(String renditionName, boolean save) {
394        getAdaptedDoc().setPropertyValue(TEMPLATE_RENDITION_PROP, renditionName);
395        if (save) {
396            doSave();
397        }
398    }
399
400}