001/* 002 * (C) Copyright 2010-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 */ 019package org.nuxeo.ecm.platform.rendition.service; 020 021import static org.nuxeo.ecm.platform.rendition.Constants.RENDITION_SOURCE_ID_PROPERTY; 022import static org.nuxeo.ecm.platform.rendition.Constants.RENDITION_SOURCE_MODIFICATION_DATE_PROPERTY; 023import static org.nuxeo.ecm.platform.rendition.Constants.RENDITION_SOURCE_VERSIONABLE_ID_PROPERTY; 024 025import java.io.Serializable; 026import java.util.ArrayList; 027import java.util.Calendar; 028import java.util.Collections; 029import java.util.Deque; 030import java.util.HashMap; 031import java.util.LinkedList; 032import java.util.List; 033import java.util.Map; 034import java.util.Objects; 035import java.util.stream.Collectors; 036 037import javax.script.Invocable; 038import javax.script.ScriptContext; 039import javax.script.ScriptEngine; 040import javax.script.ScriptEngineManager; 041import javax.script.ScriptException; 042 043import org.apache.commons.lang.StringUtils; 044import org.apache.commons.logging.Log; 045import org.apache.commons.logging.LogFactory; 046import org.nuxeo.ecm.automation.AutomationService; 047import org.nuxeo.ecm.core.api.Blob; 048import org.nuxeo.ecm.core.api.CoreSession; 049import org.nuxeo.ecm.core.api.DocumentModel; 050import org.nuxeo.ecm.core.api.DocumentRef; 051import org.nuxeo.ecm.core.api.IdRef; 052import org.nuxeo.ecm.core.api.IterableQueryResult; 053import org.nuxeo.ecm.core.api.NuxeoException; 054import org.nuxeo.ecm.core.api.NuxeoPrincipal; 055import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner; 056import org.nuxeo.ecm.core.api.VersioningOption; 057import org.nuxeo.ecm.core.api.local.ClientLoginModule; 058import org.nuxeo.ecm.core.query.sql.NXQL; 059import org.nuxeo.ecm.platform.query.nxql.NXQLQueryBuilder; 060import org.nuxeo.ecm.platform.rendition.Rendition; 061import org.nuxeo.ecm.platform.rendition.extension.DefaultAutomationRenditionProvider; 062import org.nuxeo.ecm.platform.rendition.extension.RenditionProvider; 063import org.nuxeo.ecm.platform.rendition.impl.LazyRendition; 064import org.nuxeo.ecm.platform.rendition.impl.LiveRendition; 065import org.nuxeo.ecm.platform.rendition.impl.StoredRendition; 066import org.nuxeo.runtime.api.Framework; 067import org.nuxeo.runtime.model.ComponentContext; 068import org.nuxeo.runtime.model.ComponentInstance; 069import org.nuxeo.runtime.model.DefaultComponent; 070import org.nuxeo.runtime.transaction.TransactionHelper; 071 072/** 073 * Default implementation of {@link RenditionService}. 074 * 075 * @author <a href="mailto:troger@nuxeo.com">Thomas Roger</a> 076 * @since 5.4.1 077 */ 078public class RenditionServiceImpl extends DefaultComponent implements RenditionService { 079 080 public static final String RENDITION_DEFINITIONS_EP = "renditionDefinitions"; 081 082 public static final String RENDITON_DEFINION_PROVIDERS_EP = "renditionDefinitionProviders"; 083 084 public static final String DEFAULT_RENDITION_EP = "defaultRendition"; 085 086 /** 087 * @since 8.1 088 */ 089 public static final String STORED_RENDITION_MANAGERS_EP = "storedRenditionManagers"; 090 091 private static final Log log = LogFactory.getLog(RenditionServiceImpl.class); 092 093 /** 094 * @deprecated since 7.2. Not used. 095 */ 096 @Deprecated 097 protected AutomationService automationService; 098 099 /** 100 * @deprecated since 7.3. 101 */ 102 @Deprecated 103 protected Map<String, RenditionDefinition> renditionDefinitions; 104 105 /** 106 * @since 7.3. RenditionDefinitions are store in {@link #renditionDefinitionRegistry}. 107 */ 108 protected RenditionDefinitionRegistry renditionDefinitionRegistry; 109 110 protected RenditionDefinitionProviderRegistry renditionDefinitionProviderRegistry; 111 112 protected List<DefaultRenditionDescriptor> defaultRenditionDescriptors = new ArrayList<>();; 113 114 protected DefaultRenditionDescriptor defaultRenditionDescriptor; 115 116 protected static final StoredRenditionManager DEFAULT_STORED_RENDITION_MANAGER = new DefaultStoredRenditionManager(); 117 118 /** 119 * @since 8.1 120 */ 121 protected Deque<StoredRenditionManagerDescriptor> storedRenditionManagerDescriptors = new LinkedList<>(); 122 123 protected final ScriptEngineManager scriptEngineManager; 124 125 public RenditionServiceImpl() { 126 scriptEngineManager = new ScriptEngineManager(); 127 } 128 129 /** 130 * @since 8.1 131 */ 132 public StoredRenditionManager getStoredRenditionManager() { 133 StoredRenditionManagerDescriptor descr = storedRenditionManagerDescriptors.peekLast(); 134 return descr == null ? DEFAULT_STORED_RENDITION_MANAGER : descr.getStoredRenditionManager(); 135 } 136 137 @Override 138 public void activate(ComponentContext context) { 139 renditionDefinitions = new HashMap<>(); 140 renditionDefinitionRegistry = new RenditionDefinitionRegistry(); 141 renditionDefinitionProviderRegistry = new RenditionDefinitionProviderRegistry(); 142 super.activate(context); 143 } 144 145 @Override 146 public void deactivate(ComponentContext context) { 147 renditionDefinitions = null; 148 renditionDefinitionRegistry = null; 149 renditionDefinitionProviderRegistry = null; 150 super.deactivate(context); 151 } 152 153 public RenditionDefinition getRenditionDefinition(String name) { 154 return renditionDefinitionRegistry.getRenditionDefinition(name); 155 } 156 157 /** 158 * @deprecated since 7.2 because unused 159 */ 160 @Override 161 @Deprecated 162 public List<RenditionDefinition> getDeclaredRenditionDefinitions() { 163 return new ArrayList<>(renditionDefinitionRegistry.descriptors.values()); 164 } 165 166 /** 167 * @deprecated since 7.2 because unused 168 */ 169 @Override 170 @Deprecated 171 public List<RenditionDefinition> getDeclaredRenditionDefinitionsForProviderType(String providerType) { 172 List<RenditionDefinition> defs = new ArrayList<>(); 173 for (RenditionDefinition def : getDeclaredRenditionDefinitions()) { 174 if (def.getProviderType().equals(providerType)) { 175 defs.add(def); 176 } 177 } 178 return defs; 179 } 180 181 @Override 182 public List<RenditionDefinition> getAvailableRenditionDefinitions(DocumentModel doc) { 183 184 List<RenditionDefinition> defs = new ArrayList<>(); 185 defs.addAll(renditionDefinitionRegistry.getRenditionDefinitions(doc)); 186 defs.addAll(renditionDefinitionProviderRegistry.getRenditionDefinitions(doc)); 187 188 // XXX what about "lost renditions" ? 189 return defs; 190 } 191 192 @Override 193 public DocumentRef storeRendition(DocumentModel source, String renditionDefinitionName) { 194 Rendition rendition = getRendition(source, renditionDefinitionName, true); 195 return rendition == null ? null : rendition.getHostDocument().getRef(); 196 } 197 198 /** 199 * @deprecated since 8.1 200 */ 201 @Deprecated 202 protected DocumentModel storeRendition(DocumentModel sourceDocument, Rendition rendition, String name) { 203 StoredRendition storedRendition = storeRendition(sourceDocument, rendition); 204 return storedRendition == null ? null : storedRendition.getHostDocument(); 205 } 206 207 /** 208 * @since 8.1 209 */ 210 protected StoredRendition storeRendition(DocumentModel sourceDocument, Rendition rendition) { 211 if (!rendition.isCompleted()) { 212 return null; 213 } 214 List<Blob> renderedBlobs = rendition.getBlobs(); 215 Blob renderedBlob = renderedBlobs.get(0); 216 String mimeType = renderedBlob.getMimeType(); 217 if (mimeType != null && mimeType.contains(LazyRendition.ERROR_MARKER)) { 218 return null; 219 } 220 221 CoreSession session = sourceDocument.getCoreSession(); 222 DocumentModel version = null; 223 boolean isVersionable = sourceDocument.isVersionable(); 224 if (isVersionable) { 225 DocumentRef versionRef = createVersionIfNeeded(sourceDocument, session); 226 version = session.getDocument(versionRef); 227 } 228 229 RenditionDefinition renditionDefinition = getRenditionDefinition(rendition.getName()); 230 StoredRendition storedRendition = getStoredRenditionManager().createStoredRendition(sourceDocument, version, 231 renderedBlob, renditionDefinition); 232 return storedRendition; 233 } 234 235 protected DocumentRef createVersionIfNeeded(DocumentModel source, CoreSession session) { 236 if (source.isVersionable()) { 237 if (source.isVersion()) { 238 return source.getRef(); 239 } else if (source.isCheckedOut()) { 240 DocumentRef versionRef = session.checkIn(source.getRef(), VersioningOption.MINOR, null); 241 source.refresh(DocumentModel.REFRESH_STATE, null); 242 return versionRef; 243 } else { 244 return session.getLastDocumentVersionRef(source.getRef()); 245 } 246 } 247 return null; 248 } 249 250 /** 251 * @deprecated since 7.2. Not used. 252 */ 253 @Deprecated 254 protected AutomationService getAutomationService() { 255 return Framework.getService(AutomationService.class); 256 } 257 258 @Override 259 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 260 if (RENDITION_DEFINITIONS_EP.equals(extensionPoint)) { 261 RenditionDefinition renditionDefinition = (RenditionDefinition) contribution; 262 renditionDefinitionRegistry.addContribution(renditionDefinition); 263 } else if (RENDITON_DEFINION_PROVIDERS_EP.equals(extensionPoint)) { 264 renditionDefinitionProviderRegistry.addContribution((RenditionDefinitionProviderDescriptor) contribution); 265 } else if (STORED_RENDITION_MANAGERS_EP.equals(extensionPoint)) { 266 storedRenditionManagerDescriptors.add(((StoredRenditionManagerDescriptor) contribution)); 267 } else if (DEFAULT_RENDITION_EP.equals(extensionPoint)) { 268 defaultRenditionDescriptor = ((DefaultRenditionDescriptor) contribution); 269 // Save contribution 270 defaultRenditionDescriptors.add((DefaultRenditionDescriptor) contribution); 271 } 272 } 273 274 /** 275 * @deprecated since 7.3. RenditionDefinitions are store in {@link #renditionDefinitionRegistry}. 276 */ 277 @Deprecated 278 protected void registerRendition(RenditionDefinition renditionDefinition) { 279 String name = renditionDefinition.getName(); 280 if (name == null) { 281 log.error("Cannot register rendition without a name"); 282 return; 283 } 284 boolean enabled = renditionDefinition.isEnabled(); 285 if (renditionDefinitions.containsKey(name)) { 286 log.info("Overriding rendition with name: " + name); 287 if (enabled) { 288 renditionDefinition = mergeRenditions(renditionDefinitions.get(name), renditionDefinition); 289 } else { 290 log.info("Disabled rendition with name " + name); 291 renditionDefinitions.remove(name); 292 } 293 } 294 if (enabled) { 295 log.info("Registering rendition with name: " + name); 296 renditionDefinitions.put(name, renditionDefinition); 297 } 298 299 // setup the Provider 300 setupProvider(renditionDefinition); 301 } 302 303 /** 304 * @deprecated since 7.3. RenditionDefinitions are store in {@link #renditionDefinitionRegistry}. 305 */ 306 @Deprecated 307 protected void setupProvider(RenditionDefinition definition) { 308 if (definition.getProviderClass() == null) { 309 definition.setProvider(new DefaultAutomationRenditionProvider()); 310 } else { 311 try { 312 RenditionProvider provider = definition.getProviderClass().newInstance(); 313 definition.setProvider(provider); 314 } catch (Exception e) { 315 log.error("Unable to create RenditionProvider", e); 316 } 317 } 318 } 319 320 protected RenditionDefinition mergeRenditions(RenditionDefinition oldRenditionDefinition, 321 RenditionDefinition newRenditionDefinition) { 322 String label = newRenditionDefinition.getLabel(); 323 if (label != null) { 324 oldRenditionDefinition.label = label; 325 } 326 327 String operationChain = newRenditionDefinition.getOperationChain(); 328 if (operationChain != null) { 329 oldRenditionDefinition.operationChain = operationChain; 330 } 331 332 return oldRenditionDefinition; 333 } 334 335 @Override 336 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 337 if (RENDITION_DEFINITIONS_EP.equals(extensionPoint)) { 338 renditionDefinitionRegistry.removeContribution((RenditionDefinition) contribution); 339 } else if (RENDITON_DEFINION_PROVIDERS_EP.equals(extensionPoint)) { 340 renditionDefinitionProviderRegistry.removeContribution( 341 (RenditionDefinitionProviderDescriptor) contribution); 342 } else if (STORED_RENDITION_MANAGERS_EP.equals(extensionPoint)) { 343 storedRenditionManagerDescriptors.remove((contribution)); 344 } else if (DEFAULT_RENDITION_EP.equals(extensionPoint)) { 345 defaultRenditionDescriptors.remove(contribution); 346 if (defaultRenditionDescriptors.size() == 0) { 347 // We don't have any default rendition descriptor 348 defaultRenditionDescriptor = null; 349 } else { 350 // Go back to the last contribution added 351 defaultRenditionDescriptor = defaultRenditionDescriptors.get(defaultRenditionDescriptors.size() - 1); 352 } 353 } 354 } 355 356 /** 357 * @deprecated since 7.3. RenditionDefinitions are store in {@link #renditionDefinitionRegistry}. 358 */ 359 @Deprecated 360 protected void unregisterRendition(RenditionDefinition renditionDefinition) { 361 String name = renditionDefinition.getName(); 362 renditionDefinitions.remove(name); 363 log.info("Unregistering rendition with name: " + name); 364 } 365 366 @Override 367 public Rendition getRendition(DocumentModel doc, String renditionName) { 368 RenditionDefinition renditionDefinition = getAvailableRenditionDefinition(doc, renditionName); 369 return getRendition(doc, renditionDefinition, renditionDefinition.isStoreByDefault()); 370 } 371 372 @Override 373 public Rendition getRendition(DocumentModel doc, String renditionName, boolean store) { 374 RenditionDefinition renditionDefinition = getAvailableRenditionDefinition(doc, renditionName); 375 return getRendition(doc, renditionDefinition, store); 376 } 377 378 protected Rendition getRendition(DocumentModel doc, RenditionDefinition renditionDefinition, boolean store) { 379 380 Rendition rendition = null; 381 boolean isVersionable = doc.isVersionable(); 382 if (!isVersionable || !doc.isCheckedOut()) { 383 // stored renditions are only done against a non-versionable doc 384 // or a versionable doc that is not checkedout 385 rendition = getStoredRenditionManager().findStoredRendition(doc, renditionDefinition); 386 if (rendition != null) { 387 // Mark stored rendition as stale if needed 388 Calendar renditionModificationDate = (Calendar) rendition.getHostDocument().getPropertyValue( 389 RENDITION_SOURCE_MODIFICATION_DATE_PROPERTY); 390 String sourceDocumentModificationDatePropertyName = renditionDefinition.getSourceDocumentModificationDatePropertyName(); 391 Calendar currentModificationDate = (Calendar) doc.getPropertyValue( 392 sourceDocumentModificationDatePropertyName); 393 if (!Objects.equals(renditionModificationDate, currentModificationDate)) { 394 Blob blob = rendition.getBlob(); 395 if (blob != null) { 396 blob.setMimeType(blob.getMimeType() + ";" + LazyRendition.STALE_MARKER); 397 } 398 } 399 return rendition; 400 } 401 } 402 403 rendition = new LiveRendition(doc, renditionDefinition); 404 405 if (store) { 406 StoredRendition storedRendition = storeRendition(doc, rendition); 407 if (storedRendition != null) { 408 return storedRendition; 409 } 410 } 411 return rendition; 412 } 413 414 protected RenditionDefinition getAvailableRenditionDefinition(DocumentModel doc, String renditionName) { 415 RenditionDefinition renditionDefinition = renditionDefinitionRegistry.getRenditionDefinition(renditionName); 416 if (renditionDefinition == null) { 417 renditionDefinition = renditionDefinitionProviderRegistry.getRenditionDefinition(renditionName, doc); 418 if (renditionDefinition == null) { 419 String message = "The rendition definition '%s' is not registered"; 420 throw new NuxeoException(String.format(message, renditionName)); 421 } 422 } else { 423 // we have a rendition definition but we must check that it can be used for this doc 424 if (!renditionDefinitionRegistry.canUseRenditionDefinition(renditionDefinition, doc)) { 425 throw new NuxeoException("Rendition " + renditionName + " cannot be used for this doc " + doc.getId()); 426 } 427 } 428 if (!renditionDefinition.getProvider().isAvailable(doc, renditionDefinition)) { 429 throw new NuxeoException( 430 String.format("Rendition %s not available for this doc %s", renditionName, doc.getPathAsString())); 431 } 432 return renditionDefinition; 433 } 434 435 @Override 436 public List<Rendition> getAvailableRenditions(DocumentModel doc) { 437 return getAvailableRenditions(doc, false); 438 } 439 440 @Override 441 public List<Rendition> getAvailableRenditions(DocumentModel doc, boolean onlyVisible) { 442 List<Rendition> renditions = new ArrayList<>(); 443 444 if (doc.isProxy()) { 445 return renditions; 446 } 447 448 List<RenditionDefinition> defs = getAvailableRenditionDefinitions(doc); 449 if (defs != null) { 450 for (RenditionDefinition def : defs) { 451 if (!onlyVisible || onlyVisible && def.isVisible()) { 452 Rendition rendition = getRendition(doc, def.getName(), false); 453 if (rendition != null) { 454 renditions.add(rendition); 455 } 456 } 457 } 458 } 459 460 return renditions; 461 } 462 463 @Override 464 public void deleteStoredRenditions(String repositoryName) { 465 StoredRenditionsCleaner cleaner = new StoredRenditionsCleaner(repositoryName); 466 cleaner.runUnrestricted(); 467 } 468 469 private final class StoredRenditionsCleaner extends UnrestrictedSessionRunner { 470 471 private static final int BATCH_SIZE = 100; 472 473 private StoredRenditionsCleaner(String repositoryName) { 474 super(repositoryName); 475 } 476 477 @Override 478 public void run() { 479 Map<String, List<String>> sourceIdToRenditionRefs = computeLiveDocumentRefsToRenditionRefs(); 480 removeStoredRenditions(sourceIdToRenditionRefs); 481 } 482 483 /** 484 * Computes only live documents renditions, the related versions will be deleted by Nuxeo. 485 */ 486 private Map<String, List<String>> computeLiveDocumentRefsToRenditionRefs() { 487 Map<String, List<String>> liveDocumentRefsToRenditionRefs = new HashMap<>(); 488 String query = String.format("SELECT %s, %s, %s FROM Document WHERE %s IS NOT NULL AND ecm:isVersion = 0", 489 NXQL.ECM_UUID, RENDITION_SOURCE_ID_PROPERTY, RENDITION_SOURCE_VERSIONABLE_ID_PROPERTY, 490 RENDITION_SOURCE_ID_PROPERTY); 491 try (IterableQueryResult result = session.queryAndFetch(query, NXQL.NXQL)) { 492 for (Map<String, Serializable> res : result) { 493 String renditionRef = res.get(NXQL.ECM_UUID).toString(); 494 String sourceId = res.get(RENDITION_SOURCE_ID_PROPERTY).toString(); 495 Serializable sourceVersionableId = res.get(RENDITION_SOURCE_VERSIONABLE_ID_PROPERTY); 496 497 String key = sourceVersionableId != null ? sourceVersionableId.toString() : sourceId; 498 liveDocumentRefsToRenditionRefs.computeIfAbsent(key, k -> new ArrayList<>()).add(renditionRef); 499 } 500 } 501 return liveDocumentRefsToRenditionRefs; 502 } 503 504 private void removeStoredRenditions(Map<String, List<String>> liveDocumentRefsToRenditionRefs) { 505 List<String> liveDocumentRefs = new ArrayList<>(liveDocumentRefsToRenditionRefs.keySet()); 506 if (liveDocumentRefs.isEmpty()) { 507 // no more document to check 508 return; 509 } 510 511 int processedSourceIds = 0; 512 while (processedSourceIds < liveDocumentRefs.size()) { 513 // compute the batch of source ids to check for existence 514 int limit = processedSourceIds + BATCH_SIZE > liveDocumentRefs.size() ? liveDocumentRefs.size() 515 : processedSourceIds + BATCH_SIZE; 516 List<String> batchSourceIds = liveDocumentRefs.subList(processedSourceIds, limit); 517 518 // retrieve still existing documents 519 List<String> existingSourceIds = new ArrayList<>(); 520 String query = NXQLQueryBuilder.getQuery("SELECT ecm:uuid FROM Document WHERE ecm:uuid IN ?", 521 new Object[] { batchSourceIds }, true, true, null); 522 try (IterableQueryResult result = session.queryAndFetch(query, NXQL.NXQL)) { 523 result.forEach(res -> existingSourceIds.add(res.get(NXQL.ECM_UUID).toString())); 524 } 525 batchSourceIds.removeAll(existingSourceIds); 526 527 List<String> renditionRefsToDelete = batchSourceIds.stream() 528 .map(liveDocumentRefsToRenditionRefs::get) 529 .reduce(new ArrayList<>(), (allRefs, refs) -> { 530 allRefs.addAll(refs); 531 return allRefs; 532 }); 533 534 if (!renditionRefsToDelete.isEmpty()) { 535 session.removeDocuments( 536 renditionRefsToDelete.stream().map(IdRef::new).collect(Collectors.toList()).toArray( 537 new DocumentRef[renditionRefsToDelete.size()])); 538 } 539 540 if (TransactionHelper.isTransactionActiveOrMarkedRollback()) { 541 TransactionHelper.commitOrRollbackTransaction(); 542 TransactionHelper.startTransaction(); 543 } 544 545 // next batch 546 processedSourceIds += BATCH_SIZE; 547 } 548 } 549 } 550 551 @Override 552 public Rendition getDefaultRendition(DocumentModel doc, String reason, Map<String, Serializable> extendedInfos) { 553 if (defaultRenditionDescriptor == null) { 554 return null; 555 } 556 Map<String, Object> context = new HashMap<>(); 557 Map<String, Serializable> ei = extendedInfos == null ? Collections.emptyMap() : extendedInfos; 558 NuxeoPrincipal currentUser = ClientLoginModule.getCurrentPrincipal(); 559 context.put("Document", doc); 560 context.put("Reason", reason); 561 context.put("Infos", ei); 562 context.put("CurrentUser", currentUser); 563 ScriptEngine engine = scriptEngineManager.getEngineByName(defaultRenditionDescriptor.getScriptLanguage()); 564 if (engine == null) { 565 throw new NuxeoException( 566 "Engine not found for language: " + defaultRenditionDescriptor.getScriptLanguage()); 567 } 568 if (!(engine instanceof Invocable)) { 569 throw new NuxeoException("Engine " + engine.getClass().getName() + " not Invocable for language: " 570 + defaultRenditionDescriptor.getScriptLanguage()); 571 } 572 Rendition rendition = null; 573 try { 574 engine.eval(defaultRenditionDescriptor.getScript()); 575 engine.getBindings(ScriptContext.ENGINE_SCOPE).putAll(context); 576 Object result = ((Invocable) engine).invokeFunction("run"); 577 if (!(result instanceof String)) { 578 log.error("Failed to get rendition name (" + result + ")"); 579 } else { 580 String defaultRenditionName = (String) result; 581 if (StringUtils.isBlank(defaultRenditionName)) { 582 log.info("Default rendition name cannot be evaluated, returning null"); 583 } else { 584 try { 585 rendition = getRendition(doc, defaultRenditionName); 586 } catch (NuxeoException e) { 587 log.error("Unable to use default rendition " + defaultRenditionName, e); 588 } 589 } 590 } 591 592 } catch (NoSuchMethodException e) { 593 throw new NuxeoException("Script does not contain function: run() in defaultRendition: ", e); 594 } catch (ScriptException e) { 595 log.error("Failed to evaluate script: ", e); 596 } 597 return rendition; 598 } 599 600}