001/*
002 * (C) Copyright 2006-2008 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Thierry Delprat
016 *     Florent Guillaume
017 *
018 * $Id: ExportRestlet.java 30251 2008-02-18 19:17:33Z fguillaume $
019 */
020
021package org.nuxeo.ecm.platform.ui.web.restAPI;
022
023import java.io.IOException;
024import java.io.OutputStream;
025import java.io.Serializable;
026import java.util.Map;
027
028import org.nuxeo.ecm.core.api.CoreSession;
029import org.nuxeo.ecm.core.api.DocumentModel;
030import org.nuxeo.ecm.core.api.DocumentModelList;
031import org.nuxeo.ecm.core.api.DocumentSecurityException;
032import org.nuxeo.ecm.core.api.IdRef;
033import org.nuxeo.ecm.core.api.NuxeoException;
034import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner;
035import org.nuxeo.ecm.core.api.security.SecurityConstants;
036import org.nuxeo.ecm.core.io.DocumentPipe;
037import org.nuxeo.ecm.core.io.DocumentReader;
038import org.nuxeo.ecm.core.io.DocumentWriter;
039import org.nuxeo.ecm.core.io.impl.DocumentPipeImpl;
040import org.nuxeo.ecm.core.io.impl.plugins.DocumentTreeReader;
041import org.nuxeo.ecm.core.io.impl.plugins.NuxeoArchiveWriter;
042import org.nuxeo.ecm.core.io.impl.plugins.SingleDocumentReader;
043import org.nuxeo.ecm.core.io.impl.plugins.XMLDocumentTreeWriter;
044import org.nuxeo.ecm.core.io.impl.plugins.XMLDocumentWriter;
045import org.restlet.data.CharacterSet;
046import org.restlet.data.Form;
047import org.restlet.data.MediaType;
048import org.restlet.data.Request;
049import org.restlet.data.Response;
050import org.restlet.resource.Representation;
051
052import com.noelios.restlet.http.HttpConstants;
053
054/**
055 * @deprecated since 7.2. Exports are now exposed directly as renditions on the document. Exports can be generated
056 *             through the {@code ExportDocument} operation. See NXP-16585.
057 */
058@Deprecated
059public class ExportRestlet extends BaseStatelessNuxeoRestlet implements Serializable {
060
061    private static final long serialVersionUID = 7831287875548588711L;
062
063    @Override
064    protected void doHandleStatelessRequest(Request req, Response res) {
065        boolean exportAsTree;
066        boolean exportAsZip;
067        String action = req.getResourceRef().getSegments().get(4);
068        if (action.equals("exportTree")) {
069            exportAsTree = true;
070            exportAsZip = true;
071        } else {
072            // "export", "exportSingle"
073            exportAsTree = false;
074            String format = req.getResourceRef().getQueryAsForm().getFirstValue("format");
075            if (format != null) {
076                format = format.toLowerCase();
077            } else {
078                format = "xml";
079            }
080            exportAsZip = "zip".equals(format);
081        }
082
083        String repo = (String) req.getAttributes().get("repo");
084        if (repo == null || repo.equals("*")) {
085            handleError(res, "you must specify a repository");
086            return;
087        }
088
089        DocumentModel root;
090        String docid = (String) req.getAttributes().get("docid");
091        boolean needUnrestricted = false;
092
093        try {
094            boolean init = initRepository(res, repo);
095            if (!init) {
096                handleError(res, "Unable to init repository");
097                return;
098            }
099            if (docid == null || docid.equals("*")) {
100                root = session.getRootDocument();
101            } else if (session.hasPermission(new IdRef(docid), SecurityConstants.READ)) {
102                root = session.getDocument(new IdRef(docid));
103            } else {
104                UnrestrictedVersionExporter runner = new UnrestrictedVersionExporter(session, docid);
105                runner.runUnrestricted();
106                root = runner.root;
107                needUnrestricted = true;
108
109                // if user can't read version, export is authorized
110                // if he can at least read a proxy pointing to this version
111                if (!root.isVersion()) {
112                    throw new DocumentSecurityException("Not enough rights to export " + root.getPathAsString());
113                }
114                DocumentModelList docs = session.getProxies(root.getRef(), null);
115                boolean hasReadableProxy = false;
116                for (DocumentModel doc : docs) {
117                    if (session.hasPermission(doc.getRef(), SecurityConstants.READ)) {
118                        hasReadableProxy = true;
119                        break;
120                    }
121                }
122                if (!hasReadableProxy) {
123                    throw new DocumentSecurityException(
124                            "Current user doesn't have access to any proxy pointing to version "
125                                    + root.getPathAsString());
126                }
127            }
128        } catch (NuxeoException e) {
129            handleError(res, e);
130            return;
131        }
132
133        if (exportAsZip) {
134            // set the content disposition and file name
135            String FILENAME = "export.zip";
136
137            // use the Facelets APIs to set a new header
138            Map<String, Object> attributes = res.getAttributes();
139            Form headers = (Form) attributes.get(HttpConstants.ATTRIBUTE_HEADERS);
140            if (headers == null) {
141                headers = new Form();
142            }
143            headers.add("Content-Disposition", String.format("attachment; filename=\"%s\";", FILENAME));
144            attributes.put(HttpConstants.ATTRIBUTE_HEADERS, headers);
145        }
146
147        MediaType mediaType = exportAsZip ? MediaType.APPLICATION_ZIP : MediaType.TEXT_XML;
148        Representation entity = makeRepresentation(mediaType, root, exportAsTree, exportAsZip, needUnrestricted);
149
150        res.setEntity(entity);
151        if (mediaType == MediaType.TEXT_XML) {
152            res.getEntity().setCharacterSet(CharacterSet.UTF_8);
153        }
154    }
155
156    protected Representation makeRepresentation(MediaType mediaType, DocumentModel root, final boolean exportAsTree,
157            final boolean exportAsZip, final boolean isUnrestricted) {
158
159        return new ExportRepresentation(mediaType, root, isUnrestricted) {
160
161            @Override
162            protected DocumentPipe makePipe() {
163                if (exportAsTree) {
164                    return new DocumentPipeImpl(10);
165                } else {
166                    return new DocumentPipeImpl();
167                }
168            }
169
170            @Override
171            protected DocumentReader makeDocumentReader(CoreSession documentManager, DocumentModel root)
172                    {
173                DocumentReader documentReader;
174                if (exportAsTree) {
175                    documentReader = new DocumentTreeReader(documentManager, root, false);
176                    if (!exportAsZip) {
177                        ((DocumentTreeReader) documentReader).setInlineBlobs(true);
178                    }
179                } else {
180                    documentReader = new SingleDocumentReader(documentManager, root);
181                }
182                return documentReader;
183            }
184
185            @Override
186            protected DocumentWriter makeDocumentWriter(OutputStream outputStream) throws IOException {
187                DocumentWriter documentWriter;
188                if (exportAsZip) {
189                    documentWriter = new NuxeoArchiveWriter(outputStream);
190                } else {
191                    if (exportAsTree) {
192                        documentWriter = new XMLDocumentTreeWriter(outputStream);
193                    } else {
194                        documentWriter = new XMLDocumentWriter(outputStream);
195                    }
196                }
197                return documentWriter;
198            }
199        };
200    }
201
202    protected static class UnrestrictedVersionExporter extends UnrestrictedSessionRunner {
203
204        private final String docid;
205
206        public DocumentModel root;
207
208        protected UnrestrictedVersionExporter(CoreSession session, String docId) {
209            super(session);
210            docid = docId;
211        }
212
213        @Override
214        public void run() {
215            root = session.getDocument(new IdRef(docid));
216        }
217
218    }
219
220}