001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://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 GmbH & Co. KG, please see the
018 * company website: https://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: https://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.workplace.tools.modules;
029
030import org.opencms.configuration.CmsConfigurationException;
031import org.opencms.jsp.CmsJspActionElement;
032import org.opencms.main.CmsRuntimeException;
033import org.opencms.main.OpenCms;
034import org.opencms.module.CmsModule;
035import org.opencms.module.CmsModuleDependency;
036import org.opencms.module.CmsModuleImportExportHandler;
037import org.opencms.module.CmsModuleManager;
038import org.opencms.widgets.CmsDisplayWidget;
039import org.opencms.widgets.CmsSelectWidget;
040import org.opencms.widgets.CmsSelectWidgetOption;
041import org.opencms.workplace.CmsWidgetDialog;
042import org.opencms.workplace.CmsWidgetDialogParameter;
043import org.opencms.workplace.CmsWorkplaceSettings;
044import org.opencms.workplace.tools.CmsToolDialog;
045import org.opencms.workplace.tools.CmsToolManager;
046
047import java.io.File;
048import java.io.IOException;
049import java.text.Collator;
050import java.util.ArrayList;
051import java.util.Collections;
052import java.util.Comparator;
053import java.util.HashMap;
054import java.util.List;
055import java.util.Map;
056
057import jakarta.servlet.ServletException;
058import jakarta.servlet.http.HttpServletRequest;
059import jakarta.servlet.http.HttpServletResponse;
060import jakarta.servlet.jsp.PageContext;
061
062/**
063 * Class to upload a module from the server.<p>
064 *
065 * @since 6.0.0
066 */
067public class CmsModulesUploadFromServer extends CmsWidgetDialog {
068
069    /**
070     * A <code>{@link Comparator}</code> for <code>{@link CmsSelectWidgetOption}</code> instances.<p>
071     *
072     * @since 7.0.3
073     *
074     */
075    protected class ComparatorSelectWidgetOption implements Comparator {
076
077        /** Collator used / wrapped. */
078        private Collator m_collator = Collator.getInstance(getLocale());
079
080        /**
081         * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
082         */
083        public int compare(Object arg0, Object arg1) {
084
085            CmsSelectWidgetOption o1 = (CmsSelectWidgetOption)arg0;
086            CmsSelectWidgetOption o2 = (CmsSelectWidgetOption)arg1;
087            return m_collator.compare(o1.getOption(), o2.getOption());
088        }
089
090    }
091
092    /** The dialog type. */
093    public static final String DIALOG_TYPE = "ModulesUploadServer";
094
095    /** The import action. */
096    protected static final String IMPORT_ACTION_REPORT = "/system/workplace/admin/modules/reports/import.jsp";
097
098    /** Defines which pages are valid for this dialog. */
099    public static final String[] PAGES = {"page1"};
100
101    /** Modulename parameter. */
102    public static final String PARAM_MODULENAME = "modulename";
103
104    /** The replace action. */
105    protected static final String REPLACE_ACTION_REPORT = "/system/workplace/admin/modules/reports/replace.jsp";
106
107    /** Modulename. */
108    private String m_moduleupload;
109
110    /**
111     * Public constructor with JSP action element.<p>
112     *
113     * @param jsp an initialized JSP action element
114     */
115    public CmsModulesUploadFromServer(CmsJspActionElement jsp) {
116
117        super(jsp);
118    }
119
120    /**
121     * Public constructor with JSP variables.<p>
122     *
123     * @param context the JSP page context
124     * @param req the JSP request
125     * @param res the JSP response
126     */
127    public CmsModulesUploadFromServer(PageContext context, HttpServletRequest req, HttpServletResponse res) {
128
129        this(new CmsJspActionElement(context, req, res));
130    }
131
132    /**
133     * @see org.opencms.workplace.CmsWidgetDialog#actionCommit()
134     */
135    @Override
136    public void actionCommit() throws IOException, ServletException {
137
138        List errors = new ArrayList();
139        CmsModule module = null;
140        try {
141            String importpath = OpenCms.getSystemInfo().getPackagesRfsPath();
142            importpath = OpenCms.getSystemInfo().getAbsoluteRfsPathRelativeToWebInf(
143                importpath + "modules/" + m_moduleupload);
144            module = CmsModuleImportExportHandler.readModuleFromImport(importpath);
145
146            // check if all dependencies are fulfilled
147            List dependencies = OpenCms.getModuleManager().checkDependencies(
148                module,
149                CmsModuleManager.DEPENDENCY_MODE_IMPORT);
150            if (!dependencies.isEmpty()) {
151                StringBuffer dep = new StringBuffer(32);
152                for (int i = 0; i < dependencies.size(); i++) {
153                    CmsModuleDependency dependency = (CmsModuleDependency)dependencies.get(i);
154                    dep.append("\n - ");
155                    dep.append(dependency.getName());
156                    dep.append(" (Version: ");
157                    dep.append(dependency.getVersion());
158                    dep.append(")");
159                }
160                errors.add(
161                    new CmsRuntimeException(
162                        Messages.get().container(
163                            Messages.ERR_ACTION_MODULE_DEPENDENCY_2,
164                            m_moduleupload,
165                            new String(dep))));
166            }
167
168        } catch (CmsConfigurationException e) {
169            errors.add(
170                new CmsRuntimeException(
171                    Messages.get().container(Messages.ERR_ACTION_MODULE_UPLOAD_1, m_moduleupload),
172                    e));
173        }
174
175        if ((module != null) && errors.isEmpty()) {
176
177            // refresh the list
178            Map objects = (Map)getSettings().getListObject();
179            if (objects != null) {
180                objects.remove(CmsModulesList.class.getName());
181            }
182
183            // redirect
184            Map param = new HashMap();
185            param.put(CmsModulesList.PARAM_MODULE, m_moduleupload);
186            param.put(PARAM_STYLE, CmsToolDialog.STYLE_NEW);
187            param.put(PARAM_CLOSELINK, CmsToolManager.linkForToolPath(getJsp(), "/modules"));
188            if (OpenCms.getModuleManager().hasModule(module.getName())) {
189                param.put(PARAM_MODULENAME, module.getName());
190                getToolManager().jspForwardPage(this, REPLACE_ACTION_REPORT, param);
191            } else {
192                getToolManager().jspForwardPage(this, IMPORT_ACTION_REPORT, param);
193            }
194        }
195
196        // set the list of errors to display when saving failed
197        setCommitErrors(errors);
198    }
199
200    /**
201     * Gets the module parameter.<p>
202     *
203     * @return the module parameter
204     */
205    public String getModuleupload() {
206
207        return m_moduleupload;
208    }
209
210    /**
211     * Sets the module parameter.<p>
212     * @param module the module parameter
213     */
214    public void setModuleupload(String module) {
215
216        m_moduleupload = module;
217    }
218
219    /**
220     * Creates the dialog HTML for all defined widgets of the named dialog (page).<p>
221     *
222     * @param dialog the dialog (page) to get the HTML for
223     * @return the dialog HTML for all defined widgets of the named dialog (page)
224     */
225    @Override
226    protected String createDialogHtml(String dialog) {
227
228        StringBuffer result = new StringBuffer(1024);
229
230        // create table
231        result.append(createWidgetTableStart());
232
233        // show error header once if there were validation errors
234        result.append(createWidgetErrorHeader());
235
236        if (dialog.equals(PAGES[0])) {
237            result.append(dialogBlockStart(key("label.uploadfromserver")));
238            result.append(createWidgetTableStart());
239            result.append(createDialogRowsHtml(0, 0));
240            result.append(createWidgetTableEnd());
241            result.append(dialogBlockEnd());
242        }
243
244        // close table
245        result.append(createWidgetTableEnd());
246
247        return result.toString();
248    }
249
250    /**
251     * Creates the list of widgets for this dialog.<p>
252     */
253    @Override
254    protected void defineWidgets() {
255
256        List selectOptions = getModulesFromServer();
257
258        if (selectOptions.isEmpty()) {
259            // no import modules available, display message
260            addWidget(
261                new CmsWidgetDialogParameter(
262                    this,
263                    "moduleupload",
264                    PAGES[0],
265                    new CmsDisplayWidget(key(Messages.GUI_MODULES_IMPORT_NOT_AVAILABLE_0))));
266        } else {
267            // add the file select box widget
268            addWidget(new CmsWidgetDialogParameter(this, "moduleupload", PAGES[0], new CmsSelectWidget(selectOptions)));
269        }
270    }
271
272    /**
273     * @see org.opencms.workplace.CmsWidgetDialog#getPageArray()
274     */
275    @Override
276    protected String[] getPageArray() {
277
278        return PAGES;
279    }
280
281    /**
282     * @see org.opencms.workplace.CmsWorkplace#initMessages()
283     */
284    @Override
285    protected void initMessages() {
286
287        // add specific dialog resource bundle
288        addMessages(Messages.get().getBundleName());
289        // add default resource bundles
290        super.initMessages();
291    }
292
293    /**
294     * @see org.opencms.workplace.CmsWorkplace#initWorkplaceRequestValues(org.opencms.workplace.CmsWorkplaceSettings, jakarta.servlet.http.HttpServletRequest)
295     */
296    @Override
297    protected void initWorkplaceRequestValues(CmsWorkplaceSettings settings, HttpServletRequest request) {
298
299        // set the dialog type
300        setParamDialogtype(DIALOG_TYPE);
301
302        super.initWorkplaceRequestValues(settings, request);
303
304        // save the current state of the job (may be changed because of the widget values)
305        setDialogObject(m_moduleupload);
306    }
307
308    /**
309     * Returns the list of all modules available on the server in prepared CmsSelectWidgetOption objects.<p>
310     *
311     * @return List of module names in CmsSelectWidgetOption objects
312     */
313    private List getModulesFromServer() {
314
315        List result = new ArrayList();
316
317        // get the systems-exportpath
318        String exportpath = OpenCms.getSystemInfo().getPackagesRfsPath();
319        exportpath = OpenCms.getSystemInfo().getAbsoluteRfsPathRelativeToWebInf(exportpath + "modules");
320        File folder = new File(exportpath);
321
322        // get a list of all files
323        String[] list = folder.list();
324        for (int i = 0; i < list.length; i++) {
325            try {
326                File diskFile = new File(exportpath, list[i]);
327                // check if it is a file and ends with zip -> this is a module
328                if (diskFile.isFile() && diskFile.getName().endsWith(".zip")) {
329                    result.add(new CmsSelectWidgetOption(diskFile.getName()));
330                } else if (diskFile.isDirectory()
331                    && ((new File(diskFile + File.separator + "manifest.xml")).exists())) {
332                    // this is a folder with manifest file -> this a module
333                    result.add(new CmsSelectWidgetOption(diskFile.getName()));
334                }
335            } catch (Throwable t) {
336                // ignore and continue
337            }
338        }
339
340        Collections.sort(result, new ComparatorSelectWidgetOption());
341        return result;
342    }
343
344}