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