001/*
002 * (C) Copyright 2017-2018 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 *     Guillaume Renard
018 */
019
020package org.nuxeo.ecm.platform.rendition.operation;
021
022import java.io.IOException;
023
024import org.apache.commons.logging.Log;
025import org.apache.commons.logging.LogFactory;
026import org.nuxeo.ecm.automation.OperationContext;
027import org.nuxeo.ecm.automation.core.Constants;
028import org.nuxeo.ecm.automation.core.annotations.Context;
029import org.nuxeo.ecm.automation.core.annotations.Operation;
030import org.nuxeo.ecm.automation.core.annotations.OperationMethod;
031import org.nuxeo.ecm.automation.core.annotations.Param;
032import org.nuxeo.ecm.automation.core.util.BlobList;
033import org.nuxeo.ecm.collections.api.CollectionManager;
034import org.nuxeo.ecm.collections.core.adapter.Collection;
035import org.nuxeo.ecm.core.api.Blob;
036import org.nuxeo.ecm.core.api.CoreSession;
037import org.nuxeo.ecm.core.api.DocumentModel;
038import org.nuxeo.ecm.core.api.DocumentModelIterator;
039import org.nuxeo.ecm.core.api.DocumentRef;
040import org.nuxeo.ecm.core.api.IdRef;
041import org.nuxeo.ecm.core.api.NuxeoException;
042import org.nuxeo.ecm.core.schema.FacetNames;
043import org.nuxeo.ecm.core.utils.BlobUtils;
044import org.nuxeo.ecm.platform.rendition.Rendition;
045import org.nuxeo.ecm.platform.rendition.service.RenditionService;
046
047/**
048 * Returns a Folderish Document or Collection default rendition.
049 *
050 * @since 9.3
051 */
052@Operation(id = GetContainerRendition.ID, category = Constants.CAT_BLOB, label = "Gets the folder's children or the collection's members default renditions", description = "Gets the list of blob of the folder's children or the collection's members default renditions. Returns a blob list file containing all the default rendition blobs.")
053public class GetContainerRendition {
054
055    private static final Log log = LogFactory.getLog(GetContainerRendition.class);
056
057    public static final String ID = "Document.GetContainerRendition";
058
059    @Context
060    protected RenditionService renditionService;
061
062    @Context
063    protected CollectionManager collectionManager;
064
065    @Param(name = "reason", required = false)
066    protected String reason;
067
068    @Param(name = "limit", description = "Limit of members to be returned. Default is 100.", required = false)
069    protected int limit = 100;
070
071    @Param(name = "maxDepth", description = "Depth of the hierarchy to be explored. Default is 1.", required = false)
072    protected int maxDepth = 1;
073
074    @Context
075    protected CoreSession session;
076
077    @Context
078    protected OperationContext ctx;
079
080    protected BlobList getCollectionBlobs(Collection collection, int currentDepth) throws IOException {
081        BlobList blobs = new BlobList();
082        int added = 0;
083        for (String memberId : collection.getCollectedDocumentIds()) {
084            DocumentRef memberRef = new IdRef(memberId);
085            if (session.exists(memberRef) && !session.isTrashed(memberRef)) {
086                DocumentModel member = session.getDocument(memberRef);
087                Blob blob = getDefaultRendition(member, currentDepth + 1);
088                if (blob != null) {
089                    blobs.add(blob);
090                    if (limit > -1 && ++added >= limit) {
091                        if (log.isDebugEnabled()) {
092                            log.debug(String.format(
093                                    "Limit of %s reached, increase the limit parameter to get more results.", limit));
094                        }
095                        break;
096                    }
097                }
098            }
099        }
100        return blobs;
101    }
102
103    protected Blob getDefaultRendition(DocumentModel doc, int currentDepth) throws IOException {
104        Blob blob = null;
105        if (collectionManager.isCollection(doc) || doc.hasFacet(FacetNames.FOLDERISH)) {
106            if (currentDepth >= maxDepth) {
107                return null;
108            }
109            blob = processContainer(doc, currentDepth + 1);
110        } else {
111            Rendition rendition = renditionService.getDefaultRendition(doc, reason, null);
112            if (rendition != null) {
113                blob = rendition.getBlob();
114                if (blob == null) {
115                    if (log.isDebugEnabled()) {
116                        log.debug(String.format("Default rendition '%s' has an null Blob for document '%s'",
117                                rendition.getName(), doc.getPathAsString()));
118                    }
119                }
120            }
121        }
122        return blob;
123    }
124
125    protected BlobList getFolderishBlobs(DocumentModel parent, int currentDepth) throws IOException {
126        BlobList blobs = new BlobList();
127        int added = 0;
128        DocumentModelIterator it = session.getChildrenIterator(parent.getRef());
129        while (it.hasNext()) {
130            DocumentModel child = it.next();
131            if (!child.isTrashed()) {
132                Blob blob = getDefaultRendition(child, currentDepth);
133                if (blob != null) {
134                    blobs.add(blob);
135                    if (limit > -1 && ++added >= limit) {
136                        if (log.isDebugEnabled()) {
137                            log.debug(String.format(
138                                    "Limit of %s reached, increase the limit parameter to get more results.", limit));
139                        }
140                        break;
141                    }
142                }
143            }
144        }
145        return blobs;
146    }
147
148    protected Blob processContainer(DocumentModel doc, int currentDepth) throws IOException {
149        BlobList blobs;
150        if (collectionManager.isCollection(doc)) {
151            blobs = getCollectionBlobs(doc.getAdapter(Collection.class), currentDepth);
152        } else if (doc.hasFacet(FacetNames.FOLDERISH)) {
153            blobs = getFolderishBlobs(doc, currentDepth + 1);
154        } else {
155            throw new NuxeoException("The operation only accepts folderish document or collection");
156        }
157        return BlobUtils.zip(blobs, doc.getName() + ".zip");
158    }
159
160    @OperationMethod
161    public Blob run(DocumentModel doc) throws IOException {
162        if (maxDepth <= 0) {
163            throw new NuxeoException("Maximum depth must greater or equal to 1.");
164        }
165        return processContainer(doc, 0);
166    }
167
168}