001/*
002 * Copyright (c) 2015 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     Nuxeo - initial API and implementation
011 *
012 */
013
014package org.nuxeo.ecm.core.io.impl.plugins;
015
016import java.io.IOException;
017import java.util.ArrayList;
018import java.util.LinkedList;
019import java.util.List;
020
021import org.nuxeo.common.utils.Path;
022import org.nuxeo.ecm.core.api.CoreSession;
023import org.nuxeo.ecm.core.api.DocumentModel;
024import org.nuxeo.ecm.core.api.DocumentRef;
025import org.nuxeo.ecm.core.api.DocumentTreeIterator;
026import org.nuxeo.ecm.core.io.DocumentReader;
027import org.nuxeo.ecm.core.io.ExportExtension;
028import org.nuxeo.ecm.core.io.ExportedDocument;
029import org.nuxeo.ecm.core.io.impl.ExportedDocumentImpl;
030
031/**
032 * Compared to the default {@link DocumentReader} implementation this one does handle versions and allows to plug
033 * {@link ExportExtension}
034 *
035 * @since 7.4
036 */
037public class ExtensibleDocumentTreeReader extends DocumentModelReader {
038
039    protected DocumentTreeIterator iterator;
040
041    protected int pathSegmentsToRemove = 0;
042
043    protected List<DocumentModel> pendingVersions = new LinkedList<>();
044
045    protected List<ExportExtension> extensions = new ArrayList<>();
046
047    public static final String VERSION_VIRTUAL_PATH_SEGMENT = "__versions__";
048
049    public ExtensibleDocumentTreeReader(CoreSession session, DocumentModel root, boolean excludeRoot) {
050        super(session);
051        iterator = new DocumentTreeIterator(session, root, excludeRoot);
052        pathSegmentsToRemove = root.getPath().segmentCount() - (excludeRoot ? 0 : 1);
053    }
054
055    public ExtensibleDocumentTreeReader(CoreSession session, DocumentRef root) {
056        this(session, session.getDocument(root));
057    }
058
059    public ExtensibleDocumentTreeReader(CoreSession session, DocumentModel root) {
060        this(session, root, false);
061    }
062
063    public void registerExtension(ExportExtension ext) {
064        extensions.add(ext);
065    }
066
067    @Override
068    public void close() {
069        super.close();
070        iterator.reset();
071        iterator = null;
072    }
073
074    @Override
075    public ExportedDocument read() throws IOException {
076
077        DocumentModel docModel = null;
078        if (pendingVersions.size() > 0) {
079            docModel = pendingVersions.remove(0);
080        } else {
081            if (iterator.hasNext()) {
082                docModel = iterator.next();
083                try {
084                    List<DocumentModel> versions = session.getVersions(docModel.getRef());
085                    if (!versions.isEmpty()) {
086                        pendingVersions.addAll(0, versions);
087                    }
088                } catch (Exception e) {
089                    throw new IOException("Unable to get versions", e);
090                }
091            }
092        }
093
094        ExportedDocumentImpl result = null;
095        if (docModel != null) {
096            if (pathSegmentsToRemove > 0) {
097                // remove unwanted leading segments
098                result = new ExportedDocumentImpl(docModel,
099                        docModel.getPath().removeFirstSegments(pathSegmentsToRemove), inlineBlobs);
100            } else {
101                result = new ExportedDocumentImpl(docModel, inlineBlobs);
102            }
103
104            // flag versions
105            if (docModel.isVersion()) {
106                Path path = docModel.getPath().append(VERSION_VIRTUAL_PATH_SEGMENT).append(docModel.getVersionLabel());
107                if (pathSegmentsToRemove > 0) {
108                    path = path.removeFirstSegments(pathSegmentsToRemove);
109                }
110                result.setPath(path);
111            }
112
113            try {
114                for (ExportExtension ext : extensions) {
115                    ext.updateExport(docModel, result);
116                }
117            } catch (Exception e) {
118                throw new IOException("Unable to process versions", e);
119            }
120        }
121        return result;
122    }
123
124}