001/*
002 * (C) Copyright 2011-2016 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 *     Thierry Delprat
018 */
019package org.nuxeo.template.jsf;
020
021import java.io.IOException;
022import java.util.ArrayList;
023import java.util.List;
024
025import javax.faces.model.SelectItem;
026
027import org.jboss.seam.ScopeType;
028import org.jboss.seam.annotations.Factory;
029import org.jboss.seam.annotations.In;
030import org.jboss.seam.annotations.Name;
031import org.jboss.seam.annotations.Observer;
032import org.jboss.seam.annotations.Scope;
033import org.jboss.seam.annotations.intercept.BypassInterceptors;
034import org.jboss.seam.faces.FacesMessages;
035import org.jboss.seam.international.StatusMessage;
036import org.nuxeo.ecm.core.api.Blob;
037import org.nuxeo.ecm.core.api.DocumentModel;
038import org.nuxeo.ecm.core.api.IdRef;
039import org.nuxeo.ecm.core.api.NuxeoException;
040import org.nuxeo.ecm.core.api.PropertyException;
041import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
042import org.nuxeo.ecm.core.api.security.SecurityConstants;
043import org.nuxeo.ecm.platform.ui.web.api.WebActions;
044import org.nuxeo.ecm.platform.ui.web.util.ComponentUtils;
045import org.nuxeo.ecm.webapp.contentbrowser.DocumentActions;
046import org.nuxeo.ecm.webapp.helpers.EventManager;
047import org.nuxeo.ecm.webapp.helpers.EventNames;
048import org.nuxeo.ecm.webapp.helpers.ResourcesAccessor;
049import org.nuxeo.runtime.api.Framework;
050import org.nuxeo.template.api.TemplateInput;
051import org.nuxeo.template.api.TemplateProcessorService;
052import org.nuxeo.template.api.adapters.TemplateBasedDocument;
053import org.nuxeo.template.api.adapters.TemplateSourceDocument;
054
055@Name("templateBasedActions")
056@Scope(ScopeType.CONVERSATION)
057public class TemplateBasedActionBean extends BaseTemplateAction {
058
059    private static final long serialVersionUID = 1L;
060
061    @In(create = true)
062    protected transient DocumentActions documentActions;
063
064    @In(create = true)
065    protected transient WebActions webActions;
066
067    @In(create = true, required = false)
068    protected FacesMessages facesMessages;
069
070    @In(create = true)
071    protected ResourcesAccessor resourcesAccessor;
072
073    protected List<TemplateInput> templateInputs;
074
075    protected String templateIdToAssociate;
076
077    protected String editableTemplateName;
078
079    public String createTemplate() {
080        DocumentModel changeableDocument = navigationContext.getChangeableDocument();
081        TemplateSourceDocument sourceTemplate = changeableDocument.getAdapter(TemplateSourceDocument.class);
082        if (sourceTemplate != null && sourceTemplate.getTemplateBlob() != null) {
083            try {
084                sourceTemplate.initTemplate(false);
085                if (sourceTemplate.hasEditableParams()) {
086                    templateInputs = sourceTemplate.getParams();
087                    return "editTemplateRelatedData";
088                }
089            } catch (PropertyException e) {
090                log.error("Error during parameter automatic initialization", e);
091                facesMessages.add(StatusMessage.Severity.ERROR,
092                        resourcesAccessor.getMessages().get("label.template.err.parameterInit"));
093            }
094        }
095        return documentActions.saveDocument(changeableDocument);
096    }
097
098    public List<TemplateInput> getTemplateInputs() {
099        return templateInputs;
100    }
101
102    public void setTemplateInputs(List<TemplateInput> templateInputs) {
103        this.templateInputs = templateInputs;
104    }
105
106    public String saveDocument() {
107        DocumentModel changeableDocument = navigationContext.getChangeableDocument();
108
109        for (TemplateInput ti : templateInputs) {
110            log.info(ti.toString());
111        }
112        TemplateSourceDocument source = changeableDocument.getAdapter(TemplateSourceDocument.class);
113        if (source != null) {
114            source.saveParams(templateInputs, false);
115        }
116
117        return documentActions.saveDocument(changeableDocument);
118    }
119
120    @Observer(value = { EventNames.DOCUMENT_SELECTION_CHANGED, EventNames.NEW_DOCUMENT_CREATED,
121            EventNames.DOCUMENT_CHANGED }, create = false)
122    @BypassInterceptors
123    public void reset() {
124        templateInputs = null;
125        templateEditableInputs = null;
126        editableTemplateName = null;
127        templateIdToAssociate = null;
128    }
129
130    public List<TemplateInput> getTemplateEditableInputs() {
131        if (editableTemplateName == null) {
132            return new ArrayList<>();
133        }
134        if (templateEditableInputs == null) {
135            DocumentModel currentDocument = navigationContext.getCurrentDocument();
136
137            TemplateBasedDocument templateBasedDoc = currentDocument.getAdapter(TemplateBasedDocument.class);
138            templateEditableInputs = templateBasedDoc.getParams(editableTemplateName);
139        }
140        return templateEditableInputs;
141    }
142
143    public void setTemplateEditableInputs(List<TemplateInput> templateEditableInputs) {
144        this.templateEditableInputs = templateEditableInputs;
145    }
146
147    public String saveTemplateInputs() {
148
149        DocumentModel currentDocument = navigationContext.getCurrentDocument();
150
151        TemplateBasedDocument template = currentDocument.getAdapter(TemplateBasedDocument.class);
152        if (template != null) {
153            currentDocument = template.saveParams(editableTemplateName, templateEditableInputs, true);
154        }
155        reset();
156        navigationContext.invalidateCurrentDocument();
157        return navigationContext.navigateToDocument(currentDocument);
158    }
159
160    public void cancelTemplateInputsEdit() {
161        reset();
162    }
163
164    public TemplateInput getNewInput() {
165        if (newInput == null) {
166            newInput = new TemplateInput("newField");
167        }
168        return newInput;
169    }
170
171    public void setNewInput(TemplateInput newInput) {
172        this.newInput = newInput;
173    }
174
175    public String render(String templateName) throws IOException {
176        DocumentModel currentDocument = navigationContext.getCurrentDocument();
177        TemplateBasedDocument doc = currentDocument.getAdapter(TemplateBasedDocument.class);
178        if (doc == null) {
179            return null;
180        }
181        try {
182            Blob rendition = doc.renderWithTemplate(templateName);
183            String filename = rendition.getFilename();
184            ComponentUtils.download(currentDocument, null, rendition, filename, "templateRendition");
185            return null;
186        } catch (NuxeoException e) {
187            log.error("Unable to render template ", e);
188            facesMessages.add(StatusMessage.Severity.ERROR,
189                    resourcesAccessor.getMessages().get("label.template.err.renderingFailed"));
190            return null;
191        }
192    }
193
194    public String renderAndStore(String templateName) {
195
196        DocumentModel currentDocument = navigationContext.getCurrentDocument();
197        TemplateBasedDocument doc = currentDocument.getAdapter(TemplateBasedDocument.class);
198        if (doc == null) {
199            return null;
200        }
201        doc.renderAndStoreAsAttachment(templateName, true);
202        documentManager.save();
203        return navigationContext.navigateToDocument(doc.getAdaptedDoc());
204    }
205
206    @Override
207    public boolean canResetParameters() {
208        DocumentModel currentDocument = navigationContext.getCurrentDocument();
209        if (!documentManager.hasPermission(currentDocument.getRef(), SecurityConstants.WRITE)) {
210            return false;
211        }
212        TemplateBasedDocument templateBased = currentDocument.getAdapter(TemplateBasedDocument.class);
213        if (templateBased != null) {
214            return true;
215        }
216        return false;
217    }
218
219    public void resetParameters(String templateName) {
220        DocumentModel currentDocument = navigationContext.getCurrentDocument();
221        TemplateBasedDocument templateBased = currentDocument.getAdapter(TemplateBasedDocument.class);
222        if (templateBased != null) {
223            templateBased.initializeFromTemplate(templateName, true);
224            templateEditableInputs = null;
225        }
226    }
227
228    public boolean canDetachTemplate(String templateName) {
229        DocumentModel currentDocument = navigationContext.getCurrentDocument();
230        if (!documentManager.hasPermission(currentDocument.getRef(), SecurityConstants.WRITE)) {
231            return false;
232        }
233        TemplateBasedDocument templateBased = currentDocument.getAdapter(TemplateBasedDocument.class);
234        if (templateBased != null) {
235            return true;
236        }
237        return false;
238    }
239
240    public String detachTemplate(String templateName) {
241        DocumentModel currentDocument = navigationContext.getCurrentDocument();
242        TemplateProcessorService tps = Framework.getLocalService(TemplateProcessorService.class);
243        DocumentModel detachedDocument = tps.detachTemplateBasedDocument(currentDocument, templateName, true);
244        webActions.resetTabList();
245        // because of cacheKey issue
246        navigationContext.setCurrentDocument(null);
247        return navigationContext.navigateToDocument(detachedDocument);
248    }
249
250    public String getTemplateIdToAssociate() {
251        return templateIdToAssociate;
252    }
253
254    public void setTemplateIdToAssociate(String templateIdToAssociate) {
255        this.templateIdToAssociate = templateIdToAssociate;
256    }
257
258    public void associateDocumentToTemplate() {
259        if (templateIdToAssociate == null) {
260            // return null;
261            return;
262        }
263        DocumentModel currentDocument = navigationContext.getCurrentDocument();
264        DocumentModel sourceTemplate = documentManager.getDocument(new IdRef(templateIdToAssociate));
265        TemplateProcessorService tps = Framework.getLocalService(TemplateProcessorService.class);
266        try {
267            currentDocument = tps.makeTemplateBasedDocument(currentDocument, sourceTemplate, true);
268        } catch (NuxeoException e) {
269            log.error("Unable to do template association", e);
270            facesMessages.add(StatusMessage.Severity.ERROR,
271                    resourcesAccessor.getMessages().get("label.template.err.associationFailed"),
272                    sourceTemplate.getName());
273        }
274        navigationContext.invalidateCurrentDocument();
275        EventManager.raiseEventsOnDocumentChange(currentDocument);
276        templateIdToAssociate = null;
277    }
278
279    public boolean canRenderAndStore() {
280        DocumentModel currentDocument = navigationContext.getCurrentDocument();
281        // check that templating is supported
282        TemplateBasedDocument template = currentDocument.getAdapter(TemplateBasedDocument.class);
283        if (template == null) {
284            return false;
285        }
286        // check that we can store the result
287        BlobHolder bh = currentDocument.getAdapter(BlobHolder.class);
288        if (bh == null) {
289            return false;
290        }
291        return true;
292    }
293
294    public String getEditableTemplateName() {
295        return editableTemplateName;
296    }
297
298    public void setEditableTemplateName(String editableTemplateName) {
299        if (editableTemplateName == null || !editableTemplateName.equals(this.editableTemplateName)) {
300            this.editableTemplateName = editableTemplateName;
301            templateEditableInputs = null;
302        }
303    }
304
305    public List<TemplateSourceDocument> getBindableTemplatesForDocument() {
306        DocumentModel currentDocument = navigationContext.getCurrentDocument();
307        String targetType = currentDocument.getType();
308        TemplateProcessorService tps = Framework.getLocalService(TemplateProcessorService.class);
309        List<DocumentModel> templates = tps.getAvailableTemplateDocs(documentManager, targetType);
310
311        List<TemplateSourceDocument> result = new ArrayList<>();
312        TemplateBasedDocument currentTBD = currentDocument.getAdapter(TemplateBasedDocument.class);
313        List<String> alreadyBoundTemplateNames = new ArrayList<>();
314        if (currentTBD != null) {
315            alreadyBoundTemplateNames = currentTBD.getTemplateNames();
316        }
317        for (DocumentModel doc : templates) {
318            TemplateSourceDocument source = doc.getAdapter(TemplateSourceDocument.class);
319            if (!alreadyBoundTemplateNames.contains(source.getName())) {
320                result.add(source);
321            }
322        }
323        return result;
324
325    }
326
327    public List<SelectItem> getBindableTemplatesForDocumentAsSelectItems() {
328
329        List<SelectItem> items = new ArrayList<>();
330        List<TemplateSourceDocument> sources = getBindableTemplatesForDocument();
331        for (TemplateSourceDocument sd : sources) {
332            DocumentModel doc = sd.getAdaptedDoc();
333            String label = doc.getTitle();
334            if (doc.isVersion()) {
335                label = label + " (V " + doc.getVersionLabel() + ")";
336            }
337            items.add(new SelectItem(doc.getId(), label));
338        }
339
340        return items;
341    }
342
343    public boolean canBindNewTemplate() {
344        DocumentModel currentDocument = navigationContext.getCurrentDocument();
345        if (!currentDocument.getCoreSession().hasPermission(currentDocument.getRef(), SecurityConstants.WRITE)) {
346            return false;
347        }
348        if (getBindableTemplatesForDocument().size() == 0) {
349            return false;
350        }
351        return true;
352    }
353
354    @Factory(value = "currentTemplateBasedDocument", scope = ScopeType.EVENT)
355    public TemplateBasedDocument getCurrentDocumentAsTemplateBasedDocument() {
356        return navigationContext.getCurrentDocument().getAdapter(TemplateBasedDocument.class);
357    }
358
359    @Factory(value = "associatedRenderableTemplates", scope = ScopeType.EVENT)
360    public List<TemplateSourceDocument> getRenderableTemplates() {
361        List<TemplateSourceDocument> result = new ArrayList<>();
362        TemplateBasedDocument template = getCurrentDocumentAsTemplateBasedDocument();
363        if (template != null) {
364            List<TemplateSourceDocument> sources = template.getSourceTemplates();
365            for (TemplateSourceDocument source : sources) {
366                if (source.getTargetRenditionName() == null || source.getTargetRenditionName().isEmpty()) {
367                    result.add(source);
368                }
369            }
370        }
371        return result;
372    }
373}