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