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