001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.ui.apps.logfile;
029
030import org.opencms.file.CmsResource;
031import org.opencms.main.CmsLog;
032import org.opencms.ui.CmsVaadinUtils;
033import org.opencms.ui.components.CmsBasicDialog;
034import org.opencms.util.CmsStringUtil;
035
036import java.io.File;
037import java.io.FileInputStream;
038import java.io.IOException;
039import java.io.OutputStream;
040import java.util.ArrayList;
041import java.util.HashSet;
042import java.util.List;
043import java.util.Set;
044import java.util.zip.ZipEntry;
045import java.util.zip.ZipOutputStream;
046
047import org.apache.commons.logging.Log;
048
049import com.vaadin.server.FileDownloader;
050import com.vaadin.server.Resource;
051import com.vaadin.server.StreamResource;
052import com.vaadin.ui.Button;
053import com.vaadin.ui.Button.ClickEvent;
054import com.vaadin.ui.Button.ClickListener;
055import com.vaadin.ui.Window;
056import com.vaadin.v7.data.Property.ValueChangeEvent;
057import com.vaadin.v7.data.Property.ValueChangeListener;
058import com.vaadin.v7.shared.ui.combobox.FilteringMode;
059import com.vaadin.v7.ui.CheckBox;
060import com.vaadin.v7.ui.ComboBox;
061
062/**
063 * Class for the Download dialog.<p>
064 */
065public class CmsLogDownloadDialog extends CmsBasicDialog {
066
067    /**
068     * Helper class for generating the zip file for the log download.<p>
069     */
070    public static class ZipGenerator {
071
072        /** The set of generated parent directories. */
073        private Set<String> m_directories = new HashSet<>();
074
075        /** The zip output. */
076        private ZipOutputStream m_zos;
077
078        /**
079         * Creates a new instance.<p>
080         *
081         * @param output the output stream to write to
082         */
083        public ZipGenerator(OutputStream output) {
084
085            m_zos = new ZipOutputStream(output);
086        }
087
088        /**
089         * Adds a file to a zip-stream.<p>
090         *
091         * @param directory to be zipped
092         * @param file to be added zo zip
093         * @throws IOException exception
094         */
095        public void addToZip(File directory, File file) throws IOException {
096
097            FileInputStream fis = new FileInputStream(file);
098            String dirPath = directory.getCanonicalPath();
099            String filePath = file.getCanonicalPath();
100            String zipFilePath;
101            if (CmsStringUtil.isPrefixPath(dirPath, filePath)) {
102                zipFilePath = filePath.substring(dirPath.length() + 1, filePath.length());
103            } else {
104                String parentName = generateParentName(file);
105                if (!m_directories.contains(parentName)) {
106                    m_zos.putNextEntry(new ZipEntry(parentName));
107                }
108                m_directories.add(parentName);
109                zipFilePath = CmsStringUtil.joinPaths(parentName, file.getName());
110            }
111            ZipEntry zipEntry = new ZipEntry(zipFilePath);
112            m_zos.putNextEntry(zipEntry);
113
114            byte[] bytes = new byte[1024];
115            int length;
116            while ((length = fis.read(bytes)) >= 0) {
117                m_zos.write(bytes, 0, length);
118            }
119            m_zos.closeEntry();
120            fis.close();
121        }
122
123        /**
124         * Closes the zip stream.<p>
125         *
126         * @throws IOException if something goes wrong
127         */
128        public void close() throws IOException {
129
130            m_zos.close();
131        }
132
133        /**
134         * Generates the name of the parent directory in the zip file for a non-standard log file location.<p>
135         *
136         * @param file the log file
137         * @return the generated parent directory name
138         */
139        String generateParentName(File file) {
140
141            // we might be on Windows, so we can't just assume path is /foo/bar/baz
142            List<String> pathComponents = new ArrayList<>();
143            for (int i = 0; i < (file.toPath().getNameCount() - 1); i++) {
144                pathComponents.add(file.toPath().getName(i).toString());
145            }
146            // need trailing slash when writing directory entries to ZipOutputStream
147            return CmsStringUtil.listAsString(pathComponents, "_") + "/";
148        }
149
150    }
151
152    /** Logger.*/
153    private static Log LOG = CmsLog.getLog(CmsLogDownloadDialog.class.getName());
154
155    /**vaadin serial id.*/
156    private static final long serialVersionUID = -7447640082260176245L;
157
158    /** Path to zip file.*/
159    private static final String ZIP_PATH = CmsLogFileApp.LOG_FOLDER + "logs.zip";
160
161    /**File downloader. */
162    protected FileDownloader m_downloader;
163
164    /**Vaadin component.*/
165    private Button m_cancel;
166
167    /**Vaadin component.**/
168    private CheckBox m_donwloadAll;
169
170    /**Vaadin component.*/
171    private ComboBox m_file;
172
173    /**Vaadin component.*/
174    private Button m_ok;
175
176    /**total size of log files in MB.*/
177    private double m_totalSize;
178
179    /** The download provider to be used for this dialog. */ 
180    private I_CmsLogDownloadProvider m_logProvider;
181
182    /**
183     * public constructor.<p>
184     *
185     * @param window to hold the dialog
186     * @param filePath path of currently shown file
187     */
188    public CmsLogDownloadDialog(final Window window, String filePath, I_CmsLogDownloadProvider logProvider) {
189
190        CmsVaadinUtils.readAndLocalizeDesign(this, CmsVaadinUtils.getWpMessagesForCurrentLocale(), null);
191        m_logProvider = logProvider;
192
193        for (String path : m_logProvider.getLogFiles()) {
194            m_file.addItem(path);
195        }
196
197        m_donwloadAll.setVisible(m_logProvider.canDownloadAllLogs());
198
199        m_file.setFilteringMode(FilteringMode.CONTAINS);
200        m_file.setNullSelectionAllowed(false);
201        m_file.setNewItemsAllowed(false);
202
203        m_file.select(filePath);
204
205        m_cancel.addClickListener(new ClickListener() {
206
207            private static final long serialVersionUID = 4336654148546091114L;
208
209            public void buttonClick(ClickEvent event) {
210
211                window.close();
212
213            }
214
215        });
216        m_downloader = new FileDownloader(getDownloadResource());
217        m_downloader.extend(m_ok);
218
219        ValueChangeListener listener = new ValueChangeListener() {
220
221            private static final long serialVersionUID = -1127012396158402096L;
222
223            public void valueChange(ValueChangeEvent event) {
224
225                m_downloader.setFileDownloadResource(getDownloadResource());
226                setComboBoxEnable();
227
228            }
229        };
230
231        m_file.addValueChangeListener(listener);
232        m_donwloadAll.addValueChangeListener(listener);
233
234    }
235
236    /**
237     * Creates log-file resource for download.<p>
238     *
239     * @return vaadin resource
240     */
241    protected Resource getDownloadResource() {
242
243        String pathToDownload = (String)m_file.getValue();
244        if (pathToDownload == null) {
245            return null;
246        }
247
248        if (m_donwloadAll.getValue().booleanValue()) {
249
250            return new StreamResource(
251                () -> m_logProvider.readAllLogs(),
252                m_logProvider.getDownloadPrefix() + "logs.zip");
253        }
254
255        return new StreamResource(
256            () -> m_logProvider.readLog(pathToDownload),
257            m_logProvider.getDownloadPrefix() + CmsResource.getName(pathToDownload));
258    }
259
260    /**
261     * En/ disables the combo box for files.<p>
262     */
263    protected void setComboBoxEnable() {
264
265        m_file.setEnabled(!m_donwloadAll.getValue().booleanValue());
266    }
267
268}