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 GmbH & Co. KG, 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.setup;
029
030import org.opencms.configuration.CmsConfigurationException;
031import org.opencms.configuration.CmsConfigurationManager;
032import org.opencms.configuration.CmsModuleConfiguration;
033import org.opencms.configuration.CmsParameterConfiguration;
034import org.opencms.file.CmsProject;
035import org.opencms.file.CmsResource;
036import org.opencms.file.types.I_CmsResourceType;
037import org.opencms.i18n.CmsEncoder;
038import org.opencms.importexport.CmsImportParameters;
039import org.opencms.main.CmsException;
040import org.opencms.main.CmsLog;
041import org.opencms.main.CmsShell;
042import org.opencms.main.CmsSystemInfo;
043import org.opencms.main.OpenCms;
044import org.opencms.module.CmsModule;
045import org.opencms.module.CmsModuleVersion;
046import org.opencms.module.CmsModuleXmlHandler;
047import org.opencms.relations.I_CmsLinkParseable;
048import org.opencms.report.CmsHtmlReport;
049import org.opencms.report.CmsShellReport;
050import org.opencms.report.I_CmsReport;
051import org.opencms.security.CmsRole;
052import org.opencms.setup.db.CmsUpdateDBThread;
053import org.opencms.setup.xml.CmsXmlConfigUpdater;
054import org.opencms.util.CmsStringUtil;
055import org.opencms.workplace.threads.CmsXmlContentRepairSettings;
056import org.opencms.workplace.threads.CmsXmlContentRepairThread;
057import org.opencms.workplace.tools.CmsIdentifiableObjectContainer;
058import org.opencms.xml.CmsXmlException;
059
060import java.io.File;
061import java.io.FileFilter;
062import java.io.FileInputStream;
063import java.io.FileOutputStream;
064import java.io.IOException;
065import java.lang.reflect.Method;
066import java.nio.file.FileVisitResult;
067import java.nio.file.FileVisitor;
068import java.nio.file.Files;
069import java.nio.file.Path;
070import java.nio.file.attribute.BasicFileAttributes;
071import java.util.ArrayList;
072import java.util.Arrays;
073import java.util.Collections;
074import java.util.HashMap;
075import java.util.HashSet;
076import java.util.Iterator;
077import java.util.List;
078import java.util.Map;
079import java.util.Map.Entry;
080import java.util.Set;
081import java.util.jar.Attributes;
082import java.util.jar.JarInputStream;
083import java.util.jar.Manifest;
084
085import javax.servlet.jsp.JspWriter;
086
087import org.apache.commons.logging.Log;
088
089import com.google.common.base.Objects;
090import com.google.common.collect.Lists;
091
092/**
093 * A java bean as a controller for the OpenCms update wizard.<p>
094 *
095 * @since 6.0.0
096 */
097public class CmsUpdateBean extends CmsSetupBean {
098
099    /** The empty jar marker attribute key. */
100    public static final String EMPTY_JAR_ATTRIBUTE_KEY = "OpenCms-empty-jar";
101
102    /** Folder constant name.<p> */
103    public static final String FOLDER_UPDATE = "WEB-INF/updatedata" + File.separatorChar;
104
105    /** The static log object for this class. */
106    static final Log LOG = CmsLog.getLog(CmsUpdateBean.class);
107
108    /** replace pattern constant for the cms script. */
109    private static final String C_ADMIN_GROUP = "@ADMIN_GROUP@";
110
111    /** replace pattern constant for the cms script. */
112    private static final String C_ADMIN_PWD = "@ADMIN_PWD@";
113
114    /** replace pattern constant for the cms script. */
115    private static final String C_ADMIN_USER = "@ADMIN_USER@";
116
117    /** replace pattern constant for the cms script. */
118    private static final String C_UPDATE_PROJECT = "@UPDATE_PROJECT@";
119
120    /** replace pattern constant for the cms script. */
121    private static final String C_UPDATE_SITE = "@UPDATE_SITE@";
122
123    /** New MySQL JDBC driver class name. */
124    private static final String MYSQL_DRIVER_CLASS_NEW = "com.mysql.cj.jdbc.Driver";
125
126    /** Old MySQL JDBC driver class name. */
127    private static final String MYSQL_DRIVER_CLASS_OLD = "org.gjt.mm.mysql.Driver";
128
129    /** MariaDB MySQL JDBC driver class name (used from OpenCms 12 onwards). */
130    private static final String MYSQL_DRIVER_CLASS_MARIADB = "org.mariadb.jdbc.Driver";
131
132    /** The obsolete modules that should be removed. */
133    private static String[] OBSOLETE_MODULES = new String[] {
134        "org.opencms.ade.config",
135        "org.opencms.ade.containerpage",
136        "org.opencms.ade.contenteditor",
137        "org.opencms.ade.editprovider",
138        "org.opencms.ade.galleries",
139        "org.opencms.ade.postupload",
140        "org.opencms.ade.properties",
141        "org.opencms.ade.publish",
142        "org.opencms.ade.sitemap",
143        "org.opencms.ade.upload",
144        "org.opencms.editors.codemirror",
145        "org.opencms.editors.tinymce",
146        "org.opencms.editors",
147        "org.opencms.gwt",
148        "org.opencms.jquery",
149        "org.opencms.jsp.search",
150        "org.opencms.locale.cs",
151        "org.opencms.locale.da",
152        "org.opencms.locale.de",
153        "org.opencms.locale.es",
154        "org.opencms.locale.it",
155        "org.opencms.locale.ja",
156        "org.opencms.locale.ru",
157        "org.opencms.locale.zh",
158        "org.opencms.ugc",
159        "org.opencms.workplace",
160        "org.opencms.workplace.administration",
161        "org.opencms.workplace.explorer",
162        "org.opencms.workplace.handler",
163        "org.opencms.workplace.spellcheck",
164        "org.opencms.workplace.tools.accounts",
165        "org.opencms.workplace.tools.cache",
166        "org.opencms.workplace.tools.content",
167        "org.opencms.workplace.tools.database",
168        "org.opencms.workplace.tools.galleryoverview",
169        "org.opencms.workplace.tools.git",
170        "org.opencms.workplace.tools.history",
171        "org.opencms.workplace.tools.link",
172        "org.opencms.workplace.tools.modules",
173        "org.opencms.workplace.tools.projects",
174        "org.opencms.workplace.tools.publishqueue",
175        "org.opencms.workplace.tools.scheduler",
176        "org.opencms.workplace.tools.searchindex",
177        "org.opencms.workplace.tools.sites",
178        "org.opencms.workplace.tools.workplace",
179        "org.opencms.workplace.traditional",
180        "org.opencms.workplace.help.de",
181        "org.opencms.workplace.help.en",
182        "org.opencms.workplace.help",
183        "org.opencms.workplace.tools.git"};
184
185    /** Static flag to indicate if all modules should be updated regardless of their version number. */
186    private static final boolean UPDATE_ALL_MODULES = false;
187
188    /** The new logging offset in the database update thread. */
189    protected int m_newLoggingDBOffset;
190
191    /** The old logging offset in the database update thread. */
192    protected int m_oldLoggingDBOffset;
193
194    /** The used admin user name. */
195    private String m_adminGroup = "_tmpUpdateGroup" + (System.currentTimeMillis() % 1000);
196
197    /** the admin user password. */
198    private String m_adminPwd = "admin";
199
200    /** The used admin user name. */
201    private String m_adminUser = "Admin";
202
203    /** The XML updater instance (lazily initialized). */
204    private CmsXmlConfigUpdater m_configUpdater;
205
206    /** The update database thread. */
207    private CmsUpdateDBThread m_dbUpdateThread;
208
209    /** The detected mayor version, based on DB structure. */
210    private double m_detectedVersion;
211
212    /** Parameter for keeping the history. */
213    private boolean m_keepHistory;
214
215    /** List of module to be updated. */
216    private List<String> m_modulesToUpdate;
217
218    /** The list of modules that should keep their libs. */
219    private List<String> m_preserveLibModules;
220
221    /** the update project. */
222    private String m_updateProject = "_tmpUpdateProject" + (System.currentTimeMillis() % 1000);
223
224    /** the site for update. */
225    private String m_updateSite = CmsResource.VFS_FOLDER_SITES + "/default/";
226
227    /** Cache for the up-to-date module names. */
228    private List<String> m_uptodateModules;
229
230    /** The workplace import thread. */
231    private CmsUpdateThread m_workplaceUpdateThread;
232
233    /**
234     * Default constructor.<p>
235     */
236    public CmsUpdateBean() {
237
238        super();
239        m_preserveLibModules = Collections.emptyList();
240        m_modulesFolder = FOLDER_UPDATE + CmsSystemInfo.FOLDER_MODULES;
241        m_logFile = OpenCms.getSystemInfo().getLogFileRfsFolder() + "update.log";
242    }
243
244    /**
245     * Adds the subscription driver to the properties.<p>
246     */
247    public void addSubscriptionDriver() {
248
249        setExtProperty("driver.subscription", "db");
250        String dbName = getExtProperty("db.name");
251        String packageName = getDbPackage(dbName);
252        setExtProperty("db.subscription.driver", "org.opencms.db." + packageName + ".CmsSubscriptionDriver");
253        setExtProperty("db.subscription.pool", "opencms:default");
254        setExtProperty("db.subscription.sqlmanager", "org.opencms.db." + packageName + ".CmsSqlManager");
255    }
256
257    /**
258     * Compatibility check for OCEE modules.<p>
259     *
260     * @param version the opencms version
261     *
262     * @return <code>false</code> if OCEE is present but not compatible with opencms version
263     */
264    @SuppressWarnings({"boxing"})
265    public boolean checkOceeVersion(String version) {
266
267        try {
268            Class<?> manager = Class.forName("org.opencms.ocee.base.CmsOceeManager");
269            Method checkVersion = manager.getMethod("checkOceeVersion", String.class);
270            return (Boolean)checkVersion.invoke(manager, version);
271        } catch (@SuppressWarnings("unused") ClassNotFoundException e) {
272            return true;
273        } catch (Exception e) {
274            e.printStackTrace();
275            return false;
276        }
277    }
278
279    /**
280     * Creates the shared folder if possible.<p>
281     *
282     * @throws Exception if something goes wrong
283     */
284    public void createSharedFolder() throws Exception {
285
286        String originalSiteRoot = m_cms.getRequestContext().getSiteRoot();
287        CmsProject originalProject = m_cms.getRequestContext().getCurrentProject();
288        try {
289            m_cms.getRequestContext().setSiteRoot("");
290            m_cms.getRequestContext().setCurrentProject(m_cms.createTempfileProject());
291            if (!m_cms.existsResource("/shared")) {
292                m_cms.createResource("/shared", OpenCms.getResourceManager().getResourceType("folder"));
293            }
294
295            try {
296                m_cms.lockResourceTemporary("/shared");
297            } catch (CmsException e) {
298                LOG.error(e.getLocalizedMessage(), e);
299            }
300            try {
301                m_cms.chacc("/shared", "group", "Users", "+v+w+r+i");
302            } catch (CmsException e) {
303                LOG.error(e.getLocalizedMessage(), e);
304            }
305            CmsResource shared = m_cms.readResource("/shared");
306            try {
307                OpenCms.getPublishManager().publishProject(
308                    m_cms,
309                    new CmsHtmlReport(m_cms.getRequestContext().getLocale(), m_cms.getRequestContext().getSiteRoot()),
310                    shared,
311                    false);
312                OpenCms.getPublishManager().waitWhileRunning();
313            } catch (CmsException e) {
314                LOG.error(e.getLocalizedMessage(), e);
315            }
316        } finally {
317            m_cms.getRequestContext().setSiteRoot(originalSiteRoot);
318            m_cms.getRequestContext().setCurrentProject(originalProject);
319        }
320
321    }
322
323    /**
324     * CmsShell command to delete spellcheck index.<p>
325     *
326     * Called by cmsupdate.ori to remove spellcheck index. Necessary because Solr/Lucene versions might have
327     * incompatible changes, and deleting the index causes the spellcheck index to be rebuilt.
328     */
329    public void deleteSpellcheckIndex() {
330
331        String dataPath = OpenCms.getSystemInfo().getAbsoluteRfsPathRelativeToWebInf("solr/spellcheck/data");
332        File dataDir = new File(dataPath);
333        if (dataDir.exists()) {
334            try {
335                Files.walkFileTree(dataDir.toPath(), new FileVisitor<Path>() {
336
337                    public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
338
339                        dir.toFile().delete();
340                        return FileVisitResult.CONTINUE;
341                    }
342
343                    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
344
345                        return FileVisitResult.CONTINUE;
346                    }
347
348                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
349
350                        file.toFile().delete();
351                        return FileVisitResult.CONTINUE;
352                    }
353
354                    public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
355
356                        return FileVisitResult.CONTINUE;
357
358                    }
359                });
360            } catch (IOException e) {
361                e.printStackTrace(System.err);
362            }
363        }
364
365    }
366
367    /**
368     * Returns html code to display an error.<p>
369     *
370     * @param pathPrefix to adjust the path
371     *
372     * @return html code
373     */
374    @Override
375    public String displayError(String pathPrefix) {
376
377        if (pathPrefix == null) {
378            pathPrefix = "";
379        }
380        StringBuffer html = new StringBuffer(512);
381        html.append("<table border='0' cellpadding='5' cellspacing='0' style='width: 100%; height: 100%;'>");
382        html.append("\t<tr>");
383        html.append("\t\t<td style='vertical-align: middle; height: 100%;'>");
384        html.append(getHtmlPart("C_BLOCK_START", "Error"));
385        html.append("\t\t\t<table border='0' cellpadding='0' cellspacing='0' style='width: 100%;'>");
386        html.append("\t\t\t\t<tr>");
387        html.append("\t\t\t\t\t<td><img src='").append(pathPrefix).append("resources/error.png' border='0'></td>");
388        html.append("\t\t\t\t\t<td>&nbsp;&nbsp;</td>");
389        html.append("\t\t\t\t\t<td style='width: 100%;'>");
390        html.append("\t\t\t\t\t\tThe Alkacon OpenCms update wizard has not been started correctly!<br>");
391        html.append("\t\t\t\t\t\tPlease click <a href='").append(pathPrefix);
392        html.append("index.jsp'>here</a> to restart the wizard.");
393        html.append("\t\t\t\t\t</td>");
394        html.append("\t\t\t\t</tr>");
395        html.append("\t\t\t</table>");
396        html.append(getHtmlPart("C_BLOCK_END"));
397        html.append("\t\t</td>");
398        html.append("\t</tr>");
399        html.append("</table>");
400        return html.toString();
401    }
402
403    /**
404     * Returns the admin Pwd.<p>
405     *
406     * @return the admin Pwd
407     */
408    public String getAdminPwd() {
409
410        return m_adminPwd;
411    }
412
413    /**
414     * Returns the admin User.<p>
415     *
416     * @return the admin User
417     */
418    public String getAdminUser() {
419
420        return m_adminUser;
421    }
422
423    /**
424     * Gets the folder for config files.
425     *
426     * @return the folder for config files
427     */
428    public File getConfigFolder() {
429
430        return new File(getWebAppRfsPath() + "WEB-INF/config");
431    }
432
433    /**
434     * Returns the detected mayor version, based on DB structure.<p>
435     *
436     * @return the detected mayor version
437     */
438    public double getDetectedVersion() {
439
440        return m_detectedVersion;
441    }
442
443    /**
444     * Returns a map of all previously installed modules.<p>
445     *
446     * @return a map of <code>[String, {@link org.opencms.module.CmsModuleVersion}]</code> objects
447     *
448     * @see org.opencms.module.CmsModuleManager#getAllInstalledModules()
449     */
450    public Map<String, CmsModuleVersion> getInstalledModules() {
451
452        String file = CmsModuleConfiguration.DEFAULT_XML_FILE_NAME;
453        // /opencms/modules/module[?]
454        String basePath = new StringBuffer("/").append(CmsConfigurationManager.N_ROOT).append("/").append(
455            CmsModuleConfiguration.N_MODULES).append("/").append(CmsModuleXmlHandler.N_MODULE).append(
456                "[?]/").toString();
457        Map<String, CmsModuleVersion> modules = new HashMap<String, CmsModuleVersion>();
458        String name = "";
459        for (int i = 1; name != null; i++) {
460            if (i > 1) {
461                String ver = CmsModuleVersion.DEFAULT_VERSION;
462                try {
463                    ver = getXmlHelper().getValue(
464                        file,
465                        CmsStringUtil.substitute(basePath, "?", "" + (i - 1)) + CmsModuleXmlHandler.N_VERSION);
466                } catch (@SuppressWarnings("unused") CmsXmlException e) {
467                    // ignore
468                }
469                modules.put(name, new CmsModuleVersion(ver));
470            }
471            try {
472                name = getXmlHelper().getValue(
473                    file,
474                    CmsStringUtil.substitute(basePath, "?", "" + i) + CmsModuleXmlHandler.N_NAME);
475            } catch (@SuppressWarnings("unused") CmsXmlException e) {
476                // ignore
477            }
478        }
479        return modules;
480    }
481
482    /**
483     * List of modules to be updated.<p>
484     *
485     * @return a list of module names
486     */
487    public List<String> getModulesToUpdate() {
488
489        if (m_modulesToUpdate == null) {
490            getUptodateModules();
491            m_components = new CmsIdentifiableObjectContainer<CmsSetupComponent>(true, true);
492            try {
493                addComponentsFromPath(m_webAppRfsPath + FOLDER_UPDATE);
494            } catch (CmsConfigurationException e) {
495                //
496            }
497        }
498        return m_modulesToUpdate;
499    }
500
501    /**
502     * Returns the update database thread.<p>
503     *
504     * @return the update database thread
505     */
506    public CmsUpdateDBThread getUpdateDBThread() {
507
508        return m_dbUpdateThread;
509    }
510
511    /**
512     * Returns the update Project.<p>
513     *
514     * @return the update Project
515     */
516    public String getUpdateProject() {
517
518        return m_updateProject;
519    }
520
521    /**
522     * Returns the update site.<p>
523     *
524     * @return the update site
525     */
526    public String getUpdateSite() {
527
528        return m_updateSite;
529    }
530
531    /**
532     * Returns the modules that does not need to be updated.<p>
533     *
534     * @return a list of module names
535     */
536    public List<String> getUptodateModules() {
537
538        if (m_uptodateModules == null) {
539            m_uptodateModules = new ArrayList<String>();
540            m_modulesToUpdate = new ArrayList<String>();
541            Map<String, CmsModuleVersion> installedModules = getInstalledModules();
542            Map<String, CmsModule> availableModules = getAvailableModules();
543            Iterator<Map.Entry<String, CmsModule>> itMods = availableModules.entrySet().iterator();
544            while (itMods.hasNext()) {
545                Map.Entry<String, CmsModule> entry = itMods.next();
546                String name = entry.getKey();
547                CmsModuleVersion instVer = installedModules.get(name);
548                CmsModuleVersion availVer = entry.getValue().getVersion();
549                boolean uptodate = (!UPDATE_ALL_MODULES) && ((instVer != null) && (instVer.compareTo(availVer) >= 0));
550                if (uptodate) {
551                    m_uptodateModules.add(name);
552                } else {
553                    m_modulesToUpdate.add(name);
554                }
555                if (LOG.isDebugEnabled()) {
556                    LOG.debug(
557                        name + " --- installed: " + instVer + " available: " + availVer + " --- uptodate: " + uptodate);
558                }
559            }
560        }
561        return m_uptodateModules;
562    }
563
564    /**
565     * Returns the workplace update thread.<p>
566     *
567     * @return the workplace update thread
568     */
569    public CmsUpdateThread getWorkplaceUpdateThread() {
570
571        return m_workplaceUpdateThread;
572    }
573
574    /**
575     * Gets the XML updater (lazily create it if it hasn't been created yet).
576     *
577     * @return the XML updater
578     */
579    public CmsXmlConfigUpdater getXmlConfigUpdater() {
580
581        if (m_configUpdater == null) {
582            m_configUpdater = new CmsXmlConfigUpdater(getXmlUpdateFolder(), getConfigFolder());
583        }
584        return m_configUpdater;
585    }
586
587    /**
588     * Gets the folder for XML update files.
589     *
590     * @return the folder for XML update files
591     */
592    public File getXmlUpdateFolder() {
593
594        return new File(new File(getWebAppRfsPath()), "WEB-INF/updatedata/xmlupdate");
595
596    }
597
598    /**
599     * @see org.opencms.setup.CmsSetupBean#htmlModules()
600     */
601    @Override
602    public String htmlModules() {
603
604        StringBuffer html = new StringBuffer(1024);
605        Set<String> uptodate = new HashSet<String>(getUptodateModules());
606        Iterator<String> itModules = sortModules(getAvailableModules().values()).iterator();
607        boolean hasModules = false;
608        for (int i = 0; itModules.hasNext(); i++) {
609            String moduleName = itModules.next();
610            CmsModule module = getAvailableModules().get(moduleName);
611            if (UPDATE_ALL_MODULES || !uptodate.contains(moduleName)) {
612                html.append(htmlModule(module, i));
613                hasModules = true;
614            } else {
615                html.append("<input type='hidden' name='availableModules' value='");
616                html.append(moduleName);
617                html.append("'>\n");
618            }
619        }
620        if (!hasModules) {
621            html.append("\t<tr>\n");
622            html.append("\t\t<td style='vertical-align: middle;'>\n");
623            html.append(Messages.get().getBundle().key(Messages.GUI_WARNING_ALL_MODULES_UPTODATE_0));
624            html.append("\t\t</td>\n");
625            html.append("\t</tr>\n");
626        }
627        return html.toString();
628    }
629
630    /**
631     * Creates a new instance of the setup Bean.<p>
632     *
633     * @param webAppRfsPath path to the OpenCms web application
634     * @param servletMapping the OpenCms servlet mapping
635     * @param defaultWebApplication the name of the default web application
636     */
637    @Override
638    public void init(String webAppRfsPath, String servletMapping, String defaultWebApplication) {
639
640        try {
641            super.init(webAppRfsPath, servletMapping, defaultWebApplication);
642            CmsUpdateInfo.INSTANCE.setAdeModuleVersion(getInstalledModules().get("org.opencms.ade.containerpage"));
643
644            if (m_workplaceUpdateThread != null) {
645                if (m_workplaceUpdateThread.isAlive()) {
646                    m_workplaceUpdateThread.kill();
647                }
648                m_workplaceUpdateThread = null;
649            }
650            if (m_dbUpdateThread != null) {
651                if (m_dbUpdateThread.isAlive()) {
652                    m_dbUpdateThread.kill();
653                }
654                m_dbUpdateThread = null;
655                m_newLoggingOffset = 0;
656                m_oldLoggingOffset = 0;
657            }
658        } catch (Exception e) {
659            e.printStackTrace();
660            throw new RuntimeException(e);
661        }
662    }
663
664    /**
665     * Returns the keep History parameter value.<p>
666     *
667     * @return the keep History parameter value
668     */
669    public boolean isKeepHistory() {
670
671        return m_keepHistory;
672    }
673
674    /**
675     * Returns <code>true</code> if a DB update is needed.<p>
676     *
677     * @return <code>true</code> if a DB update is needed
678     */
679    public boolean isNeedDbUpdate() {
680
681        return m_detectedVersion != 8;
682    }
683
684    /**
685     * Checks whether the selected user and password are valid and the user has the ROOT_ADMIN role.<p>
686     *
687     * @return <code>true</code> if the selected user and password are valid and the user has the ROOT_ADMIN role
688     */
689    public boolean isValidUser() {
690
691        CmsShell shell = new CmsShell(
692            getWebAppRfsPath() + "WEB-INF" + File.separator,
693            getServletMapping(),
694            getDefaultWebApplication(),
695            "${user}@${project}>",
696            Collections.emptyList());
697        boolean validUser = shell.validateUser(getAdminUser(), getAdminPwd(), CmsRole.ROOT_ADMIN);
698        shell.exit();
699        return validUser;
700    }
701
702    /**
703     * Prepares step 1 of the update wizard.<p>
704     */
705    public void prepareUpdateStep1() {
706
707        // the MySQL driver class name has changed with OpenCms 11.0.0
708        // it needs to be updated before any database access
709        //updateDBDriverClassName();
710    }
711
712    /**
713     * Prepares step 1 of the update wizard.<p>
714     */
715    public void prepareUpdateStep1b() {
716
717        if (!isInitialized()) {
718            return;
719        }
720
721        if ((m_dbUpdateThread != null) && (m_dbUpdateThread.isFinished())) {
722            // update is already finished, just wait for client to collect final data
723            return;
724        }
725
726        if (m_dbUpdateThread == null) {
727            m_dbUpdateThread = new CmsUpdateDBThread(this);
728        }
729
730        if (!m_dbUpdateThread.isAlive()) {
731            m_dbUpdateThread.start();
732        }
733    }
734
735    /**
736     * Generates the output for step 1 of the setup wizard.<p>
737     *
738     * @param out the JSP print stream
739     * @throws IOException in case errors occur while writing to "out"
740     */
741    public void prepareUpdateStep1bOutput(JspWriter out) throws IOException {
742
743        m_oldLoggingDBOffset = m_newLoggingDBOffset;
744        m_newLoggingDBOffset = m_dbUpdateThread.getLoggingThread().getMessages().size();
745        if (isInitialized()) {
746            for (int i = m_oldLoggingDBOffset; i < m_newLoggingDBOffset; i++) {
747                String str = m_dbUpdateThread.getLoggingThread().getMessages().get(i).toString();
748                str = CmsEncoder.escapeWBlanks(str, CmsEncoder.ENCODING_UTF_8);
749                out.println("output[" + (i - m_oldLoggingDBOffset) + "] = \"" + str + "\";");
750            }
751        } else {
752            out.println("output[0] = 'ERROR';");
753        }
754
755        boolean threadFinished = m_dbUpdateThread.isFinished();
756        boolean allWritten = m_oldLoggingDBOffset >= m_dbUpdateThread.getLoggingThread().getMessages().size();
757
758        out.println("function initThread() {");
759        if (isInitialized()) {
760            out.print("send();");
761            if (threadFinished && allWritten) {
762                out.println("setTimeout('top.display.finish()', 1000);");
763            } else {
764                int timeout = 5000;
765                if (getUpdateDBThread().getLoggingThread().getMessages().size() < 20) {
766                    timeout = 2000;
767                }
768                out.println("setTimeout('location.reload()', " + timeout + ");");
769            }
770        }
771        out.println("}");
772    }
773
774    /**
775     * Prepares step 5 of the update wizard.<p>
776     */
777    public void prepareUpdateStep5() {
778
779        if (isInitialized()) {
780            try {
781                String fileName = getWebAppRfsPath() + FOLDER_UPDATE + "cmsupdate";
782                // read the file
783                FileInputStream fis = new FileInputStream(fileName + CmsConfigurationManager.POSTFIX_ORI);
784                String script = "";
785                int readChar = fis.read();
786                while (readChar > -1) {
787                    script += (char)readChar;
788                    readChar = fis.read();
789                }
790                fis.close();
791                // substitute macros
792                script = CmsStringUtil.substitute(script, C_ADMIN_USER, getAdminUser());
793                script = CmsStringUtil.substitute(script, C_ADMIN_PWD, getAdminPwd());
794                script = CmsStringUtil.substitute(script, C_UPDATE_PROJECT, getUpdateProject());
795                script = CmsStringUtil.substitute(script, C_UPDATE_SITE, getUpdateSite());
796                script = CmsStringUtil.substitute(script, C_ADMIN_GROUP, getAdminGroup());
797                // write the new script
798                FileOutputStream fos = new FileOutputStream(fileName + ".txt");
799                fos.write(script.getBytes());
800                fos.close();
801            } catch (IOException e) {
802                e.printStackTrace();
803                throw new RuntimeException(e);
804            }
805        }
806    }
807
808    /**
809     * Prepares step 5 of the update wizard.<p>
810     */
811    public void prepareUpdateStep5b() {
812
813        if (!isInitialized()) {
814            return;
815        }
816
817        addSubscriptionDriver();
818
819        if ((m_workplaceUpdateThread != null) && (m_workplaceUpdateThread.isFinished())) {
820            // update is already finished, just wait for client to collect final data
821            return;
822        }
823
824        if (m_workplaceUpdateThread == null) {
825            m_workplaceUpdateThread = new CmsUpdateThread(this);
826        }
827
828        if (!m_workplaceUpdateThread.isAlive()) {
829            m_workplaceUpdateThread.start();
830        }
831    }
832
833    /**
834     * Generates the output for the update wizard.<p>
835     *
836     * @param out the JSP print stream
837     *
838     * @throws IOException in case errors occur while writing to "out"
839     */
840    public void prepareUpdateStep5bOutput(JspWriter out) throws IOException {
841
842        if ((m_workplaceUpdateThread == null) || (m_workplaceUpdateThread.getLoggingThread() == null)) {
843            return;
844        }
845        m_oldLoggingOffset = m_newLoggingOffset;
846        m_newLoggingOffset = m_workplaceUpdateThread.getLoggingThread().getMessages().size();
847        if (isInitialized()) {
848            for (int i = m_oldLoggingOffset; i < m_newLoggingOffset; i++) {
849                String str = m_workplaceUpdateThread.getLoggingThread().getMessages().get(i).toString();
850                str = CmsEncoder.escapeWBlanks(str, CmsEncoder.ENCODING_UTF_8);
851                out.println("output[" + (i - m_oldLoggingOffset) + "] = \"" + str + "\";");
852            }
853        } else {
854            out.println("output[0] = 'ERROR';");
855        }
856
857        boolean threadFinished = m_workplaceUpdateThread.isFinished();
858        boolean allWritten = m_oldLoggingOffset >= m_workplaceUpdateThread.getLoggingThread().getMessages().size();
859
860        out.println("function initThread() {");
861        if (isInitialized()) {
862            out.print("send();");
863            if (threadFinished && allWritten) {
864                out.println("setTimeout('top.display.finish()', 500);");
865            } else {
866                int timeout = 5000;
867                if (getWorkplaceUpdateThread().getLoggingThread().getMessages().size() < 20) {
868                    timeout = 1000;
869                }
870                out.println("setTimeout('location.reload()', " + timeout + ");");
871            }
872        }
873        out.println("}");
874    }
875
876    /**
877     * Prepares step 6 of the update wizard.<p>
878     */
879    public void prepareUpdateStep6() {
880
881        Set<String> forced = new HashSet<String>();
882        forced.add("driver.subscription");
883        forced.add("db.subscription.driver");
884        forced.add("db.subscription.pool");
885        forced.add("db.subscription.sqlmanager");
886        addSubscriptionDriver();
887        if (isInitialized()) {
888            // lock the wizard for further use
889            lockWizard();
890            // save Properties to file "opencms.properties"
891            saveProperties(getProperties(), CmsSystemInfo.FILE_PROPERTIES, false, forced);
892            deleteEmptyJars();
893        }
894    }
895
896    /**
897     * Sets the admin Pwd.<p>
898     *
899     * @param adminPwd the admin Pwd to set
900     */
901    public void setAdminPwd(String adminPwd) {
902
903        m_adminPwd = adminPwd;
904    }
905
906    /**
907     * Sets the admin User.<p>
908     *
909     * @param adminUser the admin User to set
910     */
911    public void setAdminUser(String adminUser) {
912
913        m_adminUser = adminUser;
914    }
915
916    /**
917     * Sets the detected mayor version.<p>
918     *
919     * @param detectedVersion the value to set
920     */
921    public void setDetectedVersion(double detectedVersion) {
922
923        m_detectedVersion = detectedVersion;
924    }
925
926    /**
927     * Sets the keep History parameter value.<p>
928     *
929     * @param keepHistory the keep History parameter value to set
930     */
931    public void setKeepHistory(boolean keepHistory) {
932
933        m_keepHistory = keepHistory;
934    }
935
936    /**
937     * Sets the list of modules where the included libs should be preserved during update.<p>
938     * Called from step_5_update_modules.jsp.<p>
939     *
940     * @param preserveLibModules the comma separated list of module names
941     */
942    public void setPreserveLibModules(String preserveLibModules) {
943
944        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(preserveLibModules)) {
945            String[] modules = preserveLibModules.split(",");
946            m_preserveLibModules = Arrays.asList(modules);
947        } else {
948            m_preserveLibModules = Collections.emptyList();
949        }
950    }
951
952    /**
953     * Sets the update Project.<p>
954     *
955     * @param updateProject the update Project to set
956     */
957    public void setUpdateProject(String updateProject) {
958
959        m_updateProject = updateProject;
960    }
961
962    /**
963     * Sets the update site.<p>
964     *
965     * @param site the update site to set
966     */
967    public void setUpdateSite(String site) {
968
969        m_updateSite = site;
970    }
971
972    /**
973     * @see org.opencms.main.I_CmsShellCommands#shellExit()
974     */
975    @Override
976    public void shellExit() {
977
978        System.out.println();
979        System.out.println();
980        System.out.println("The update is finished!\nThe OpenCms system used for the update will now shut down.");
981    }
982
983    /**
984     * @see org.opencms.main.I_CmsShellCommands#shellStart()
985     */
986    @Override
987    public void shellStart() {
988
989        System.out.println();
990        System.out.println("Starting Workplace update for OpenCms!");
991
992        String[] copy = org.opencms.main.Messages.COPYRIGHT_BY_ALKACON;
993        for (int i = copy.length - 1; i >= 0; i--) {
994            System.out.println(copy[i]);
995        }
996        System.out.println(
997            "This is OpenCms "
998                + OpenCms.getSystemInfo().getVersionNumber()
999                + " ["
1000                + OpenCms.getSystemInfo().getVersionId()
1001                + "]");
1002        System.out.println();
1003        System.out.println();
1004    }
1005
1006    /**
1007     * Updates the JDBC driver class names.<p>
1008     * Needs to be executed before any database access.<p>
1009     */
1010    public void updateDBDriverProperties() {
1011
1012        Map<String, String> modifiedElements = new HashMap<String, String>();
1013        // replace MySQL JDBC driver class name
1014        CmsParameterConfiguration properties = getProperties();
1015        for (Entry<String, String> propertyEntry : properties.entrySet()) {
1016            if (MYSQL_DRIVER_CLASS_OLD.equals(propertyEntry.getValue())
1017                || MYSQL_DRIVER_CLASS_NEW.equals(propertyEntry.getValue())) {
1018                modifiedElements.put(propertyEntry.getKey(), MYSQL_DRIVER_CLASS_MARIADB);
1019            }
1020        }
1021
1022        if (properties.containsValue(MYSQL_DRIVER_CLASS_MARIADB)
1023            || properties.containsValue(MYSQL_DRIVER_CLASS_NEW)
1024            || properties.containsValue(MYSQL_DRIVER_CLASS_OLD)) {
1025            for (Entry<String, String> propertyEntry : properties.entrySet()) {
1026                if (MYSQL_DRIVER_CLASS_OLD.equals(propertyEntry.getValue())
1027                    || MYSQL_DRIVER_CLASS_NEW.equals(propertyEntry.getValue())
1028                    || MYSQL_DRIVER_CLASS_MARIADB.equals(propertyEntry.getValue())) {
1029
1030                    String mysqlkey = propertyEntry.getKey().substring(0, propertyEntry.getKey().lastIndexOf("."));
1031                    String parameterKey = mysqlkey + ".jdbcUrl.params";
1032                    String currentParameter = properties.get(parameterKey);
1033                    String modifiedParameter = currentParameter;
1034                    if (modifiedParameter == null) {
1035                        modifiedParameter = "";
1036                    }
1037                    if (!modifiedParameter.contains("serverTimezone")) {
1038                        String parameterSeperator = "?";
1039                        if (modifiedParameter.contains("?")) {
1040                            parameterSeperator = "&";
1041                        }
1042                        modifiedParameter = currentParameter + parameterSeperator + "serverTimezone=UTC";
1043                    }
1044                    if (modifiedParameter.contains("useSSL=false")
1045                        && !modifiedParameter.contains("allowPublicKeyRetrieval")) {
1046                        modifiedParameter = currentParameter + "&" + "allowPublicKeyRetrieval=true";
1047                    }
1048                    if (!Objects.equal(modifiedParameter, currentParameter)) {
1049                        modifiedElements.put(parameterKey, modifiedParameter);
1050                    }
1051                    parameterKey = mysqlkey + ".jdbcUrl";
1052                    currentParameter = properties.get(parameterKey);
1053                    if ((currentParameter != null) && currentParameter.startsWith("jdbc:mysql:")) {
1054                        modifiedParameter = "jdbc:mariadb:" + currentParameter.substring(11);
1055                        modifiedElements.put(parameterKey, modifiedParameter);
1056                    }
1057                }
1058            }
1059        }
1060
1061        for (String key : modifiedElements.keySet()) {
1062            properties.put(key, modifiedElements.get(key));
1063        }
1064
1065        if (!modifiedElements.isEmpty()) {
1066            saveProperties(properties, CmsSystemInfo.FILE_PROPERTIES, false, modifiedElements.keySet());
1067        }
1068    }
1069
1070    /**
1071     * Installed all modules that have been set using {@link #setInstallModules(String)}.<p>
1072     *
1073     * This method is invoked as a shell command.<p>
1074     *
1075     * @throws Exception if something goes wrong
1076     */
1077    public void updateModulesFromUpdateBean() throws Exception {
1078
1079        // read here how the list of modules to be installed is passed from the setup bean to the
1080        // setup thread, and finally to the shell process that executes the setup script:
1081        // 1) the list with the package names of the modules to be installed is saved by setInstallModules
1082        // 2) the setup thread gets initialized in a JSP of the setup wizard
1083        // 3) the instance of the setup bean is passed to the setup thread by setAdditionalShellCommand
1084        // 4) the setup bean is passed to the shell by startSetup
1085        // 5) because the setup bean implements I_CmsShellCommands, the shell constructor can pass the shell's CmsObject back to the setup bean
1086        // 6) thus, the setup bean can do things with the Cms
1087
1088        if (m_cms != null) {
1089
1090            I_CmsReport report = new CmsShellReport(m_cms.getRequestContext().getLocale());
1091
1092            // remove obsolete modules in any case
1093            for (String moduleToRemove : getModulesToDelete()) {
1094                removeModule(moduleToRemove, report);
1095            }
1096
1097            // check if there are any modules to install
1098            if (m_installModules != null) {
1099                Set<String> utdModules = new HashSet<String>(getUptodateModules());
1100                List<String> installList = Lists.newArrayList(m_installModules);
1101                for (String name : installList) {
1102                    if (!utdModules.contains(name)) {
1103                        String filename = m_moduleFilenames.get(name);
1104                        try {
1105                            updateModule(name, filename, report);
1106                        } catch (Exception e) {
1107                            // log a exception during module import, but make sure the next module is still imported
1108                            e.printStackTrace(System.err);
1109                        }
1110                    } else {
1111                        report.println(
1112                            Messages.get().container(Messages.RPT_MODULE_UPTODATE_1, name),
1113                            I_CmsReport.FORMAT_HEADLINE);
1114                    }
1115                }
1116            }
1117        }
1118    }
1119
1120    /**
1121     * Fills the relations db tables during the update.<p>
1122     *
1123     * @throws Exception if something goes wrong
1124     */
1125    public void updateRelations() throws Exception {
1126
1127        if (m_detectedVersion > 6) {
1128            // skip if not updating from 6.x
1129            return;
1130        }
1131        I_CmsReport report = new CmsShellReport(m_cms.getRequestContext().getLocale());
1132
1133        report.println(Messages.get().container(Messages.RPT_START_UPDATE_RELATIONS_0), I_CmsReport.FORMAT_HEADLINE);
1134
1135        String storedSite = m_cms.getRequestContext().getSiteRoot();
1136        CmsProject project = null;
1137        try {
1138            String projectName = "Update relations project";
1139            try {
1140                // try to read a (leftover) unlock project
1141                project = m_cms.readProject(projectName);
1142            } catch (@SuppressWarnings("unused") CmsException e) {
1143                // create a Project to unlock the resources
1144                project = m_cms.createProject(
1145                    projectName,
1146                    projectName,
1147                    OpenCms.getDefaultUsers().getGroupAdministrators(),
1148                    OpenCms.getDefaultUsers().getGroupAdministrators(),
1149                    CmsProject.PROJECT_TYPE_TEMPORARY);
1150            }
1151
1152            m_cms.getRequestContext().setSiteRoot(""); // change to the root site
1153            m_cms.getRequestContext().setCurrentProject(project);
1154
1155            List<I_CmsResourceType> types = OpenCms.getResourceManager().getResourceTypes();
1156            int n = types.size();
1157            int m = 0;
1158            Iterator<I_CmsResourceType> itTypes = types.iterator();
1159            while (itTypes.hasNext()) {
1160                I_CmsResourceType type = itTypes.next();
1161                m++;
1162                report.print(
1163                    org.opencms.report.Messages.get().container(
1164                        org.opencms.report.Messages.RPT_SUCCESSION_2,
1165                        String.valueOf(m),
1166                        String.valueOf(n)),
1167                    I_CmsReport.FORMAT_NOTE);
1168                report.print(
1169                    org.opencms.report.Messages.get().container(
1170                        org.opencms.report.Messages.RPT_ARGUMENT_1,
1171                        type.getTypeName()));
1172                report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0));
1173
1174                if (type instanceof I_CmsLinkParseable) {
1175                    try {
1176                        CmsXmlContentRepairSettings settings = new CmsXmlContentRepairSettings(m_cms);
1177                        settings.setIncludeSubFolders(true);
1178                        settings.setVfsFolder("/");
1179                        settings.setForce(true);
1180                        settings.setResourceType(type.getTypeName());
1181
1182                        CmsXmlContentRepairThread t = new CmsXmlContentRepairThread(m_cms, settings);
1183                        t.start();
1184
1185                        synchronized (this) {
1186                            t.join();
1187                        }
1188                        report.println(
1189                            org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
1190                            I_CmsReport.FORMAT_OK);
1191                    } catch (Exception e) {
1192                        report.println(
1193                            org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_ERROR_0),
1194                            I_CmsReport.FORMAT_ERROR);
1195                        report.addError(e);
1196                        // log the error
1197                        e.printStackTrace(System.err);
1198                    }
1199                } else {
1200                    report.println(
1201                        org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_SKIPPED_0),
1202                        I_CmsReport.FORMAT_WARNING);
1203                }
1204            }
1205        } finally {
1206            try {
1207                if (project != null) {
1208                    try {
1209                        m_cms.unlockProject(project.getUuid()); // unlock everything
1210                        OpenCms.getPublishManager().publishProject(
1211                            m_cms,
1212                            report,
1213                            OpenCms.getPublishManager().getPublishList(m_cms));
1214                        OpenCms.getPublishManager().waitWhileRunning();
1215                    } finally {
1216                        m_cms.getRequestContext().setCurrentProject(m_cms.readProject(CmsProject.ONLINE_PROJECT_ID));
1217                    }
1218                }
1219            } finally {
1220                m_cms.getRequestContext().setSiteRoot(storedSite);
1221            }
1222            report.println(
1223                Messages.get().container(Messages.RPT_FINISH_UPDATE_RELATIONS_0),
1224                I_CmsReport.FORMAT_HEADLINE);
1225        }
1226    }
1227
1228    /**
1229     * Returns the admin Group.<p>
1230     *
1231     * @return the admin Group
1232     */
1233    protected String getAdminGroup() {
1234
1235        return m_adminGroup;
1236    }
1237
1238    /**
1239     * Computes a list of modules which need to be removed before updating the other modules, e.g. because of resource type
1240     * conflicts.<p>
1241     *
1242     * @return the list of names of modules which need to be removed
1243     */
1244    protected List<String> getModulesToDelete() {
1245
1246        List<String> result = new ArrayList<String>();
1247        for (int i = 0; i < OBSOLETE_MODULES.length; i++) {
1248            if (OpenCms.getModuleManager().hasModule(OBSOLETE_MODULES[i])) {
1249                result.add(OBSOLETE_MODULES[i]);
1250            }
1251        }
1252        return result;
1253    }
1254
1255    /**
1256     * Removes a module.<p>
1257     *
1258     * @param moduleName the name of the module to remove
1259     * @param report the report to write to
1260     *
1261     * @throws CmsException in case something goes wrong
1262     */
1263    protected void removeModule(String moduleName, I_CmsReport report) throws CmsException {
1264
1265        if (OpenCms.getModuleManager().getModule(moduleName) != null) {
1266            OpenCms.getModuleManager().deleteModule(
1267                m_cms,
1268                moduleName,
1269                true,
1270                m_preserveLibModules.contains(moduleName),
1271                report);
1272        }
1273    }
1274
1275    /**
1276     * Sets the admin Group.<p>
1277     *
1278     * @param adminGroup the admin Group to set
1279     */
1280    protected void setAdminGroup(String adminGroup) {
1281
1282        m_adminGroup = adminGroup;
1283    }
1284
1285    /**
1286     * Imports a module (zipfile) from the default module directory,
1287     * creating a temporary project for this.<p>
1288     *
1289     * @param moduleName the name of the module to replace
1290     * @param importFile the name of the import .zip file located in the update module directory
1291     * @param report the shell report to write the output
1292     *
1293     * @throws Exception if something goes wrong
1294     *
1295     * @see org.opencms.importexport.CmsImportExportManager#importData(org.opencms.file.CmsObject, I_CmsReport, org.opencms.importexport.CmsImportParameters)
1296     */
1297    protected void updateModule(String moduleName, String importFile, I_CmsReport report) throws Exception {
1298
1299        String fileName = getModuleFolder() + importFile;
1300
1301        report.println(
1302            Messages.get().container(Messages.RPT_BEGIN_UPDATE_MODULE_1, moduleName),
1303            I_CmsReport.FORMAT_HEADLINE);
1304        removeModule(moduleName, report);
1305        OpenCms.getPublishManager().stopPublishing();
1306        OpenCms.getPublishManager().startPublishing();
1307        OpenCms.getPublishManager().waitWhileRunning();
1308        OpenCms.getImportExportManager().importData(m_cms, report, new CmsImportParameters(fileName, "/", true));
1309        report.println(
1310            Messages.get().container(Messages.RPT_END_UPDATE_MODULE_1, moduleName),
1311            I_CmsReport.FORMAT_HEADLINE);
1312        OpenCms.getPublishManager().stopPublishing();
1313        OpenCms.getPublishManager().startPublishing();
1314        OpenCms.getPublishManager().waitWhileRunning();
1315    }
1316
1317    /**
1318     * Marks all empty jars for deletion on VM exit.<p>
1319     */
1320    private void deleteEmptyJars() {
1321
1322        File libFolder = new File(getLibFolder());
1323        if (libFolder.exists()) {
1324            File[] emptyJars = libFolder.listFiles(new FileFilter() {
1325
1326                public boolean accept(File pathname) {
1327
1328                    if (pathname.getName().endsWith(".jar")) {
1329                        FileInputStream fileInput = null;
1330                        JarInputStream jarStream = null;
1331                        try {
1332                            fileInput = new FileInputStream(pathname);
1333                            jarStream = new JarInputStream(fileInput);
1334                            // check the manifest for the empty jar marker attribute
1335                            Manifest mf = jarStream.getManifest();
1336                            Attributes att = mf.getMainAttributes();
1337                            if ((att != null) && "true".equals(att.getValue(EMPTY_JAR_ATTRIBUTE_KEY))) {
1338                                return true;
1339                            }
1340                        } catch (Exception e) {
1341                            LOG.warn(e.getMessage(), e);
1342                        } finally {
1343                            if (jarStream != null) {
1344                                try {
1345                                    jarStream.close();
1346                                } catch (IOException e) {
1347                                    LOG.warn(e.getMessage(), e);
1348                                }
1349                            }
1350                            if (fileInput != null) {
1351                                try {
1352                                    fileInput.close();
1353                                } catch (IOException e) {
1354                                    LOG.warn(e.getMessage(), e);
1355                                }
1356                            }
1357                        }
1358                    }
1359                    return false;
1360                }
1361            });
1362            for (int i = 0; i < emptyJars.length; i++) {
1363                emptyJars[i].deleteOnExit();
1364            }
1365        }
1366    }
1367
1368    /**
1369     * Gets the database package name part.<p>
1370     *
1371     * @param dbName the db name from the opencms.properties file
1372     *
1373     * @return the db package name part
1374     */
1375    private String getDbPackage(String dbName) {
1376
1377        if (dbName.contains("mysql")) {
1378            return "mysql";
1379        } else if (dbName.contains("oracle")) {
1380            return "oracle";
1381        } else {
1382            return dbName;
1383        }
1384    }
1385}