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