View Javadoc
1   /**
2    * This file Copyright (c) 2003-2014 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.module.admininterface.pages;
35  
36  import info.magnolia.cms.beans.config.ContentRepository;
37  import info.magnolia.cms.core.HierarchyManager;
38  import info.magnolia.cms.i18n.Messages;
39  import info.magnolia.cms.i18n.MessagesManager;
40  import info.magnolia.cms.security.AccessDeniedException;
41  import info.magnolia.cms.security.AccessManager;
42  import info.magnolia.cms.security.Permission;
43  import info.magnolia.cms.util.AlertUtil;
44  import info.magnolia.context.MgnlContext;
45  import info.magnolia.importexport.DataTransporter;
46  import info.magnolia.module.admininterface.TemplatedMVCHandler;
47  import info.magnolia.repository.RepositoryConstants;
48  
49  import java.io.IOException;
50  import java.io.OutputStream;
51  import java.util.Iterator;
52  
53  import javax.jcr.LoginException;
54  import javax.jcr.PathNotFoundException;
55  import javax.jcr.RepositoryException;
56  import javax.jcr.Session;
57  import javax.jcr.Workspace;
58  import javax.servlet.ServletException;
59  import javax.servlet.http.HttpServletRequest;
60  import javax.servlet.http.HttpServletResponse;
61  
62  import org.apache.commons.lang.StringEscapeUtils;
63  import org.apache.commons.lang.StringUtils;
64  import org.slf4j.Logger;
65  import org.slf4j.LoggerFactory;
66  
67  
68  /**
69   * Simple servlet used to import/export data from jcr using the standard jcr import/export features.
70   * @author Fabrizio Giustina
71   * @version $Id$
72   */
73  public class ExportPage extends TemplatedMVCHandler {
74  
75      /**
76       * Stable serialVersionUID.
77       */
78      public static final long serialVersionUID = 222L;
79  
80      public static final String MIME_TEXT_XML = "text/xml";
81  
82      public static final String MIME_GZIP = "application/x-gzip";
83  
84      public static final String MIME_APPLICATION_ZIP = "application/zip";
85  
86      /**
87       * View value for the export file stream (won't render anything)
88       */
89      public static final String VIEW_EXPORT="export";
90  
91      /**
92       * Logger.
93       */
94      private static Logger log = LoggerFactory.getLogger(ExportPage.class);
95  
96      protected String mgnlRepository;
97  
98      protected String mgnlPath;
99  
100     private boolean mgnlFormat;
101 
102     private String ext;
103 
104     private boolean exportxml;
105 
106     /**
107      * Getter for <code>ext</code>.
108      * @return Returns the ext.
109      */
110     public String getExt() {
111         return this.ext;
112     }
113 
114     /**
115      * Setter for <code>ext</code>.
116      * @param ext The ext to set.
117      */
118     public void setExt(String ext) {
119         this.ext = ext;
120     }
121 
122     /**
123      * Getter for <code>mgnlFormat</code>.
124      * @return Returns the mgnlFormat.
125      */
126     public boolean isMgnlFormat() {
127         return this.mgnlFormat;
128     }
129 
130     /**
131      * Setter for <code>mgnlFormat</code>.
132      * @param mgnlFormat The mgnlFormat to set.
133      */
134     public void setMgnlFormat(boolean mgnlFormat) {
135         this.mgnlFormat = mgnlFormat;
136     }
137 
138     /**
139      * Getter for <code>mgnlPath</code>.
140      * @return Returns the mgnlPath.
141      */
142     public String getMgnlPath() {
143         return this.mgnlPath;
144     }
145 
146     /**
147      * Setter for <code>mgnlPath</code>.
148      * @param mgnlPath The mgnlPath to set.
149      */
150     public void setMgnlPath(String mgnlPath) {
151         this.mgnlPath = mgnlPath;
152     }
153 
154     /**
155      * Getter for <code>mgnlRepository</code>.
156      * @return Returns the mgnlRepository.
157      */
158     public String getMgnlRepository() {
159         return this.mgnlRepository;
160     }
161 
162     /**
163      * Setter for <code>mgnlRepository</code>.
164      * @param mgnlRepository The mgnlRepository to set.
165      */
166     public void setMgnlRepository(String mgnlRepository) {
167         this.mgnlRepository = mgnlRepository;
168     }
169 
170     /**
171      * Getter for <code>exportxml</code>.
172      * @return Returns the exportxml.
173      */
174     public boolean isExportxml() {
175         return this.exportxml;
176     }
177 
178     /**
179      * Setter for <code>exportxml</code>.
180      * @param exportxml The exportxml to set.
181      */
182     public void setExportxml(boolean exportxml) {
183         this.exportxml = exportxml;
184     }
185 
186     /**
187      * @param name
188      * @param request
189      * @param response
190      */
191     public ExportPage(String name, HttpServletRequest request, HttpServletResponse response) {
192         super(name, request, response);
193     }
194 
195     /**
196      * @see info.magnolia.cms.servlets.MVCServletHandlerImpl#getCommand()
197      */
198     @Override
199     public String getCommand() {
200         if (this.exportxml) {
201             return "exportxml";
202         }
203         return super.getCommand();
204     }
205 
206     /**
207      * Actually perform export. The generated file is sent to the client.
208      * @param response HttpServletResponse
209      * @param repository selected repository
210      * @param basepath base path in repository
211      * @param format should we format the resulting xml
212      * @param keepVersionHistory if <code>false</code> version info will be stripped from the exported document
213      * @throws IOException for errors while accessing the servlet output stream
214      */
215     public String exportxml() throws Exception {
216 
217         if (StringUtils.isEmpty(mgnlRepository)) {
218             mgnlRepository = RepositoryConstants.WEBSITE;
219         }
220         if (StringUtils.isEmpty(mgnlPath)) {
221             mgnlPath = "/";
222         }
223         if (StringUtils.isEmpty(ext)) {
224             ext = DataTransporter.XML;
225         }
226 
227         checkPath(); //check if path exists
228 
229         if (!checkPermissions(request, mgnlRepository, mgnlPath, Permission.WRITE)) {
230 
231             AlertUtil.setMessage("User not allowed to modify own user data [" + StringEscapeUtils.escapeHtml(mgnlPath) + "].");
232 
233             throw new ServletException(new AccessDeniedException(
234                 "User not allowed to modify own user data ["
235                     + StringEscapeUtils.escapeHtml(mgnlPath) //escape to prevent XSS attack
236                     + "]."));
237 
238         }
239         HierarchyManager hr = MgnlContext.getHierarchyManager(mgnlRepository);
240         Workspace ws = hr.getWorkspace();
241         Session session = ws.getSession();
242 
243         if (ext.equalsIgnoreCase(DataTransporter.ZIP)) {
244             response.setContentType(MIME_APPLICATION_ZIP);
245         }
246         else if (ext.equalsIgnoreCase(DataTransporter.GZ)) {
247             response.setContentType(MIME_GZIP);
248         }
249         else {
250             response.setContentType(MIME_TEXT_XML);
251             response.setCharacterEncoding("UTF-8");
252         }
253 
254         String pathName = DataTransporter.createExportPath(mgnlPath);
255         pathName = DataTransporter.encodePath(pathName, DataTransporter.DOT, DataTransporter.UTF8);
256         if (DataTransporter.DOT.equals(pathName)) {
257             // root node
258             pathName = StringUtils.EMPTY;
259         }
260 
261         response.setHeader("content-disposition", "attachment; filename=" + mgnlRepository + pathName + ext);
262         OutputStream baseOutputStream = response.getOutputStream();
263 
264         try {
265             DataTransporter.executeExport(
266                 baseOutputStream,
267                 false,
268                 mgnlFormat,
269                 session,
270                 mgnlPath,
271                 mgnlRepository,
272                 ext);
273         }
274         catch (RuntimeException e) {
275             response.setContentType("text/html; charset=UTF-8");
276             response.setHeader("content-disposition", "inline");
277             throw e;
278         }
279 
280         return VIEW_EXPORT;
281     }
282 
283     /**
284      * Uses access manager to authorise this request.
285      * @param request HttpServletRequest as received by the service method
286      * @return boolean true if read access is granted
287      */
288     protected boolean checkPermissions(HttpServletRequest request, String repository, String basePath,
289         long permissionType) {
290 
291         AccessManager accessManager = MgnlContext.getAccessManager(repository);
292         if (accessManager != null) {
293             if (!accessManager.isGranted(basePath, permissionType)) {
294                 return false;
295             }
296         }
297         return true;
298     }
299 
300     @Override
301     public void renderHtml(String view) throws IOException {
302         // if we are exporing the file, everything is already done --> do not render
303         if(VIEW_EXPORT.equals(view)){
304             return;
305         }
306         super.renderHtml(view);
307     }
308 
309     public Messages getMessages() {
310         return MessagesManager.getMessages();
311     }
312 
313     public Iterator getRepositories() {
314         return ContentRepository.getAllRepositoryNames();
315     }
316 
317     protected void checkPath() throws LoginException, RepositoryException, ServletException {
318         try {
319             if (!MgnlContext.getJCRSession(mgnlRepository).nodeExists(mgnlPath)) {
320                 String escapedMessage = "The path [" + StringEscapeUtils.escapeHtml(mgnlPath) + "] doesn't exist in the [" + mgnlRepository + "] repository."; // escape to prevent XSS attack
321                 AlertUtil.setMessage(escapedMessage);
322                 throw new ServletException(new PathNotFoundException(escapedMessage));
323             }
324         } catch (RepositoryException e) {
325             String escapedMessage = StringEscapeUtils.escapeHtml(e.getMessage());
326             AlertUtil.setMessage(escapedMessage);
327             throw new ServletException(new RepositoryException(escapedMessage)); // escape to prevent XSS attack
328         }
329     }
330 }