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