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