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