001/* 002 * (C) Copyright 2019 Nuxeo (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 * Nour Al Kotob 018 */ 019 020package org.nuxeo.ecm.platform.thumbnail.action; 021 022import static org.nuxeo.ecm.core.api.CoreSession.ALLOW_VERSION_WRITE; 023import static org.nuxeo.ecm.core.bulk.BulkServiceImpl.STATUS_STREAM; 024import static org.nuxeo.lib.stream.computation.AbstractComputation.INPUT_1; 025import static org.nuxeo.lib.stream.computation.AbstractComputation.OUTPUT_1; 026 027import java.io.IOException; 028import java.io.InputStream; 029import java.io.Serializable; 030import java.util.Arrays; 031import java.util.List; 032import java.util.Map; 033 034import org.nuxeo.ecm.core.api.Blob; 035import org.nuxeo.ecm.core.api.Blobs; 036import org.nuxeo.ecm.core.api.CoreSession; 037import org.nuxeo.ecm.core.api.DocumentModel; 038import org.nuxeo.ecm.core.api.DocumentModelList; 039import org.nuxeo.ecm.core.api.NuxeoException; 040import org.nuxeo.ecm.core.api.VersioningOption; 041import org.nuxeo.ecm.core.api.blobholder.BlobHolder; 042import org.nuxeo.ecm.core.api.thumbnail.ThumbnailAdapter; 043import org.nuxeo.ecm.core.api.versioning.VersioningService; 044import org.nuxeo.ecm.core.blob.BlobManager; 045import org.nuxeo.ecm.core.bulk.action.computation.AbstractBulkComputation; 046import org.nuxeo.ecm.platform.dublincore.listener.DublinCoreListener; 047import org.nuxeo.ecm.platform.ec.notification.NotificationConstants; 048import org.nuxeo.ecm.platform.thumbnail.ThumbnailConstants; 049import org.nuxeo.lib.stream.computation.Topology; 050import org.nuxeo.runtime.api.Framework; 051import org.nuxeo.runtime.stream.StreamProcessorTopology; 052 053/** 054 * Bulk Action processor that generates thumbnails from documents. 055 * 056 * @since 11.1 057 */ 058public class RecomputeThumbnailsAction implements StreamProcessorTopology { 059 060 public static final String THUMBNAIL_UPDATED = "thumbnailUpdated"; 061 062 public static final String ACTION_NAME = "recomputeThumbnails"; 063 064 // @since 11.1 065 public static final String ACTION_FULL_NAME = "bulk/" + ACTION_NAME; 066 067 @Override 068 public Topology getTopology(Map<String, String> options) { 069 return Topology.builder() 070 .addComputation(RecomputeThumbnailsComputation::new, // 071 Arrays.asList(INPUT_1 + ":" + ACTION_FULL_NAME, OUTPUT_1 + ":" + STATUS_STREAM)) 072 .build(); 073 } 074 075 public static class RecomputeThumbnailsComputation extends AbstractBulkComputation { 076 077 public RecomputeThumbnailsComputation() { 078 super(ACTION_FULL_NAME); 079 } 080 081 @Override 082 protected void compute(CoreSession session, List<String> ids, Map<String, Serializable> properties) { 083 DocumentModelList docs = loadDocuments(session, ids); 084 085 for (DocumentModel doc : docs) { 086 processDoc(session, doc); 087 } 088 } 089 090 protected void processDoc(CoreSession session, DocumentModel doc) { 091 Blob thumbnailBlob = getManagedThumbnail(doc); 092 if (thumbnailBlob == null) { 093 ThumbnailAdapter thumbnailAdapter = doc.getAdapter(ThumbnailAdapter.class); 094 if (thumbnailAdapter == null) { 095 return; 096 } 097 thumbnailBlob = thumbnailAdapter.computeThumbnail(session); 098 } 099 if (thumbnailBlob != null) { 100 if (!doc.hasFacet(ThumbnailConstants.THUMBNAIL_FACET)) { 101 doc.addFacet(ThumbnailConstants.THUMBNAIL_FACET); 102 } 103 doc.setPropertyValue(ThumbnailConstants.THUMBNAIL_PROPERTY_NAME, (Serializable) thumbnailBlob); 104 } else { 105 if (doc.hasFacet(ThumbnailConstants.THUMBNAIL_FACET)) { 106 doc.setPropertyValue(ThumbnailConstants.THUMBNAIL_PROPERTY_NAME, null); 107 doc.removeFacet(ThumbnailConstants.THUMBNAIL_FACET); 108 } 109 } 110 if (doc.isDirty()) { 111 doc.putContextData(VersioningService.VERSIONING_OPTION, VersioningOption.NONE); 112 doc.putContextData(VersioningService.DISABLE_AUTO_CHECKOUT, Boolean.TRUE); 113 doc.putContextData(DublinCoreListener.DISABLE_DUBLINCORE_LISTENER, Boolean.TRUE); 114 doc.putContextData(NotificationConstants.DISABLE_NOTIFICATION_SERVICE, Boolean.TRUE); 115 doc.putContextData("disableAuditLogger", Boolean.TRUE); 116 if (doc.isVersion()) { 117 doc.putContextData(ALLOW_VERSION_WRITE, Boolean.TRUE); 118 } 119 doc.putContextData(THUMBNAIL_UPDATED, true); 120 session.saveDocument(doc); 121 } 122 } 123 124 protected Blob getManagedThumbnail(DocumentModel doc) { 125 BlobHolder bh = doc.getAdapter(BlobHolder.class); 126 if (bh == null) { 127 return null; 128 } 129 Blob blob = bh.getBlob(); 130 if (blob == null) { 131 return null; 132 } 133 BlobManager blobManager = Framework.getService(BlobManager.class); 134 try (InputStream is = blobManager.getThumbnail(blob)) { 135 if (is == null) { 136 return null; 137 } 138 return Blobs.createBlob(is); 139 } catch (IOException e) { 140 throw new NuxeoException("Failed to get managed blob thumbnail", e); 141 } 142 } 143 } 144}