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}