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.CmsImportExportConfiguration;
033import org.opencms.configuration.CmsModuleConfiguration;
034import org.opencms.configuration.CmsParameterConfiguration;
035import org.opencms.configuration.CmsSearchConfiguration;
036import org.opencms.configuration.CmsSitesConfiguration;
037import org.opencms.configuration.CmsSystemConfiguration;
038import org.opencms.configuration.CmsVfsConfiguration;
039import org.opencms.configuration.CmsWorkplaceConfiguration;
040import org.opencms.configuration.I_CmsXmlConfiguration;
041import org.opencms.db.CmsDbPoolV11;
042import org.opencms.db.CmsUserSettings;
043import org.opencms.file.CmsObject;
044import org.opencms.file.CmsResource;
045import org.opencms.file.CmsUser;
046import org.opencms.i18n.CmsEncoder;
047import org.opencms.i18n.CmsMessageContainer;
048import org.opencms.importexport.CmsImportParameters;
049import org.opencms.loader.CmsImageLoader;
050import org.opencms.main.CmsException;
051import org.opencms.main.CmsLog;
052import org.opencms.main.CmsRuntimeException;
053import org.opencms.main.CmsShell;
054import org.opencms.main.CmsSystemInfo;
055import org.opencms.main.I_CmsEventListener;
056import org.opencms.main.I_CmsShellCommands;
057import org.opencms.main.OpenCms;
058import org.opencms.main.OpenCmsServlet;
059import org.opencms.module.CmsModule;
060import org.opencms.module.CmsModuleManager;
061import org.opencms.report.CmsShellReport;
062import org.opencms.setup.comptest.CmsSetupTestResult;
063import org.opencms.setup.comptest.CmsSetupTestSimapi;
064import org.opencms.setup.comptest.I_CmsSetupTest;
065import org.opencms.setup.xml.CmsSetupXmlHelper;
066import org.opencms.util.CmsCollectionsGenericWrapper;
067import org.opencms.util.CmsFileUtil;
068import org.opencms.util.CmsStringUtil;
069import org.opencms.workplace.tools.CmsIdentifiableObjectContainer;
070
071import java.io.File;
072import java.io.FileInputStream;
073import java.io.FileNotFoundException;
074import java.io.FileReader;
075import java.io.FileWriter;
076import java.io.IOException;
077import java.io.InputStream;
078import java.io.LineNumberReader;
079import java.util.ArrayList;
080import java.util.Collection;
081import java.util.Collections;
082import java.util.Comparator;
083import java.util.HashMap;
084import java.util.HashSet;
085import java.util.Iterator;
086import java.util.List;
087import java.util.Map;
088import java.util.Properties;
089import java.util.Set;
090import java.util.SortedMap;
091import java.util.TreeMap;
092import java.util.zip.ZipEntry;
093import java.util.zip.ZipFile;
094
095import javax.servlet.ServletConfig;
096import javax.servlet.ServletContext;
097import javax.servlet.http.HttpServletRequest;
098import javax.servlet.http.HttpSession;
099import javax.servlet.jsp.JspWriter;
100import javax.servlet.jsp.PageContext;
101
102import org.apache.commons.logging.Log;
103
104import com.google.common.collect.Maps;
105
106/**
107 * A java bean as a controller for the OpenCms setup wizard.<p>
108 *
109 * It is not allowed to customize this bean with methods for a specific database server setup!<p>
110 *
111 * Database server specific settings should be set/read using get/setDbProperty, as for example like:
112 *
113 * <pre>
114 * setDbProperty("oracle.defaultTablespace", value);
115 * </pre>
116 * <p>
117 *
118 * @since 6.0.0
119 */
120public class CmsSetupBean implements I_CmsShellCommands {
121
122    /** Prefix for 'marker' properties in opencms.properties where additional properties should be inserted. */
123    public static final String ADDITIONAL_PREFIX = "additional.";
124
125    /** DB provider constant for as400. */
126    public static final String AS400_PROVIDER = "as400";
127
128    /** The name of the components properties file. */
129    public static final String COMPONENTS_PROPERTIES = "components.properties";
130
131    /** DB provider constant for db2. */
132    public static final String DB2_PROVIDER = "db2";
133
134    /** Folder constant name.<p> */
135    public static final String FOLDER_BACKUP = "backup" + File.separatorChar;
136
137    /** Folder constant name.<p> */
138    public static final String FOLDER_DATABASE = "database" + File.separatorChar;
139
140    /** Folder constant name.<p> */
141    public static final String FOLDER_LIB = "lib" + File.separatorChar;
142
143    /** Folder constant name.<p> */
144    public static final String FOLDER_SETUP = "WEB-INF/setupdata" + File.separatorChar;
145
146    /** DB provider constant. */
147    public static final String GENERIC_PROVIDER = "generic";
148
149    /** DB provider constant for hsqldb. */
150    public static final String HSQLDB_PROVIDER = "hsqldb";
151
152    /** Name of the property file containing HTML fragments for setup wizard and error dialog. */
153    public static final String HTML_MESSAGE_FILE = "org/opencms/setup/htmlmsg.properties";
154
155    /** DB provider constant for maxdb. */
156    public static final String MAXDB_PROVIDER = "maxdb";
157
158    /** DB provider constant for mssql. */
159    public static final String MSSQL_PROVIDER = "mssql";
160
161    /** DB provider constant for mysql. */
162    public static final String MYSQL_PROVIDER = "mysql";
163
164    /** DB provider constant for oracle. */
165    public static final String ORACLE_PROVIDER = "oracle";
166
167    /** DB provider constant for postgresql. */
168    public static final String POSTGRESQL_PROVIDER = "postgresql";
169
170    /** The default component position, is missing. */
171    protected static final int DEFAULT_POSITION = 9999;
172
173    /** Properties file key constant post fix. */
174    protected static final String PROPKEY_CHECKED = ".checked";
175
176    /** Properties file key constant prefix. */
177    protected static final String PROPKEY_COMPONENT = "component.";
178
179    /** Properties file key constant. */
180    protected static final String PROPKEY_COMPONENTS = "components";
181
182    /** Properties file key constant post fix. */
183    protected static final String PROPKEY_DEPENDENCIES = ".dependencies";
184
185    /** Properties file key constant post fix. */
186    protected static final String PROPKEY_DESCRIPTION = ".description";
187
188    /** Properties file key constant post fix. */
189    protected static final String PROPKEY_MODULES = ".modules";
190
191    /** Properties file key constant post fix. */
192    protected static final String PROPKEY_NAME = ".name";
193
194    /** Properties file key constant post fix. */
195    protected static final String PROPKEY_POSITION = ".position";
196
197    /** The log object for this class. */
198    private static final Log LOG = CmsLog.getLog(CmsSetupBean.class);
199
200    /** Contains HTML fragments for the output in the JSP pages of the setup wizard. */
201    private static Properties m_htmlProps;
202
203    /** Required files per database setup (for sql supported dbs). */
204    private static final String[] REQUIRED_SQL_DB_SETUP_FILES = {"database.properties"};
205
206    /** A map with all available modules. */
207    protected Map<String, CmsModule> m_availableModules;
208
209    /** A CmsObject to execute shell commands. */
210    protected CmsObject m_cms;
211
212    /** Contains all defined components. */
213    protected CmsIdentifiableObjectContainer<CmsSetupComponent> m_components;
214
215    /** A list with the package names of the modules to be installed .*/
216    protected List<String> m_installModules;
217
218    /** Location for log file.  */
219    protected String m_logFile = OpenCms.getSystemInfo().getLogFileRfsFolder() + "setup.log";
220
221    /** A map with lists of dependent module package names keyed by module package names. */
222    protected Map<String, List<String>> m_moduleDependencies;
223
224    /** A map with all available modules filenames. */
225    protected Map<String, String> m_moduleFilenames;
226
227    /** Location for module archives relative to the webapp folder.  */
228    protected String m_modulesFolder = CmsSystemInfo.FOLDER_WEBINF
229        + CmsSystemInfo.FOLDER_PACKAGES
230        + CmsSystemInfo.FOLDER_MODULES;
231
232    /** The new logging offset in the workplace import thread. */
233    protected int m_newLoggingOffset;
234
235    /** The lod logging offset in the workplace import thread. */
236    protected int m_oldLoggingOffset;
237
238    /** The absolute path to the home directory of the OpenCms webapp. */
239    protected String m_webAppRfsPath;
240
241    /** Additional property sets to be inserted into opencms.properties during setup. */
242    private Map<String, String> m_additionalProperties = Maps.newHashMap();
243
244    /** Signals whether the setup is executed in the auto mode or in the wizard mode. */
245    private boolean m_autoMode;
246
247    /** The absolute path to the config sub directory of the OpenCms web application. */
248    private String m_configRfsPath;
249
250    /** Contains the properties of "opencms.properties". */
251    private CmsParameterConfiguration m_configuration;
252
253    private String m_contextPath;
254
255    /** Key of the selected database server (e.g. "mysql", "generic" or "oracle") */
256    private String m_databaseKey;
257
258    /** List of keys of all available database server setups (e.g. "mysql", "generic" or "oracle") */
259    private List<String> m_databaseKeys;
260
261    /** Map of database setup properties of all available database server setups keyed by their database keys. */
262    private Map<String, Properties> m_databaseProperties;
263
264    /** Password used for the JDBC connection when the OpenCms database is created. */
265    private String m_dbCreatePwd;
266
267    /** The name of the default web application (in web.xml). */
268    private String m_defaultWebApplication;
269
270    /** Contains the error messages to be displayed in the setup wizard. */
271    private List<String> m_errors;
272
273    /** The ethernet address. */
274    private String m_ethernetAddress;
275
276    /** The full key of the selected database including the "_jpa" or "_sql" information. */
277    private String m_fullDatabaseKey;
278
279    /** Flag which is set to true after module import if there is an index.html file in the default site. */
280    private boolean m_hasIndexHtml;
281
282    /** The Database Provider used in setup. */
283    private String m_provider;
284
285    /** A map with tokens ${...} to be replaced in SQL scripts. */
286    private Map<String, String> m_replacer;
287
288    /** The initial servlet configuration. */
289    private ServletConfig m_servletConfig;
290
291    /** The servlet mapping (in web.xml). */
292    private String m_servletMapping;
293
294    private CmsShell m_shell;
295
296    /** List of sorted keys by ranking of all available database server setups (e.g. "mysql", "generic" or "oracle") */
297    private List<String> m_sortedDatabaseKeys;
298
299    /** The workplace import thread. */
300    private CmsSetupWorkplaceImportThread m_workplaceImportThread;
301
302    /** Xml read/write helper object. */
303    private CmsSetupXmlHelper m_xmlHelper;
304
305    /**
306     * Default constructor.<p>
307     */
308    public CmsSetupBean() {
309
310        initHtmlParts();
311    }
312
313    /**
314     * Restores the opencms.xml either to or from a backup file, depending
315     * whether the setup wizard is executed the first time (the backup
316     * does not exist) or not (the backup exists).
317     *
318     * @param filename something like e.g. "opencms.xml"
319     * @param originalFilename the configurations real file name, e.g. "opencms.xml.ori"
320     */
321    public void backupConfiguration(String filename, String originalFilename) {
322
323        // ensure backup folder exists
324        File backupFolder = new File(m_configRfsPath + FOLDER_BACKUP);
325        if (!backupFolder.exists()) {
326            backupFolder.mkdirs();
327        }
328
329        // copy file to (or from) backup folder
330        originalFilename = FOLDER_BACKUP + originalFilename;
331        File file = new File(m_configRfsPath + originalFilename);
332        if (file.exists()) {
333            copyFile(originalFilename, filename);
334        } else {
335            copyFile(filename, originalFilename);
336        }
337    }
338
339    /**
340     * Returns a map of dependencies.<p>
341     *
342     * The component dependencies are get from the setup and module components.properties files found.<p>
343     *
344     * @return a Map of component ids as keys and a list of dependency names as values
345     */
346    public Map<String, List<String>> buildDepsForAllComponents() {
347
348        Map<String, List<String>> ret = new HashMap<String, List<String>>();
349
350        Iterator<CmsSetupComponent> itComponents = CmsCollectionsGenericWrapper.<CmsSetupComponent> list(
351            m_components.elementList()).iterator();
352        while (itComponents.hasNext()) {
353            CmsSetupComponent component = itComponents.next();
354
355            // if component a depends on component b, and component c depends also on component b:
356            // build a map with a list containing "a" and "c" keyed by "b" to get a
357            // list of components depending on component "b"...
358            Iterator<String> itDeps = component.getDependencies().iterator();
359            while (itDeps.hasNext()) {
360                String dependency = itDeps.next();
361
362                // get the list of dependent modules
363                List<String> componentDependencies = ret.get(dependency);
364                if (componentDependencies == null) {
365                    // build a new list if "b" has no dependent modules yet
366                    componentDependencies = new ArrayList<String>();
367                    ret.put(dependency, componentDependencies);
368                }
369                // add "a" as a module depending on "b"
370                componentDependencies.add(component.getId());
371            }
372        }
373        itComponents = CmsCollectionsGenericWrapper.<CmsSetupComponent> list(m_components.elementList()).iterator();
374        while (itComponents.hasNext()) {
375            CmsSetupComponent component = itComponents.next();
376            if (ret.get(component.getId()) == null) {
377                ret.put(component.getId(), new ArrayList<String>());
378            }
379        }
380        return ret;
381    }
382
383    /**
384     * Checks the ethernet address value and generates a dummy address, if necessary.<p>     *
385     */
386    public void checkEthernetAddress() {
387
388        // check the ethernet address in order to generate a random address, if not available
389        if (CmsStringUtil.isEmpty(getEthernetAddress())) {
390            setEthernetAddress(CmsStringUtil.getEthernetAddress());
391        }
392    }
393
394    /**
395     * Clears the cache.<p>
396     */
397    public void clearCache() {
398
399        OpenCms.getEventManager().fireEvent(I_CmsEventListener.EVENT_CLEAR_CACHES);
400    }
401
402    /**
403     * Copies a given file.<p>
404     *
405     * @param source the source file
406     * @param target the destination file
407     */
408    public void copyFile(String source, String target) {
409
410        try {
411            CmsFileUtil.copy(m_configRfsPath + source, m_configRfsPath + target);
412        } catch (IOException e) {
413            m_errors.add("Could not copy " + source + " to " + target + " \n");
414            m_errors.add(e.toString() + "\n");
415        }
416    }
417
418    /**
419     * Returns html code to display an error.<p>
420     *
421     * @param pathPrefix to adjust the path
422     *
423     * @return html code
424     */
425    public String displayError(String pathPrefix) {
426
427        if (pathPrefix == null) {
428            pathPrefix = "";
429        }
430        StringBuffer html = new StringBuffer(512);
431        html.append("<table border='0' cellpadding='5' cellspacing='0' style='width: 100%; height: 100%;'>");
432        html.append("\t<tr>");
433        html.append("\t\t<td style='vertical-align: middle; height: 100%;'>");
434        html.append(getHtmlPart("C_BLOCK_START", "Error"));
435        html.append("\t\t\t<table border='0' cellpadding='0' cellspacing='0' style='width: 100%;'>");
436        html.append("\t\t\t\t<tr>");
437        html.append("\t\t\t\t\t<td><img src='").append(pathPrefix).append("resources/error.png' border='0'></td>");
438        html.append("\t\t\t\t\t<td>&nbsp;&nbsp;</td>");
439        html.append("\t\t\t\t\t<td style='width: 100%;'>");
440        html.append("\t\t\t\t\t\tThe Alkacon OpenCms setup wizard has not been started correctly!<br>");
441        html.append("\t\t\t\t\t\tPlease click <a href='").append(pathPrefix);
442        html.append("index.jsp'>here</a> to restart the wizard.");
443        html.append("\t\t\t\t\t</td>");
444        html.append("\t\t\t\t</tr>");
445        html.append("\t\t\t</table>");
446        html.append(getHtmlPart("C_BLOCK_END"));
447        html.append("\t\t</td>");
448        html.append("\t</tr>");
449        html.append("</table>");
450        return html.toString();
451    }
452
453    /**
454     * Returns html code to display the errors occurred.<p>
455     *
456     * @param pathPrefix to adjust the path
457     *
458     * @return html code
459     */
460    public String displayErrors(String pathPrefix) {
461
462        if (pathPrefix == null) {
463            pathPrefix = "";
464        }
465        StringBuffer html = new StringBuffer(512);
466        html.append("<table border='0' cellpadding='5' cellspacing='0' style='width: 100%; height: 100%;'>");
467        html.append("\t<tr>");
468        html.append("\t\t<td style='vertical-align: middle; height: 100%;'>");
469        html.append(getHtmlPart("C_BLOCK_START", "Error"));
470        html.append("\t\t\t<table border='0' cellpadding='0' cellspacing='0' style='width: 100%;'>");
471        html.append("\t\t\t\t<tr>");
472        html.append("\t\t\t\t\t<td><img src='").append(pathPrefix).append("resources/error.png' border='0'></td>");
473        html.append("\t\t\t\t\t<td>&nbsp;&nbsp;</td>");
474        html.append("\t\t\t\t\t<td style='width: 100%;'>");
475
476        Iterator<String> iter = getErrors().iterator();
477        while (iter.hasNext()) {
478            String msg = iter.next();
479            html.append("\t\t\t\t\t\t");
480            html.append(msg);
481            html.append("<br/>");
482        }
483
484        html.append("\t\t\t\t\t</td>");
485        html.append("\t\t\t\t</tr>");
486        html.append("\t\t\t</table>");
487        html.append(getHtmlPart("C_BLOCK_END"));
488        html.append("\t\t</td>");
489        html.append("\t</tr>");
490        html.append("</table>");
491        return html.toString();
492    }
493
494    /**
495     * Returns a map with all available modules.<p>
496     *
497     * The map contains maps keyed by module package names. Each of these maps contains various
498     * information about the module such as the module name, version, description, and a list of
499     * it's dependencies. You should refer to the source code of this method to understand the data
500     * structure of the map returned by this method!<p>
501     *
502     * @return a map with all available modules
503     */
504    public Map<String, CmsModule> getAvailableModules() {
505
506        if ((m_availableModules == null) || m_availableModules.isEmpty()) {
507            m_availableModules = new HashMap<String, CmsModule>();
508            m_moduleDependencies = new HashMap<String, List<String>>();
509            m_moduleFilenames = new HashMap<String, String>();
510            m_components = new CmsIdentifiableObjectContainer<CmsSetupComponent>(true, true);
511
512            try {
513                addComponentsFromPath(m_webAppRfsPath + FOLDER_SETUP);
514                Map<CmsModule, String> modules = CmsModuleManager.getAllModulesFromPath(getModuleFolder());
515                Iterator<Map.Entry<CmsModule, String>> itMods = modules.entrySet().iterator();
516                while (itMods.hasNext()) {
517                    Map.Entry<CmsModule, String> entry = itMods.next();
518                    CmsModule module = entry.getKey();
519                    // put the module information into a map keyed by the module packages names
520                    m_availableModules.put(module.getName(), module);
521                    m_moduleFilenames.put(module.getName(), entry.getValue());
522                    addComponentsFromPath(getModuleFolder() + entry.getValue());
523                }
524            } catch (CmsConfigurationException e) {
525                throw new CmsRuntimeException(e.getMessageContainer());
526            }
527            initializeComponents(new HashSet<String>(m_availableModules.keySet()));
528        }
529        return m_availableModules;
530    }
531
532    /**
533     * Returns the components.<p>
534     *
535     * @return the components
536     */
537    public CmsIdentifiableObjectContainer<CmsSetupComponent> getComponents() {
538
539        return m_components;
540    }
541
542    /**
543     * Returns the "config" path in the OpenCms web application.<p>
544     *
545     * @return the config path
546     */
547    public String getConfigRfsPath() {
548
549        return m_configRfsPath;
550    }
551
552    public String getContextPath() {
553
554        return m_contextPath;
555    }
556
557    /**
558     * Returns the key of the selected database server (e.g. "mysql", "generic" or "oracle").<p>
559     *
560     * @return the key of the selected database server (e.g. "mysql", "generic" or "oracle")
561     */
562    public String getDatabase() {
563
564        if (m_databaseKey == null) {
565            m_databaseKey = getExtProperty("db.name");
566        }
567        if (CmsStringUtil.isEmpty(m_databaseKey)) {
568            m_databaseKey = getSortedDatabases().get(0);
569        }
570        return m_databaseKey;
571    }
572
573    /**
574     * Returns a list of needed jar filenames for a database server setup specified by a database key (e.g. "mysql", "generic" or "oracle").<p>
575     *
576     * @param databaseKey a database key (e.g. "mysql", "generic" or "oracle")
577     *
578     * @return a list of needed jar filenames
579     */
580    public List<String> getDatabaseLibs(String databaseKey) {
581
582        List<String> lst;
583        lst = CmsStringUtil.splitAsList(
584            getDatabaseProperties().get(databaseKey).getProperty(databaseKey + ".libs"),
585            ',',
586            true);
587
588        return lst;
589    }
590
591    /**
592     * Returns the clear text name for a database server setup specified by a database key (e.g. "mysql", "generic" or "oracle").<p>
593     *
594     * @param databaseKey a database key (e.g. "mysql", "generic" or "oracle")
595     * @return the clear text name for a database server setup
596     */
597    public String getDatabaseName(String databaseKey) {
598
599        return getDatabaseProperties().get(databaseKey).getProperty(databaseKey + PROPKEY_NAME);
600    }
601
602    /**
603     * Returns a map with the database properties of *all* available database configurations keyed
604     * by their database keys (e.g. "mysql", "generic" or "oracle").<p>
605     *
606     * @return a map with the database properties of *all* available database configurations
607     */
608    public Map<String, Properties> getDatabaseProperties() {
609
610        if (m_databaseProperties == null) {
611            readDatabaseConfig();
612        }
613        return m_databaseProperties;
614    }
615
616    /**
617     * Returns a list with they keys (e.g. "mysql", "generic" or "oracle") of all available
618     * database server setups found in "/setup/database/".<p>
619     *
620     * @return a list with they keys (e.g. "mysql", "generic" or "oracle") of all available database server setups
621     */
622    public List<String> getDatabases() {
623
624        if (m_databaseKeys == null) {
625            readDatabaseConfig();
626        }
627        return m_databaseKeys;
628    }
629
630    /**
631     * Returns the database name.<p>
632     *
633     * @return the database name
634     */
635    public String getDb() {
636
637        return getDbProperty(m_databaseKey + ".dbname");
638    }
639
640    /**
641     * Returns the JDBC connect URL parameters.<p>
642     *
643     * @return the JDBC connect URL parameters
644     */
645    public String getDbConStrParams() {
646
647        return getDbProperty(m_databaseKey + ".constr.params");
648    }
649
650    /**
651     * Returns the database create statement.<p>
652     *
653     * @return the database create statement
654     */
655    public String getDbCreateConStr() {
656
657        return getDbProperty(m_databaseKey + ".constr");
658    }
659
660    /**
661     * Returns the password used for database creation.<p>
662     *
663     * @return the password used for database creation
664     */
665    public String getDbCreatePwd() {
666
667        return (m_dbCreatePwd != null) ? m_dbCreatePwd : "";
668    }
669
670    /**
671     * Returns the database user that is used to connect to the database.<p>
672     *
673     * @return the database user
674     */
675    public String getDbCreateUser() {
676
677        return getDbProperty(m_databaseKey + ".user");
678    }
679
680    /**
681     * Returns the database driver belonging to the database
682     * from the default configuration.<p>
683     *
684     * @return name of the database driver
685     */
686    public String getDbDriver() {
687
688        return getDbProperty(m_databaseKey + ".driver");
689    }
690
691    /**
692     * Returns the value for a given key from the database properties.
693     *
694     * @param key the property key
695     *
696     * @return the string value for a given key
697     */
698    public String getDbProperty(String key) {
699
700        // extract the database key out of the entire key
701        String databaseKey = key.substring(0, key.indexOf('.'));
702        Properties databaseProperties = getDatabaseProperties().get(databaseKey);
703
704        return databaseProperties.getProperty(key, "");
705    }
706
707    /**
708     * Returns the validation query belonging to the database
709     * from the default configuration .<p>
710     *
711     * @return query used to validate connections
712     */
713    public String getDbTestQuery() {
714
715        return getDbProperty(m_databaseKey + ".testQuery");
716    }
717
718    /**
719     * Returns a connection string.<p>
720     *
721     * @return the connection string used by the OpenCms core
722     */
723    public String getDbWorkConStr() {
724
725        if (m_provider.equals(POSTGRESQL_PROVIDER)) {
726            return getDbProperty(m_databaseKey + ".constr.newDb");
727        } else {
728            return getExtProperty(CmsDbPoolV11.KEY_DATABASE_POOL + '.' + getPool() + ".jdbcUrl");
729        }
730    }
731
732    /**
733     * Returns the password of the database from the properties .<p>
734     *
735     * @return the password for the OpenCms database user
736     */
737    public String getDbWorkPwd() {
738
739        return getExtProperty(CmsDbPoolV11.KEY_DATABASE_POOL + '.' + getPool() + ".password");
740    }
741
742    /**
743     * Returns the user of the database from the properties.<p>
744     *
745     * @return the database user used by the opencms core
746     */
747    public String getDbWorkUser() {
748
749        String user = getExtProperty(CmsDbPoolV11.KEY_DATABASE_POOL + '.' + getPool() + ".user");
750        if (CmsStringUtil.isEmptyOrWhitespaceOnly(user)) {
751            return getDbCreateUser();
752        }
753        return user;
754    }
755
756    /**
757     * Returns the default content encoding.<p>
758     * @return String
759     */
760    public String getDefaultContentEncoding() {
761
762        return getExtProperty("defaultContentEncoding");
763    }
764
765    /**
766     * Returns the name of the default web application, configured in <code>web.xml</code>.<p>
767     *
768     * By default this is <code>"ROOT"</code>.<p>
769     *
770     * @return the name of the default web application, configured in <code>web.xml</code>
771     */
772    public String getDefaultWebApplication() {
773
774        return m_defaultWebApplication;
775    }
776
777    /**
778     * Returns the display string for a given module.<p>
779     *
780     * @param module a module
781     *
782     * @return the display string for the given module
783     */
784    public String getDisplayForModule(CmsModule module) {
785
786        String name = module.getNiceName();
787        String group = module.getGroup();
788        String version = module.getVersion().getVersion();
789        String display = name;
790        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(group)) {
791            display = group + ": " + display;
792        }
793        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(version)) {
794            display += " (" + version + ")";
795        }
796        return display;
797    }
798
799    /**
800     * Returns the error messages.<p>
801     *
802     * @return a vector of error messages
803     */
804    public List<String> getErrors() {
805
806        return m_errors;
807    }
808
809    /**
810     * Returns the mac ethernet address.<p>
811     *
812     * @return the mac ethernet addess
813     */
814    public String getEthernetAddress() {
815
816        if (m_ethernetAddress == null) {
817            String address = getExtProperty("server.ethernet.address");
818            m_ethernetAddress = CmsStringUtil.isNotEmpty(address) ? address : CmsStringUtil.getEthernetAddress();
819        }
820        return m_ethernetAddress;
821    }
822
823    /**
824     * Returns the fullDatabaseKey.<p>
825     *
826     * @return the fullDatabaseKey
827     */
828    public String getFullDatabaseKey() {
829
830        if (m_fullDatabaseKey == null) {
831            m_fullDatabaseKey = getExtProperty("db.name") + "_sql";
832        }
833        if (CmsStringUtil.isEmpty(m_fullDatabaseKey) || m_fullDatabaseKey.equals("_sql")) {
834            m_fullDatabaseKey = getSortedDatabases().get(0) + "_sql";
835        }
836        return m_fullDatabaseKey;
837    }
838
839    /**
840     * Generates the HTML code for the drop down for db selection.<p>
841     *
842     * @return the generated HTML
843     */
844    public String getHtmlForDbSelection() {
845
846        StringBuffer buf = new StringBuffer(2048);
847
848        buf.append(
849            "<select name=\"fullDatabaseKey\" style=\"width: 250px;\" size=\"1\" onchange=\"location.href='../../step_3_database_selection.jsp?fullDatabaseKey='+this.options[this.selectedIndex].value;\">");
850        buf.append("<!-- --------------------- JSP CODE --------------------------- -->");
851
852        // get all available databases
853        List<String> databases = getSortedDatabases();
854
855        //  List all databases found in the dbsetup.properties
856        if ((databases != null) && (databases.size() > 0)) {
857
858            List<String> sqlDbs = new ArrayList<String>();
859
860            for (String dbKey : databases) {
861                sqlDbs.add(dbKey);
862            }
863
864            // show the sql dbs first
865            for (String dbKey : sqlDbs) {
866                String dn = getDatabaseName(dbKey);
867                String selected = "";
868                if (getFullDatabaseKey().equals(dbKey + "_sql")) {
869                    selected = "selected";
870                }
871                buf.append("<option value='" + dbKey + "_sql' " + selected + ">" + dn);
872            }
873        } else {
874            buf.append("<option value='null'>no database found");
875        }
876
877        buf.append("<!-- --------------------------------------------------------- -->");
878        buf.append("</select>");
879
880        return buf.toString();
881    }
882
883    /**
884     * Returns a help image icon tag to display a help text in the setup wizard.<p>
885     *
886     * @param id the id of the desired help div
887     * @param pathPrefix the path prefix to the image
888     * @return the HTML part for the help icon or an empty String, if the part was not found
889     */
890    public String getHtmlHelpIcon(String id, String pathPrefix) {
891
892        String value = m_htmlProps.getProperty("C_HELP_IMG");
893        if (value == null) {
894            return "";
895        } else {
896            value = CmsStringUtil.substitute(value, "$replace$", id);
897            return CmsStringUtil.substitute(value, "$path$", pathPrefix);
898        }
899    }
900
901    /**
902     * Returns the specified HTML part of the HTML property file to create the output.<p>
903     *
904     * @param part the name of the desired part
905     * @return the HTML part or an empty String, if the part was not found
906     */
907    public String getHtmlPart(String part) {
908
909        return getHtmlPart(part, "");
910    }
911
912    /**
913     * Returns the specified HTML part of the HTML property file to create the output.<p>
914     *
915     * @param part the name of the desired part
916     * @param replaceString String which is inserted in the found HTML part at the location of "$replace$"
917     * @return the HTML part or an empty String, if the part was not found
918     */
919    public String getHtmlPart(String part, String replaceString) {
920
921        String value = m_htmlProps.getProperty(part);
922        if (value == null) {
923            return "";
924        } else {
925            return CmsStringUtil.substitute(value, "$replace$", replaceString);
926        }
927    }
928
929    /**
930     * Returns the path to the /WEB-INF/lib folder.<p>
931     *
932     * @return the path to the /WEB-INF/lib folder
933     */
934    public String getLibFolder() {
935
936        return getWebAppRfsPath() + CmsSystemInfo.FOLDER_WEBINF + FOLDER_LIB;
937    }
938
939    /**
940     * Returns the name of the log file.<p>
941     *
942     * @return the name of the log file
943     */
944    public String getLogName() {
945
946        return m_logFile;
947    }
948
949    /**
950     * Returns a map with lists of dependent module package names keyed by module package names.<p>
951     *
952     * @return a map with lists of dependent module package names keyed by module package names
953     */
954    public Map<String, List<String>> getModuleDependencies() {
955
956        if ((m_moduleDependencies == null) || m_moduleDependencies.isEmpty()) {
957            try {
958                // open the folder "/WEB-INF/packages/modules/"
959                m_moduleDependencies = CmsModuleManager.buildDepsForAllModules(getModuleFolder(), true);
960            } catch (CmsConfigurationException e) {
961                throw new CmsRuntimeException(e.getMessageContainer());
962            }
963        }
964        return m_moduleDependencies;
965    }
966
967    /**
968     * Returns the absolute path to the module root folder.<p>
969     *
970     * @return the absolute path to the module root folder
971     */
972    public String getModuleFolder() {
973
974        return new StringBuffer(m_webAppRfsPath).append(m_modulesFolder).toString();
975    }
976
977    /**
978     * Returns A list with the package names of the modules to be installed.<p>
979     *
980     * @return A list with the package names of the modules to be installed
981     */
982    public List<String> getModulesToInstall() {
983
984        if ((m_installModules == null) || m_installModules.isEmpty()) {
985            return Collections.emptyList();
986        }
987        return Collections.unmodifiableList(m_installModules);
988    }
989
990    /**
991     * Gets the default pool.<p>
992     *
993     * @return name of the default pool
994     */
995    public String getPool() {
996
997        return CmsStringUtil.splitAsArray(getExtProperty("db.pools"), ",")[0];
998    }
999
1000    /**
1001     * Returns the parameter configuration.<p>
1002     *
1003     * @return the parameter configuration
1004     */
1005    public CmsParameterConfiguration getProperties() {
1006
1007        return m_configuration;
1008    }
1009
1010    /**
1011     * Returns the replacer.<p>
1012     *
1013     * @return the replacer
1014     */
1015    public Map<String, String> getReplacer() {
1016
1017        return m_replacer;
1018    }
1019
1020    /**
1021     * Return the OpenCms server name.<p>
1022     *
1023     * @return the OpenCms server name
1024     */
1025    public String getServerName() {
1026
1027        return getExtProperty("server.name");
1028    }
1029
1030    /**
1031     * Returns the initial servlet configuration.<p>
1032     *
1033     * @return the initial servlet configuration
1034     */
1035    public ServletConfig getServletConfig() {
1036
1037        return m_servletConfig;
1038    }
1039
1040    /**
1041     * Returns the OpenCms servlet mapping, configured in <code>web.xml</code>.<p>
1042     *
1043     * By default this is <code>"/opencms/*"</code>.<p>
1044     *
1045     * @return the OpenCms servlet mapping, configured in <code>web.xml</code>
1046     */
1047    public String getServletMapping() {
1048
1049        return m_servletMapping;
1050    }
1051
1052    /**
1053     * Returns a sorted list with they keys (e.g. "mysql", "generic" or "oracle") of all available
1054     * database server setups found in "/setup/database/" sorted by their ranking property.<p>
1055     *
1056     * @return a sorted list with they keys (e.g. "mysql", "generic" or "oracle") of all available database server setups
1057     */
1058    public List<String> getSortedDatabases() {
1059
1060        if (m_sortedDatabaseKeys == null) {
1061            List<String> databases = m_databaseKeys;
1062            List<String> sortedDatabases = new ArrayList<String>(databases.size());
1063            SortedMap<Integer, String> mappedDatabases = new TreeMap<Integer, String>();
1064            for (int i = 0; i < databases.size(); i++) {
1065                String key = databases.get(i);
1066                Integer ranking = Integer.valueOf(0);
1067                try {
1068                    ranking = Integer.valueOf(getDbProperty(key + ".ranking"));
1069                } catch (Exception e) {
1070                    // ignore
1071                }
1072                mappedDatabases.put(ranking, key);
1073            }
1074
1075            while (mappedDatabases.size() > 0) {
1076                // get database with highest ranking
1077                Integer key = mappedDatabases.lastKey();
1078                String database = mappedDatabases.get(key);
1079                sortedDatabases.add(database);
1080                mappedDatabases.remove(key);
1081            }
1082            m_sortedDatabaseKeys = sortedDatabases;
1083        }
1084        return m_sortedDatabaseKeys;
1085    }
1086
1087    /**
1088     * Returns the absolute path to the OpenCms home directory.<p>
1089     *
1090     * @return the path to the OpenCms home directory
1091     */
1092    public String getWebAppRfsPath() {
1093
1094        return m_webAppRfsPath;
1095    }
1096
1097    /**
1098     * Checks if the setup wizard is enabled.<p>
1099     *
1100     * @return true if the setup wizard is enables, false otherwise
1101     */
1102    public boolean getWizardEnabled() {
1103
1104        return Boolean.valueOf(getExtProperty("wizard.enabled")).booleanValue();
1105    }
1106
1107    /**
1108     * Returns the workplace import thread.<p>
1109     *
1110     * @return the workplace import thread
1111     */
1112    public CmsSetupWorkplaceImportThread getWorkplaceImportThread() {
1113
1114        return m_workplaceImportThread;
1115    }
1116
1117    /**
1118     * Return the OpenCms workplace site.<p>
1119     *
1120     * @return the OpenCms workplace site
1121     */
1122    public String getWorkplaceSite() {
1123
1124        return getExtProperty("site.workplace");
1125    }
1126
1127    /**
1128     * Returns the xml Helper object.<p>
1129     *
1130     * @return the xml Helper object
1131     */
1132    public CmsSetupXmlHelper getXmlHelper() {
1133
1134        if (m_xmlHelper == null) {
1135            // lazzy initialization
1136            m_xmlHelper = new CmsSetupXmlHelper(getConfigRfsPath());
1137        }
1138        return m_xmlHelper;
1139    }
1140
1141    /**
1142     * Returns true if there is an index.html file in the default site after the module import.
1143     *
1144     * @return true if there is an index.html file
1145     */
1146    public boolean hasIndexHtml() {
1147
1148        return m_hasIndexHtml;
1149    }
1150
1151    /**
1152     * Returns the html code for component selection.<p>
1153     *
1154     * @return html code
1155     */
1156    public String htmlComponents() {
1157
1158        StringBuffer html = new StringBuffer(1024);
1159        Iterator<CmsSetupComponent> itComponents = CmsCollectionsGenericWrapper.<CmsSetupComponent> list(
1160            m_components.elementList()).iterator();
1161        while (itComponents.hasNext()) {
1162            CmsSetupComponent component = itComponents.next();
1163            html.append(htmlComponent(component));
1164        }
1165        return html.toString();
1166    }
1167
1168    /**
1169     * Returns html code for the module descriptions in help ballons.<p>
1170     *
1171     * @return html code
1172     */
1173    public String htmlModuleHelpDescriptions() {
1174
1175        StringBuffer html = new StringBuffer(1024);
1176        Iterator<String> itModules = sortModules(getAvailableModules().values()).iterator();
1177        for (int i = 0; itModules.hasNext(); i++) {
1178            String moduleName = itModules.next();
1179            CmsModule module = getAvailableModules().get(moduleName);
1180            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(module.getDescription())) {
1181                html.append(getHtmlPart("C_HELP_START", "" + i));
1182                html.append(module.getDescription());
1183                html.append("\n");
1184                html.append(getHtmlPart("C_HELP_END"));
1185                html.append("\n");
1186            }
1187        }
1188        return html.toString();
1189    }
1190
1191    /**
1192     * Returns html for displaying a module selection box.<p>
1193     *
1194     * @return html code
1195     */
1196    public String htmlModules() {
1197
1198        StringBuffer html = new StringBuffer(1024);
1199        Iterator<String> itModules = sortModules(getAvailableModules().values()).iterator();
1200        for (int i = 0; itModules.hasNext(); i++) {
1201            String moduleName = itModules.next();
1202            CmsModule module = getAvailableModules().get(moduleName);
1203            html.append(htmlModule(module, i));
1204        }
1205        return html.toString();
1206    }
1207
1208    /**
1209     * Installed all modules that have been set using {@link #setInstallModules(String)}.<p>
1210     *
1211     * This method is invoked as a shell command.<p>
1212     *
1213     * @throws Exception if something goes wrong
1214     */
1215    public void importModulesFromSetupBean() throws Exception {
1216
1217        // read here how the list of modules to be installed is passed from the setup bean to the
1218        // setup thread, and finally to the shell process that executes the setup script:
1219        // 1) the list with the package names of the modules to be installed is saved by setInstallModules
1220        // 2) the setup thread gets initialized in a JSP of the setup wizard
1221        // 3) the instance of the setup bean is passed to the setup thread by setAdditionalShellCommand
1222        // 4) the setup bean is passed to the shell by startSetup
1223        // 5) because the setup bean implements I_CmsShellCommands, the shell constructor can pass the shell's CmsObject back to the setup bean
1224        // 6) thus, the setup bean can do things with the Cms
1225
1226        if ((m_cms != null) && (m_installModules != null)) {
1227            for (int i = 0; i < m_installModules.size(); i++) {
1228                String filename = m_moduleFilenames.get(m_installModules.get(i));
1229                try {
1230                    importModuleFromDefault(filename);
1231                } catch (Exception e) {
1232                    // log a exception during module import, but make sure the next module is still imported
1233                    e.printStackTrace(System.err);
1234                }
1235            }
1236            m_hasIndexHtml = false;
1237            try {
1238                m_cms.readResource("/index.html");
1239                m_hasIndexHtml = true;
1240            } catch (Exception e) {
1241
1242            }
1243
1244        }
1245
1246    }
1247
1248    /**
1249     * Creates a new instance of the setup Bean from a JSP page.<p>
1250     *
1251     * @param pageContext the JSP's page context
1252     */
1253    public void init(PageContext pageContext) {
1254
1255        ServletContext servCtx = pageContext.getServletContext();
1256        ServletConfig servConfig = pageContext.getServletConfig();
1257
1258        init(servCtx, servConfig);
1259    }
1260
1261    public void init(ServletContext servCtx, ServletConfig servConfig) {
1262
1263        // check for OpenCms installation directory path
1264        String webAppRfsPath = servConfig.getServletContext().getRealPath("/");
1265
1266        // read the the OpenCms servlet mapping from the servlet context parameters
1267        String servletMapping = servCtx.getInitParameter(OpenCmsServlet.SERVLET_PARAM_OPEN_CMS_SERVLET);
1268
1269        // read the the default context name from the servlet context parameters
1270        String defaultWebApplication = servCtx.getInitParameter(OpenCmsServlet.SERVLET_PARAM_DEFAULT_WEB_APPLICATION);
1271
1272        m_servletConfig = servConfig;
1273        m_contextPath = servCtx.getContextPath();
1274
1275        init(webAppRfsPath, servletMapping, defaultWebApplication);
1276    }
1277
1278    /**
1279     * Creates a new instance of the setup Bean.<p>
1280     *
1281     * @param webAppRfsPath path to the OpenCms web application
1282     * @param servletMapping the OpenCms servlet mapping
1283     * @param defaultWebApplication the name of the default web application
1284     *
1285     */
1286    public void init(String webAppRfsPath, String servletMapping, String defaultWebApplication) {
1287
1288        try {
1289            // explicit set to null to overwrite exiting values from session
1290            m_availableModules = null;
1291            m_fullDatabaseKey = null;
1292            m_databaseKey = null;
1293            m_databaseKeys = null;
1294            m_databaseProperties = null;
1295            m_configuration = null;
1296            m_installModules = null;
1297            m_moduleDependencies = null;
1298            m_sortedDatabaseKeys = null;
1299            m_moduleFilenames = null;
1300
1301            if (servletMapping == null) {
1302                servletMapping = "/opencms/*";
1303            }
1304            if (defaultWebApplication == null) {
1305                defaultWebApplication = "ROOT";
1306            }
1307            m_servletMapping = servletMapping;
1308            m_defaultWebApplication = defaultWebApplication;
1309
1310            setWebAppRfsPath(webAppRfsPath);
1311            m_errors = new ArrayList<String>();
1312
1313            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(webAppRfsPath)) {
1314                m_configuration = new CmsParameterConfiguration(m_configRfsPath + CmsSystemInfo.FILE_PROPERTIES);
1315                readDatabaseConfig();
1316            }
1317
1318            if (m_workplaceImportThread != null) {
1319                if (m_workplaceImportThread.isAlive()) {
1320                    m_workplaceImportThread.kill();
1321                }
1322                m_workplaceImportThread = null;
1323                m_newLoggingOffset = 0;
1324                m_oldLoggingOffset = 0;
1325            }
1326        } catch (Exception e) {
1327            e.printStackTrace();
1328            m_errors.add(e.toString());
1329        }
1330    }
1331
1332    /**
1333     * This method reads the properties from the htmlmsg.property file
1334     * and sets the HTML part properties with the matching values.<p>
1335     */
1336    public void initHtmlParts() {
1337
1338        if (m_htmlProps != null) {
1339            // html already initialized
1340            return;
1341        }
1342        try {
1343            m_htmlProps = new Properties();
1344            m_htmlProps.load(getClass().getClassLoader().getResourceAsStream(HTML_MESSAGE_FILE));
1345        } catch (Exception e) {
1346            e.printStackTrace();
1347            m_errors.add(e.toString());
1348        }
1349    }
1350
1351    /**
1352     * @see org.opencms.main.I_CmsShellCommands#initShellCmsObject(org.opencms.file.CmsObject, org.opencms.main.CmsShell)
1353     */
1354    public void initShellCmsObject(CmsObject cms, CmsShell shell) {
1355
1356        m_cms = cms;
1357        m_shell = shell;
1358    }
1359
1360    /**
1361     * Returns the autoMode.<p>
1362     *
1363     * @return the autoMode
1364     */
1365    public boolean isAutoMode() {
1366
1367        return m_autoMode;
1368    }
1369
1370    /**
1371     * Over simplistic helper to compare two strings to check radio buttons.
1372     *
1373     * @param value1 the first value
1374     * @param value2 the second value
1375     * @return "checked" if both values are equal, the empty String "" otherwise
1376     */
1377    public String isChecked(String value1, String value2) {
1378
1379        if ((value1 == null) || (value2 == null)) {
1380            return "";
1381        }
1382
1383        if (value1.trim().equalsIgnoreCase(value2.trim())) {
1384            return "checked";
1385        }
1386
1387        return "";
1388    }
1389
1390    /**
1391     * Returns true if this setup bean is correctly initialized.<p>
1392     *
1393     * @return true if this setup bean is correctly initialized
1394     */
1395    public boolean isInitialized() {
1396
1397        return m_configuration != null;
1398    }
1399
1400    /**
1401     * Returns js code with array definition for the available component dependencies.<p>
1402     *
1403     * @return js code
1404     */
1405    public String jsComponentDependencies() {
1406
1407        List<CmsSetupComponent> components = CmsCollectionsGenericWrapper.list(m_components.elementList());
1408        Map<String, List<String>> componentDependencies = buildDepsForAllComponents();
1409
1410        StringBuffer jsCode = new StringBuffer(1024);
1411        jsCode.append("\t// an array holding the dependent components for the n-th component\n");
1412        jsCode.append("\tvar componentDependencies = new Array(");
1413        jsCode.append(components.size());
1414        jsCode.append(");\n");
1415        for (int i = 0; i < components.size(); i++) {
1416            CmsSetupComponent component = components.get(i);
1417            List<String> dependencies = componentDependencies.get(component.getId());
1418            jsCode.append("\tcomponentDependencies[" + i + "] = new Array(");
1419            if (dependencies != null) {
1420                for (int j = 0; j < dependencies.size(); j++) {
1421                    jsCode.append("\"" + dependencies.get(j) + "\"");
1422                    if (j < (dependencies.size() - 1)) {
1423                        jsCode.append(", ");
1424                    }
1425                }
1426            }
1427            jsCode.append(");\n");
1428        }
1429        jsCode.append("\n\n");
1430        return jsCode.toString();
1431    }
1432
1433    /**
1434     * Returns js code with array definition for the component modules.<p>
1435     *
1436     * @return js code
1437     */
1438    public String jsComponentModules() {
1439
1440        List<CmsSetupComponent> components = CmsCollectionsGenericWrapper.list(m_components.elementList());
1441
1442        StringBuffer jsCode = new StringBuffer(1024);
1443        jsCode.append("\t// an array holding the components modules\n");
1444        jsCode.append("\tvar componentModules = new Array(");
1445        jsCode.append(components.size());
1446        jsCode.append(");\n");
1447        for (int i = 0; i < components.size(); i++) {
1448            CmsSetupComponent component = components.get(i);
1449            jsCode.append("\tcomponentModules[" + i + "] = \"");
1450            List<String> modules = getComponentModules(component);
1451            for (int j = 0; j < modules.size(); j++) {
1452                jsCode.append(modules.get(j));
1453                if (j < (modules.size() - 1)) {
1454                    jsCode.append("|");
1455                }
1456            }
1457            jsCode.append("\";\n");
1458        }
1459        jsCode.append("\n\n");
1460        return jsCode.toString();
1461    }
1462
1463    /**
1464     * Returns js code with array definition for the available components names.<p>
1465     *
1466     * @return js code
1467     */
1468    public String jsComponentNames() {
1469
1470        StringBuffer jsCode = new StringBuffer(1024);
1471        jsCode.append("\t// an array from 1...n holding the component names\n");
1472        jsCode.append("\tvar componentNames = new Array(");
1473        jsCode.append(m_components.elementList().size());
1474        jsCode.append(");\n");
1475        for (int i = 0; i < m_components.elementList().size(); i++) {
1476            CmsSetupComponent component = m_components.elementList().get(i);
1477            jsCode.append("\tcomponentNames[" + i + "] = \"" + component.getId() + "\";\n");
1478        }
1479        jsCode.append("\n\n");
1480        return jsCode.toString();
1481    }
1482
1483    /**
1484     * Returns js code with array definition for the available module dependencies.<p>
1485     *
1486     * @return js code
1487     */
1488    public String jsModuleDependencies() {
1489
1490        List<String> moduleNames = sortModules(getAvailableModules().values());
1491
1492        StringBuffer jsCode = new StringBuffer(1024);
1493        jsCode.append("\t// an array holding the dependent modules for the n-th module\n");
1494        jsCode.append("\tvar moduleDependencies = new Array(");
1495        jsCode.append(moduleNames.size());
1496        jsCode.append(");\n");
1497        for (int i = 0; i < moduleNames.size(); i++) {
1498            String moduleName = moduleNames.get(i);
1499            List<String> dependencies = getModuleDependencies().get(moduleName);
1500            jsCode.append("\tmoduleDependencies[" + i + "] = new Array(");
1501            if (dependencies != null) {
1502                for (int j = 0; j < dependencies.size(); j++) {
1503                    jsCode.append("\"" + dependencies.get(j) + "\"");
1504                    if (j < (dependencies.size() - 1)) {
1505                        jsCode.append(", ");
1506                    }
1507                }
1508            }
1509            jsCode.append(");\n");
1510        }
1511        jsCode.append("\n\n");
1512        return jsCode.toString();
1513    }
1514
1515    /**
1516     * Returns js code with array definition for the available module names.<p>
1517     *
1518     * @return js code
1519     */
1520    public String jsModuleNames() {
1521
1522        List<String> moduleNames = sortModules(getAvailableModules().values());
1523        StringBuffer jsCode = new StringBuffer(1024);
1524        jsCode.append("\t// an array from 1...n holding the module package names\n");
1525        jsCode.append("\tvar modulePackageNames = new Array(");
1526        jsCode.append(moduleNames.size());
1527        jsCode.append(");\n");
1528        for (int i = 0; i < moduleNames.size(); i++) {
1529            String moduleName = moduleNames.get(i);
1530            jsCode.append("\tmodulePackageNames[" + i + "] = \"" + moduleName + "\";\n");
1531        }
1532        jsCode.append("\n\n");
1533        return jsCode.toString();
1534    }
1535
1536    /**
1537     * Locks (i.e. disables) the setup wizard.<p>
1538     *
1539     */
1540    public void lockWizard() {
1541
1542        setExtProperty("wizard.enabled", CmsStringUtil.FALSE);
1543    }
1544
1545    /**
1546     * Prepares step 10 of the setup wizard.<p>
1547     */
1548    public void prepareStep10() {
1549
1550        if (isInitialized()) {
1551            // lock the wizard for further use
1552            lockWizard();
1553            // save Properties to file "opencms.properties"
1554            saveProperties(getProperties(), CmsSystemInfo.FILE_PROPERTIES, false);
1555        }
1556    }
1557
1558    /**
1559     * Prepares step 8 of the setup wizard.<p>
1560     *
1561     * @return true if the workplace should be imported
1562     */
1563    public boolean prepareStep8() {
1564
1565        if (isInitialized()) {
1566            try {
1567                checkEthernetAddress();
1568                // backup the XML configuration
1569                backupConfiguration(
1570                    CmsImportExportConfiguration.DEFAULT_XML_FILE_NAME,
1571                    CmsImportExportConfiguration.DEFAULT_XML_FILE_NAME + CmsConfigurationManager.POSTFIX_ORI);
1572                backupConfiguration(
1573                    CmsModuleConfiguration.DEFAULT_XML_FILE_NAME,
1574                    CmsModuleConfiguration.DEFAULT_XML_FILE_NAME + CmsConfigurationManager.POSTFIX_ORI);
1575                backupConfiguration(
1576                    CmsSearchConfiguration.DEFAULT_XML_FILE_NAME,
1577                    CmsSearchConfiguration.DEFAULT_XML_FILE_NAME + CmsConfigurationManager.POSTFIX_ORI);
1578                backupConfiguration(
1579                    CmsSystemConfiguration.DEFAULT_XML_FILE_NAME,
1580                    CmsSystemConfiguration.DEFAULT_XML_FILE_NAME + CmsConfigurationManager.POSTFIX_ORI);
1581                backupConfiguration(
1582                    CmsVfsConfiguration.DEFAULT_XML_FILE_NAME,
1583                    CmsVfsConfiguration.DEFAULT_XML_FILE_NAME + CmsConfigurationManager.POSTFIX_ORI);
1584                backupConfiguration(
1585                    CmsWorkplaceConfiguration.DEFAULT_XML_FILE_NAME,
1586                    CmsWorkplaceConfiguration.DEFAULT_XML_FILE_NAME + CmsConfigurationManager.POSTFIX_ORI);
1587                backupConfiguration(
1588                    CmsConfigurationManager.DEFAULT_XML_FILE_NAME,
1589                    CmsConfigurationManager.DEFAULT_XML_FILE_NAME + CmsConfigurationManager.POSTFIX_ORI);
1590
1591                // save Properties to file "opencms.properties"
1592                setDatabase(m_databaseKey);
1593                saveProperties(getProperties(), CmsSystemInfo.FILE_PROPERTIES, true);
1594
1595                // if has sql driver the sql scripts will be eventualy executed
1596                CmsSetupTestResult testResult = new CmsSetupTestSimapi().execute(this);
1597                if (testResult.getResult().equals(I_CmsSetupTest.RESULT_FAILED)) {
1598                    // "/opencms/vfs/resources/resourceloaders/loader[@class='org.opencms.loader.CmsImageLoader']/param[@name='image.scaling.enabled']";
1599                    StringBuffer xp = new StringBuffer(256);
1600                    xp.append("/").append(CmsConfigurationManager.N_ROOT);
1601                    xp.append("/").append(CmsVfsConfiguration.N_VFS);
1602                    xp.append("/").append(CmsVfsConfiguration.N_RESOURCES);
1603                    xp.append("/").append(CmsVfsConfiguration.N_RESOURCELOADERS);
1604                    xp.append("/").append(CmsVfsConfiguration.N_LOADER);
1605                    xp.append("[@").append(I_CmsXmlConfiguration.A_CLASS);
1606                    xp.append("='").append(CmsImageLoader.class.getName());
1607                    xp.append("']/").append(I_CmsXmlConfiguration.N_PARAM);
1608                    xp.append("[@").append(I_CmsXmlConfiguration.A_NAME);
1609                    xp.append("='").append(CmsImageLoader.CONFIGURATION_SCALING_ENABLED).append("']");
1610
1611                    getXmlHelper().setValue(
1612                        CmsVfsConfiguration.DEFAULT_XML_FILE_NAME,
1613                        xp.toString(),
1614                        Boolean.FALSE.toString());
1615                }
1616                // /opencms/system/sites/workplace-server
1617                StringBuffer xp = new StringBuffer(256);
1618                xp.append("/").append(CmsConfigurationManager.N_ROOT);
1619                xp.append("/").append(CmsSitesConfiguration.N_SITES);
1620                xp.append("/").append(CmsSitesConfiguration.N_WORKPLACE_SERVER);
1621
1622                getXmlHelper().setValue(CmsSitesConfiguration.DEFAULT_XML_FILE_NAME, xp.toString(), getWorkplaceSite());
1623
1624                // /opencms/system/sites/site[@uri='/sites/default/']/@server
1625                xp = new StringBuffer(256);
1626                xp.append("/").append(CmsConfigurationManager.N_ROOT);
1627                xp.append("/").append(CmsSitesConfiguration.N_SITES);
1628                xp.append("/").append(I_CmsXmlConfiguration.N_SITE);
1629                xp.append("[@").append(I_CmsXmlConfiguration.A_URI);
1630                xp.append("='").append(CmsResource.VFS_FOLDER_SITES);
1631                xp.append("/default/']/@").append(CmsSitesConfiguration.A_SERVER);
1632
1633                getXmlHelper().setValue(CmsSitesConfiguration.DEFAULT_XML_FILE_NAME, xp.toString(), getWorkplaceSite());
1634                getXmlHelper().writeAll();
1635            } catch (Exception e) {
1636                if (LOG.isErrorEnabled()) {
1637                    LOG.error(e.getLocalizedMessage(), e);
1638                }
1639            }
1640        }
1641        return true;
1642    }
1643
1644    /**
1645     * Prepares step 8b of the setup wizard.<p>
1646     */
1647    public void prepareStep8b() {
1648
1649        if (!isInitialized()) {
1650            return;
1651        }
1652
1653        if ((m_workplaceImportThread != null) && (m_workplaceImportThread.isFinished())) {
1654            // setup is already finished, just wait for client to collect final data
1655            return;
1656        }
1657
1658        if (m_workplaceImportThread == null) {
1659            m_workplaceImportThread = new CmsSetupWorkplaceImportThread(this);
1660        }
1661
1662        if (!m_workplaceImportThread.isAlive() && !m_workplaceImportThread.getState().equals(Thread.State.TERMINATED)) {
1663            m_workplaceImportThread.start();
1664        }
1665    }
1666
1667    /**
1668     * Generates the output for step 8b of the setup wizard.<p>
1669     *
1670     * @param out the JSP print stream
1671     * @throws IOException in case errors occur while writing to "out"
1672     */
1673    public void prepareStep8bOutput(JspWriter out) throws IOException {
1674
1675        if ((m_workplaceImportThread == null) || (m_workplaceImportThread.getLoggingThread() == null)) {
1676            return;
1677        }
1678        m_oldLoggingOffset = m_newLoggingOffset;
1679        m_newLoggingOffset = m_workplaceImportThread.getLoggingThread().getMessages().size();
1680        if (isInitialized()) {
1681            for (int i = m_oldLoggingOffset; i < m_newLoggingOffset; i++) {
1682                String str = m_workplaceImportThread.getLoggingThread().getMessages().get(i).toString();
1683                str = CmsEncoder.escapeWBlanks(str, CmsEncoder.ENCODING_UTF_8);
1684                out.println("output[" + (i - m_oldLoggingOffset) + "] = \"" + str + "\";");
1685            }
1686        } else {
1687            out.println("output[0] = 'ERROR';");
1688        }
1689
1690        boolean threadFinished = m_workplaceImportThread.isFinished();
1691        boolean allWritten = m_oldLoggingOffset >= m_workplaceImportThread.getLoggingThread().getMessages().size();
1692
1693        out.println("function initThread() {");
1694        if (isInitialized()) {
1695            out.print("send();");
1696            if (threadFinished && allWritten) {
1697                out.println("setTimeout('top.display.finish()', 1000);");
1698            } else {
1699                int timeout = 5000;
1700                if (getWorkplaceImportThread().getLoggingThread().getMessages().size() < 20) {
1701                    timeout = 2000;
1702                }
1703                out.println("setTimeout('location.reload()', " + timeout + ");");
1704            }
1705        }
1706        out.println("}");
1707    }
1708
1709    /**
1710     *  Saves properties to specified file.<p>
1711     *
1712     *  @param properties the properties to be saved
1713     *  @param file the file to save the properties to
1714     *  @param backup if true, create a backupfile
1715     */
1716    public void saveProperties(CmsParameterConfiguration properties, String file, boolean backup) {
1717
1718        if (new File(m_configRfsPath + file).isFile()) {
1719            String backupFile = file + CmsConfigurationManager.POSTFIX_ORI;
1720            String tempFile = file + ".tmp";
1721
1722            m_errors.clear();
1723
1724            if (backup) {
1725                // make a backup copy
1726                copyFile(file, FOLDER_BACKUP + backupFile);
1727            }
1728
1729            //save to temporary file
1730            copyFile(file, tempFile);
1731
1732            // save properties
1733            save(properties, tempFile, file, null);
1734
1735            // delete temp file
1736            File temp = new File(m_configRfsPath + tempFile);
1737            temp.delete();
1738        } else {
1739            m_errors.add("No valid file: " + file + "\n");
1740        }
1741
1742    }
1743
1744    /**
1745     *  Saves properties to specified file.<p>
1746     *
1747     *  @param properties the properties to be saved
1748     *  @param file the file to save the properties to
1749     *  @param backup if true, create a backupfile
1750     *  @param forceWrite the keys for the properties which should always be written, even if they don't exist in the configuration file
1751     */
1752    public void saveProperties(
1753        CmsParameterConfiguration properties,
1754        String file,
1755        boolean backup,
1756        Set<String> forceWrite) {
1757
1758        if (new File(m_configRfsPath + file).isFile()) {
1759            String backupFile = file + CmsConfigurationManager.POSTFIX_ORI;
1760            String tempFile = file + ".tmp";
1761
1762            m_errors.clear();
1763
1764            if (backup) {
1765                // make a backup copy
1766                copyFile(file, FOLDER_BACKUP + backupFile);
1767            }
1768
1769            //save to temporary file
1770            copyFile(file, tempFile);
1771
1772            // save properties
1773            save(properties, tempFile, file, forceWrite);
1774
1775            // delete temp file
1776            File temp = new File(m_configRfsPath + tempFile);
1777            temp.delete();
1778        } else {
1779            m_errors.add("No valid file: " + file + "\n");
1780        }
1781
1782    }
1783
1784    /**
1785     * Sets the autoMode.<p>
1786     *
1787     * @param autoMode the autoMode to set
1788     */
1789    public void setAutoMode(boolean autoMode) {
1790
1791        m_autoMode = autoMode;
1792    }
1793
1794    /**
1795     * Sets the database drivers to the given value.<p>
1796     *
1797     * @param databaseKey the key of the selected database server (e.g. "mysql", "generic" or "oracle")
1798     */
1799    public void setDatabase(String databaseKey) {
1800
1801        m_databaseKey = databaseKey;
1802        String vfsDriver;
1803        String userDriver;
1804        String projectDriver;
1805        String historyDriver;
1806        String subscriptionDriver;
1807        String sqlManager;
1808        vfsDriver = getDbProperty(m_databaseKey + ".vfs.driver");
1809        userDriver = getDbProperty(m_databaseKey + ".user.driver");
1810        projectDriver = getDbProperty(m_databaseKey + ".project.driver");
1811        historyDriver = getDbProperty(m_databaseKey + ".history.driver");
1812        subscriptionDriver = getDbProperty(m_databaseKey + ".subscription.driver");
1813        sqlManager = getDbProperty(m_databaseKey + ".sqlmanager");
1814        // set the db properties
1815        setExtProperty("db.name", m_databaseKey);
1816        setExtProperty("db.vfs.driver", vfsDriver);
1817        setExtProperty("db.vfs.sqlmanager", sqlManager);
1818        setExtProperty("db.user.driver", userDriver);
1819        setExtProperty("db.user.sqlmanager", sqlManager);
1820        setExtProperty("db.project.driver", projectDriver);
1821        setExtProperty("db.project.sqlmanager", sqlManager);
1822        setExtProperty("db.history.driver", historyDriver);
1823        setExtProperty("db.history.sqlmanager", sqlManager);
1824        setExtProperty("db.subscription.driver", subscriptionDriver);
1825        setExtProperty("db.subscription.sqlmanager", sqlManager);
1826        Properties dbProps = getDatabaseProperties().get(databaseKey);
1827        String prefix = "additional.";
1828        String dbPropBlock = "";
1829        for (Map.Entry<Object, Object> entry : dbProps.entrySet()) {
1830            if (entry.getKey() instanceof String) {
1831                String key = (String)entry.getKey();
1832                if (key.startsWith(prefix)) {
1833                    key = key.substring(prefix.length());
1834                    String val = (String)(entry.getValue());
1835                    setExtProperty(key, val);
1836                    dbPropBlock += key + "=" + val + "\n";
1837                }
1838            }
1839
1840        }
1841        if (!CmsStringUtil.isEmptyOrWhitespaceOnly(dbPropBlock)) {
1842            m_additionalProperties.put("dbprops", dbPropBlock);
1843        }
1844    }
1845
1846    /**
1847     * Sets the database name.<p>
1848     *
1849     * @param db the database name to set
1850     */
1851    public void setDb(String db) {
1852
1853        setDbProperty(m_databaseKey + ".dbname", db);
1854    }
1855
1856    /**
1857     * Sets the JDBC connect URL parameters.<p>
1858     *
1859     * @param value the JDBC connect URL parameters
1860     */
1861    public void setDbConStrParams(String value) {
1862
1863        setDbProperty(m_databaseKey + ".constr.params", value);
1864    }
1865
1866    /**
1867     * Sets the database create statement.<p>
1868     *
1869     * @param dbCreateConStr the database create statement
1870     */
1871    public void setDbCreateConStr(String dbCreateConStr) {
1872
1873        setDbProperty(m_databaseKey + ".constr", dbCreateConStr);
1874    }
1875
1876    /**
1877     * Sets the password used for the initial OpenCms database creation.<p>
1878     *
1879     * This password will not be stored permanently,
1880     * but used only in the setup wizard.<p>
1881     *
1882     * @param dbCreatePwd the password used for the initial OpenCms database creation
1883     */
1884    public void setDbCreatePwd(String dbCreatePwd) {
1885
1886        m_dbCreatePwd = dbCreatePwd;
1887    }
1888
1889    /**
1890     * Set the database user that is used to connect to the database.<p>
1891     *
1892     * @param dbCreateUser the user to set
1893     */
1894    public void setDbCreateUser(String dbCreateUser) {
1895
1896        setDbProperty(m_databaseKey + ".user", dbCreateUser);
1897    }
1898
1899    /**
1900     * Sets the database driver belonging to the database.<p>
1901     *
1902     * @param driver name of the opencms driver
1903     */
1904    public void setDbDriver(String driver) {
1905
1906        setDbProperty(m_databaseKey + ".driver", driver);
1907    }
1908
1909    /**
1910     * Sets the needed database parameters.<p>
1911     *
1912     * @param request the http request
1913     * @param provider the db provider
1914     *
1915     * @return true if already submitted
1916     */
1917    public boolean setDbParamaters(HttpServletRequest request, String provider) {
1918
1919        return setDbParamaters(request.getParameterMap(), provider, request.getContextPath(), request.getSession());
1920    }
1921
1922    /**
1923     * Sets the needed database parameters.<p>
1924     *
1925     * @param request the http request
1926     * @param provider the db provider
1927     * @param contextPath the context path to use
1928     * @param session  the session to use or <code>null</code> if running outside a servlet container
1929     *
1930     * @return true if already submitted
1931     */
1932    public boolean setDbParamaters(
1933        Map<String, String[]> request,
1934        String provider,
1935        String contextPath,
1936        HttpSession session) {
1937
1938        String conStr = getReqValue(request, "dbCreateConStr");
1939        // store the DB provider
1940        m_provider = provider;
1941
1942        boolean isFormSubmitted = ((getReqValue(request, "submit") != null) && (conStr != null));
1943        if (conStr == null) {
1944            conStr = "";
1945        }
1946        String database = "";
1947        if (provider.equals(MYSQL_PROVIDER)
1948            || provider.equals(MSSQL_PROVIDER)
1949            || provider.equals(DB2_PROVIDER)
1950            || provider.equals(AS400_PROVIDER)) {
1951            database = getReqValue(request, "db");
1952        } else if (provider.equals(POSTGRESQL_PROVIDER)) {
1953            database = getReqValue(request, "dbName");
1954        }
1955        if (provider.equals(MYSQL_PROVIDER)
1956            || provider.equals(MSSQL_PROVIDER)
1957            || provider.equals(POSTGRESQL_PROVIDER)
1958            || provider.equals(AS400_PROVIDER)
1959            || provider.equals(DB2_PROVIDER)) {
1960            isFormSubmitted = (isFormSubmitted && (database != null));
1961        }
1962        if (!(MAXDB_PROVIDER.equals(provider)
1963            || MSSQL_PROVIDER.equals(provider)
1964            || MYSQL_PROVIDER.equals(provider)
1965            || ORACLE_PROVIDER.equals(provider)
1966            || DB2_PROVIDER.equals(provider)
1967            || AS400_PROVIDER.equals(provider)
1968            || HSQLDB_PROVIDER.equals(provider)
1969            || POSTGRESQL_PROVIDER.equals(provider))) {
1970            throw new RuntimeException("Database provider '" + provider + "' not supported!");
1971        }
1972
1973        if (isInitialized()) {
1974            String createDb = getReqValue(request, "createDb");
1975            if ((createDb == null) || provider.equals(DB2_PROVIDER) || provider.equals(AS400_PROVIDER)) {
1976                createDb = "";
1977            }
1978
1979            String createTables = getReqValue(request, "createTables");
1980            if (createTables == null) {
1981                createTables = "";
1982            }
1983
1984            if (isFormSubmitted) {
1985
1986                if (provider.equals(POSTGRESQL_PROVIDER)) {
1987                    setDb(database);
1988
1989                    String templateDb = getReqValue(request, "templateDb");
1990                    setDbProperty(getDatabase() + ".templateDb", templateDb);
1991                    setDbProperty(getDatabase() + ".newDb", database);
1992
1993                    if (!conStr.endsWith("/")) {
1994                        conStr += "/";
1995                    }
1996                    setDbProperty(getDatabase() + ".constr", conStr + getDbProperty(getDatabase() + ".templateDb"));
1997                    setDbProperty(getDatabase() + ".constr.newDb", conStr + getDbProperty(getDatabase() + ".newDb"));
1998                    conStr += database;
1999                } else if (provider.equals(MYSQL_PROVIDER)
2000                    || provider.equals(DB2_PROVIDER)
2001                    || provider.equals(MSSQL_PROVIDER)
2002                    || provider.equals(POSTGRESQL_PROVIDER)) {
2003                        if (!conStr.endsWith("/")) {
2004                            conStr += "/";
2005                        }
2006                        conStr += database;
2007                    } else if (provider.equals(AS400_PROVIDER)) {
2008                        if (conStr.endsWith("/")) {
2009                            conStr = conStr.substring(0, conStr.length() - 1);
2010                        }
2011                        if (!conStr.endsWith(";")) {
2012                            conStr += ";";
2013                        }
2014                        conStr += "libraries='" + database + "'";
2015                    }
2016                setDbWorkConStr(conStr);
2017                if (provider.equals(POSTGRESQL_PROVIDER)) {
2018                    setDb(database);
2019                }
2020                String dbCreateUser = getReqValue(request, "dbCreateUser");
2021                String dbCreatePwd = getReqValue(request, "dbCreatePwd");
2022
2023                String dbWorkUser = getReqValue(request, "dbWorkUser");
2024                String dbWorkPwd = getReqValue(request, "dbWorkPwd");
2025
2026                if ((dbCreateUser != null) && !provider.equals(DB2_PROVIDER) && !provider.equals(AS400_PROVIDER)) {
2027                    setDbCreateUser(dbCreateUser);
2028                }
2029                setDbCreatePwd(dbCreatePwd);
2030
2031                if (dbWorkUser.equals("")) {
2032                    dbWorkUser = contextPath;
2033                }
2034                if (dbWorkUser.equals("")) {
2035                    dbWorkUser = "opencms";
2036                }
2037                if (dbWorkUser.startsWith("/")) {
2038                    dbWorkUser = dbWorkUser.substring(1, dbWorkUser.length());
2039                }
2040                setDbWorkUser(dbWorkUser);
2041                setDbWorkPwd(dbWorkPwd);
2042
2043                if (provider.equals(ORACLE_PROVIDER)) {
2044                    String dbDefaultTablespace = getReqValue(request, "dbDefaultTablespace");
2045                    String dbTemporaryTablespace = getReqValue(request, "dbTemporaryTablespace");
2046                    String dbIndexTablespace = getReqValue(request, "dbIndexTablespace");
2047
2048                    setDbProperty(getDatabase() + ".defaultTablespace", dbDefaultTablespace);
2049                    setDbProperty(getDatabase() + ".temporaryTablespace", dbTemporaryTablespace);
2050                    setDbProperty(getDatabase() + ".indexTablespace", dbIndexTablespace);
2051                }
2052                Map<String, String> replacer = new HashMap<String, String>();
2053                if (!provider.equals(MYSQL_PROVIDER) || provider.equals(MSSQL_PROVIDER)) {
2054                    replacer.put("${user}", dbWorkUser);
2055                    replacer.put("${password}", dbWorkPwd);
2056                }
2057                if (provider.equals(MYSQL_PROVIDER)
2058                    || provider.equals(MSSQL_PROVIDER)
2059                    || provider.equals(POSTGRESQL_PROVIDER)) {
2060                    replacer.put("${database}", database);
2061                }
2062                if (provider.equals(ORACLE_PROVIDER)) {
2063                    replacer.put("${defaultTablespace}", getDbProperty(getDatabase() + ".defaultTablespace"));
2064                    replacer.put("${indexTablespace}", getDbProperty(getDatabase() + ".indexTablespace"));
2065                    replacer.put("${temporaryTablespace}", getDbProperty(getDatabase() + ".temporaryTablespace"));
2066                }
2067                setReplacer(replacer);
2068
2069                if (session != null) {
2070                    if (provider.equals(GENERIC_PROVIDER)
2071                        || provider.equals(ORACLE_PROVIDER)
2072                        || provider.equals(DB2_PROVIDER)
2073                        || provider.equals(AS400_PROVIDER)
2074                        || provider.equals(MAXDB_PROVIDER)) {
2075                        session.setAttribute("createTables", createTables);
2076                    }
2077                    session.setAttribute("createDb", createDb);
2078                }
2079            } else {
2080                String dbName = "opencms";
2081                // initialize the database name with the app name
2082                if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(contextPath)) {
2083                    dbName = contextPath.substring(1);
2084                }
2085                if (provider.equals(ORACLE_PROVIDER)
2086                    || provider.equals(POSTGRESQL_PROVIDER)
2087                    || provider.equals(MAXDB_PROVIDER)) {
2088                    setDbWorkUser(dbName);
2089                } else if (dbName != null) {
2090                    setDb(dbName);
2091                }
2092            }
2093        }
2094        return isFormSubmitted;
2095    }
2096
2097    /**
2098     * This method sets the value for a given key in the database properties.<p>
2099     *
2100     * @param key The key of the property
2101     * @param value The value of the property
2102     */
2103    public void setDbProperty(String key, String value) {
2104
2105        // extract the database key out of the entire key
2106        String databaseKey = key.substring(0, key.indexOf('.'));
2107        Properties databaseProperties = getDatabaseProperties().get(databaseKey);
2108        databaseProperties.put(key, value);
2109    }
2110
2111    /**
2112     * Sets the connection string to the database to the given value.<p>
2113     *
2114     * @param dbWorkConStr the connection string used by the OpenCms core
2115     */
2116    public void setDbWorkConStr(String dbWorkConStr) {
2117
2118        String driver;
2119        String pool = '.' + getPool() + '.';
2120
2121        driver = getDbProperty(m_databaseKey + ".driver");
2122
2123        setExtProperty(CmsDbPoolV11.KEY_DATABASE_POOL + pool + CmsDbPoolV11.KEY_JDBC_DRIVER, driver);
2124        setExtProperty(CmsDbPoolV11.KEY_DATABASE_POOL + pool + CmsDbPoolV11.KEY_JDBC_URL, dbWorkConStr);
2125        String testQuery = getDbTestQuery();
2126        if (!CmsStringUtil.isEmptyOrWhitespaceOnly(testQuery)) {
2127            setExtProperty(CmsDbPoolV11.KEY_DATABASE_POOL + pool + "v11.connectionTestQuery", testQuery);
2128        }
2129        setExtProperty(CmsDbPoolV11.KEY_DATABASE_POOL + pool + CmsDbPoolV11.KEY_JDBC_URL_PARAMS, getDbConStrParams());
2130    }
2131
2132    /**
2133     * Sets the password of the database to the given value.<p>
2134     *
2135     * @param dbWorkPwd the password for the OpenCms database user
2136     */
2137    public void setDbWorkPwd(String dbWorkPwd) {
2138
2139        setExtProperty(CmsDbPoolV11.KEY_DATABASE_POOL + '.' + getPool() + '.' + CmsDbPoolV11.KEY_PASSWORD, dbWorkPwd);
2140    }
2141
2142    /**
2143     * Sets the user of the database to the given value.<p>
2144     *
2145     * @param dbWorkUser the database user used by the opencms core
2146     */
2147    public void setDbWorkUser(String dbWorkUser) {
2148
2149        setExtProperty(CmsDbPoolV11.KEY_DATABASE_POOL + '.' + getPool() + '.' + CmsDbPoolV11.KEY_POOL_USER, dbWorkUser);
2150    }
2151
2152    /**
2153     * Set the mac ethernet address, required for UUID generation.<p>
2154     *
2155     * @param ethernetAddress the mac addess to set
2156     */
2157    public void setEthernetAddress(String ethernetAddress) {
2158
2159        setExtProperty("server.ethernet.address", ethernetAddress);
2160    }
2161
2162    /**
2163     * Sets the fullDatabaseKey.<p>
2164     *
2165     * @param fullDatabaseKey the fullDatabaseKey to set
2166     */
2167    public void setFullDatabaseKey(String fullDatabaseKey) {
2168
2169        m_fullDatabaseKey = fullDatabaseKey;
2170
2171        String driverPart = fullDatabaseKey.substring(fullDatabaseKey.lastIndexOf("_"), fullDatabaseKey.length());
2172        String keyPart = fullDatabaseKey.substring(0, fullDatabaseKey.lastIndexOf("_"));
2173        setDatabase(keyPart);
2174    }
2175
2176    /**
2177     * Sets the list with the package names of the modules to be installed.<p>
2178     *
2179     * @param value a string with the package names of the modules to be installed delimited by the pipe symbol "|"
2180     */
2181    public void setInstallModules(String value) {
2182
2183        m_installModules = CmsStringUtil.splitAsList(value, "|", true);
2184        try {
2185            m_installModules = CmsModuleManager.topologicalSort(m_installModules, getModuleFolder());
2186        } catch (CmsConfigurationException e) {
2187            throw new RuntimeException(e);
2188        }
2189    }
2190
2191    /**
2192     * Sets the replacer.<p>
2193     *
2194     * @param map the replacer to set
2195     */
2196    public void setReplacer(Map<String, String> map) {
2197
2198        m_replacer = map;
2199    }
2200
2201    /**
2202     * Sets the OpenCms server name.<p>
2203     *
2204     * @param name the OpenCms server name
2205     */
2206    public void setServerName(String name) {
2207
2208        setExtProperty("server.name", name);
2209    }
2210
2211    /**
2212     * Sets the start view for the given user.<p>
2213     *
2214     * @param userName the name of the user
2215     * @param view the start view path
2216     *
2217     * @throws CmsException if something goes wrong
2218     */
2219    public void setStartView(String userName, String view) throws CmsException {
2220
2221        try {
2222
2223            CmsUser user = m_cms.readUser(userName);
2224            user.getAdditionalInfo().put(
2225                CmsUserSettings.PREFERENCES
2226                    + CmsWorkplaceConfiguration.N_WORKPLACESTARTUPSETTINGS
2227                    + CmsWorkplaceConfiguration.N_WORKPLACEVIEW,
2228                view);
2229            m_cms.writeUser(user);
2230        } catch (CmsException e) {
2231            e.printStackTrace(System.err);
2232            throw e;
2233        }
2234    }
2235
2236    /**
2237     * Sets the OpenCms workplace site.<p>
2238     *
2239     * @param newSite the OpenCms workplace site
2240     */
2241    public void setWorkplaceSite(String newSite) {
2242
2243        String oldSite = getWorkplaceSite();
2244        // get the site list
2245        String siteList = getExtProperty("site.root.list");
2246        // replace old site URL in site list with new site URL
2247        siteList = CmsStringUtil.substitute(siteList, oldSite, newSite);
2248        setExtProperty("site.root.list", siteList);
2249        setExtProperty("site.workplace", newSite);
2250    }
2251
2252    /**
2253     * @see org.opencms.main.I_CmsShellCommands#shellExit()
2254     */
2255    public void shellExit() {
2256
2257        m_shell.getOut().println();
2258        m_shell.getOut().println();
2259        m_shell.getOut().println("The setup is finished!\nThe OpenCms system used for the setup will now shut down.");
2260    }
2261
2262    /**
2263     * @see org.opencms.main.I_CmsShellCommands#shellStart()
2264     */
2265    public void shellStart() {
2266
2267        m_shell.getOut().println();
2268        m_shell.getOut().println("Starting Workplace import and database setup for OpenCms!");
2269
2270        String[] copy = org.opencms.main.Messages.COPYRIGHT_BY_ALKACON;
2271        for (int i = copy.length - 1; i >= 0; i--) {
2272            m_shell.getOut().println(copy[i]);
2273        }
2274        m_shell.getOut().println(
2275            "This is OpenCms "
2276                + OpenCms.getSystemInfo().getVersionNumber()
2277                + " ["
2278                + OpenCms.getSystemInfo().getVersionId()
2279                + "]");
2280        m_shell.getOut().println();
2281        m_shell.getOut().println();
2282    }
2283
2284    /**
2285     * Sorts the modules for display.<p>
2286     *
2287     * @param modules the list of {@link CmsModule} objects
2288     *
2289     * @return a sorted list of module names
2290     */
2291    public List<String> sortModules(Collection<CmsModule> modules) {
2292
2293        List<CmsModule> aux = new ArrayList<CmsModule>(modules);
2294        Collections.sort(aux, new Comparator<CmsModule>() {
2295
2296            public int compare(CmsModule module1, CmsModule module2) {
2297
2298                return getDisplayForModule(module1).compareTo(getDisplayForModule(module2));
2299            }
2300        });
2301
2302        List<String> ret = new ArrayList<String>(aux.size());
2303        for (Iterator<CmsModule> it = aux.iterator(); it.hasNext();) {
2304            CmsModule module = it.next();
2305            ret.add(module.getName());
2306        }
2307        return ret;
2308    }
2309
2310    /**
2311     * Writes configuration changes back to the XML configuration.
2312     */
2313    public void updateConfiguration() {
2314
2315        // currently we only need the system configuration
2316        OpenCms.writeConfiguration(CmsSystemConfiguration.class);
2317    }
2318
2319    /**
2320     * Checks the jdbc driver.<p>
2321     *
2322     * @return <code>true</code> if at least one of the recommended drivers is found
2323     */
2324    public boolean validateJdbc() {
2325
2326        boolean result = false;
2327        String libFolder = getLibFolder();
2328        Iterator<String> it = getDatabaseLibs(getDatabase()).iterator();
2329        while (it.hasNext()) {
2330            String libName = it.next();
2331            File libFile = new File(libFolder, libName);
2332            if (libFile.exists()) {
2333                result = true;
2334            }
2335        }
2336        return result;
2337    }
2338
2339    /**
2340     * Reads all components from the given location, a folder or a zip file.<p>
2341     *
2342     * @param fileName the location to read the components from
2343     *
2344     * @throws CmsConfigurationException if something goes wrong
2345     */
2346    protected void addComponentsFromPath(String fileName) throws CmsConfigurationException {
2347
2348        CmsParameterConfiguration configuration;
2349        try {
2350            configuration = getComponentsProperties(fileName);
2351        } catch (FileNotFoundException e) {
2352            if (LOG.isDebugEnabled()) {
2353                LOG.debug(e.getLocalizedMessage(), e);
2354            }
2355            return;
2356        }
2357
2358        for (String componentId : configuration.getList(PROPKEY_COMPONENTS)) {
2359            CmsSetupComponent componentBean = new CmsSetupComponent();
2360            componentBean.setId(componentId);
2361            componentBean.setName(configuration.get(PROPKEY_COMPONENT + componentId + PROPKEY_NAME));
2362            componentBean.setDescription(configuration.get(PROPKEY_COMPONENT + componentId + PROPKEY_DESCRIPTION));
2363            componentBean.setModulesRegex(configuration.get(PROPKEY_COMPONENT + componentId + PROPKEY_MODULES));
2364            componentBean.setDependencies(
2365                configuration.getList(PROPKEY_COMPONENT + componentId + PROPKEY_DEPENDENCIES));
2366            componentBean.setPosition(
2367                configuration.getInteger(PROPKEY_COMPONENT + componentId + PROPKEY_POSITION, DEFAULT_POSITION));
2368            componentBean.setChecked(
2369                configuration.getBoolean(PROPKEY_COMPONENT + componentId + PROPKEY_CHECKED, false));
2370            m_components.addIdentifiableObject(componentBean.getId(), componentBean, componentBean.getPosition());
2371        }
2372    }
2373
2374    /**
2375     * Returns a pipe separated list of module names for the given list of components.<p>
2376     *
2377     * @param componentIds the list of component IDs to get the modules for
2378     *
2379     * @return a pipe separated list of module names for the given list of components
2380     */
2381    protected String getComponentModules(List<String> componentIds) {
2382
2383        Set<String> comps = new HashSet<String>();
2384        List<CmsSetupComponent> components = CmsCollectionsGenericWrapper.list(m_components.elementList());
2385        for (CmsSetupComponent comp : components) {
2386            if (componentIds.contains(comp.getId())) {
2387                comps.addAll(getComponentModules(comp));
2388            }
2389
2390        }
2391
2392        StringBuffer buf = new StringBuffer();
2393        List<String> moduleNames = sortModules(getAvailableModules().values());
2394        boolean first = true;
2395        for (String moduleName : moduleNames) {
2396            if (!first) {
2397                buf.append("|");
2398            }
2399            if (comps.contains(moduleName)) {
2400                buf.append(moduleName);
2401            }
2402            first = false;
2403        }
2404
2405        return buf.toString();
2406    }
2407
2408    /**
2409     * Reads all properties from the components.properties file at the given location, a folder or a zip file.<p>
2410     *
2411     * @param location the location to read the properties from
2412     *
2413     * @return the read properties
2414     *
2415     * @throws FileNotFoundException if the properties file could not be found
2416     * @throws CmsConfigurationException if the something else goes wrong
2417     */
2418    protected CmsParameterConfiguration getComponentsProperties(String location)
2419    throws FileNotFoundException, CmsConfigurationException {
2420
2421        InputStream stream = null;
2422        ZipFile zipFile = null;
2423        try {
2424            // try to interpret the fileName as a folder
2425            File folder = new File(location);
2426
2427            // if it is a file it must be a zip-file
2428            if (folder.isFile()) {
2429                zipFile = new ZipFile(location);
2430                ZipEntry entry = zipFile.getEntry(COMPONENTS_PROPERTIES);
2431                // path to file might be relative, too
2432                if ((entry == null) && location.startsWith("/")) {
2433                    entry = zipFile.getEntry(location.substring(1));
2434                }
2435                if (entry == null) {
2436                    zipFile.close();
2437                    throw new FileNotFoundException(
2438                        org.opencms.importexport.Messages.get().getBundle().key(
2439                            org.opencms.importexport.Messages.LOG_IMPORTEXPORT_FILE_NOT_FOUND_IN_ZIP_1,
2440                            location + "/" + COMPONENTS_PROPERTIES));
2441                }
2442
2443                stream = zipFile.getInputStream(entry);
2444            } else {
2445                // it is a folder
2446                File file = new File(folder, COMPONENTS_PROPERTIES);
2447                stream = new FileInputStream(file);
2448            }
2449            return new CmsParameterConfiguration(stream);
2450        } catch (Throwable ioe) {
2451            if (stream != null) {
2452                try {
2453                    stream.close();
2454                } catch (IOException e) {
2455                    if (LOG.isDebugEnabled()) {
2456                        LOG.debug(e.getLocalizedMessage(), e);
2457                    }
2458                }
2459            }
2460            if (zipFile != null) {
2461                try {
2462                    zipFile.close();
2463                } catch (IOException e) {
2464                    if (LOG.isDebugEnabled()) {
2465                        LOG.debug(e.getLocalizedMessage(), e);
2466                    }
2467                }
2468            }
2469            if (ioe instanceof FileNotFoundException) {
2470                throw (FileNotFoundException)ioe;
2471            }
2472
2473            CmsMessageContainer msg = org.opencms.importexport.Messages.get().container(
2474                org.opencms.importexport.Messages.ERR_IMPORTEXPORT_ERROR_READING_FILE_1,
2475                location + "/" + COMPONENTS_PROPERTIES);
2476            if (LOG.isErrorEnabled()) {
2477                LOG.error(msg.key(), ioe);
2478            }
2479            throw new CmsConfigurationException(msg, ioe);
2480        }
2481    }
2482
2483    /**
2484     * Returns the value for a given key from the extended properties.
2485     *
2486     * @param key the property key
2487     * @return the string value for a given key
2488     */
2489    protected String getExtProperty(String key) {
2490
2491        return m_configuration.getString(key, "");
2492    }
2493
2494    /**
2495     * Returns html for the given component to fill the selection list.<p>
2496     *
2497     * @param component the component to generate the code for
2498     *
2499     * @return html code
2500     */
2501    protected String htmlComponent(CmsSetupComponent component) {
2502
2503        StringBuffer html = new StringBuffer(256);
2504        html.append("\t<tr>\n");
2505        html.append("\t\t<td>\n");
2506        html.append("\t\t\t<input type='checkbox' name='availableComponents' value='");
2507        html.append(component.getId());
2508        html.append("'");
2509        if (component.isChecked()) {
2510            html.append(" checked='checked'");
2511        }
2512        html.append(" onClick=\"checkComponentDependencies('");
2513        html.append(component.getId());
2514        html.append("');\">\n");
2515        html.append("\t\t</td>\n");
2516        html.append("\t\t<td style='width: 100%; '>\n\t\t\t");
2517        html.append(component.getName());
2518        html.append("\n\t\t</td>\n");
2519        html.append("\t</tr>\n");
2520        html.append("\t<tr>\n");
2521        html.append("\t\t<td>&nbsp;</td>\n");
2522        html.append(
2523            "\t\t<td style='vertical-align: top; width: 100%; padding-bottom: 8px; font-style: italic;'>\n\t\t\t");
2524        html.append(component.getDescription());
2525        html.append("\n\t\t</td>\n");
2526        html.append("\t</tr>\n");
2527
2528        return html.toString();
2529    }
2530
2531    /**
2532     * Returns html for the given module to fill the selection list.<p>
2533     *
2534     * @param module the module to generate the code for
2535     * @param pos the position in the list
2536     *
2537     * @return html code
2538     */
2539    protected String htmlModule(CmsModule module, int pos) {
2540
2541        StringBuffer html = new StringBuffer(256);
2542        html.append("\t<tr>\n");
2543        html.append("\t\t<td style='vertical-align: top;'>\n");
2544        html.append("\t\t\t<input type='checkbox' name='availableModules' value='");
2545        html.append(module.getName());
2546        html.append("' checked='checked' onClick=\"checkModuleDependencies('");
2547        html.append(module.getName());
2548        html.append("');\">\n");
2549        html.append("\t\t</td>\n");
2550        html.append("\t\t<td style='vertical-align: top; width: 100%; padding-top: 4px;'>\n\t\t\t");
2551        html.append(getDisplayForModule(module));
2552        html.append("\n\t\t</td>\n");
2553        html.append("\t\t<td style='vertical-align: top; text-align: right;'>\n");
2554        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(module.getDescription())) {
2555            html.append("\t\t\t");
2556            html.append(getHtmlHelpIcon("" + pos, ""));
2557        }
2558        html.append("\t\t</td>\n");
2559        html.append("\t</tr>\n");
2560        return html.toString();
2561    }
2562
2563    /**
2564     * Imports a module (zipfile) from the default module directory,
2565     * creating a temporary project for this.<p>
2566     *
2567     * @param importFile the name of the import module located in the default module directory
2568     *
2569     * @throws Exception if something goes wrong
2570     *
2571     * @see org.opencms.importexport.CmsImportExportManager#importData(CmsObject, org.opencms.report.I_CmsReport, CmsImportParameters)
2572     */
2573    protected void importModuleFromDefault(String importFile) throws Exception {
2574
2575        String fileName = getModuleFolder() + importFile;
2576        OpenCms.getImportExportManager().importData(
2577            m_cms,
2578            new CmsShellReport(m_cms.getRequestContext().getLocale()),
2579            new CmsImportParameters(fileName, "/", true));
2580    }
2581
2582    /**
2583     * Initializes and validates the read components.<p>
2584     *
2585     * @param modules a modifiable list of the modules to be imported
2586     */
2587    protected void initializeComponents(Collection<String> modules) {
2588
2589        Iterator<CmsSetupComponent> itGroups = new ArrayList<CmsSetupComponent>(
2590            CmsCollectionsGenericWrapper.<CmsSetupComponent> list(m_components.elementList())).iterator();
2591        while (itGroups.hasNext()) {
2592            CmsSetupComponent component = itGroups.next();
2593            String errMsg = "";
2594            String warnMsg = "";
2595            // check name
2596            if (CmsStringUtil.isEmptyOrWhitespaceOnly(component.getName())) {
2597                errMsg += Messages.get().container(Messages.ERR_COMPONENT_NAME_EMPTY_1, component.getId()).key();
2598                errMsg += "\n";
2599            }
2600            // check description
2601            if (CmsStringUtil.isEmptyOrWhitespaceOnly(component.getName())) {
2602                warnMsg += Messages.get().container(Messages.LOG_WARN_COMPONENT_DESC_EMPTY_1, component.getId()).key();
2603                warnMsg += "\n";
2604            }
2605            // check position
2606            if (component.getPosition() == DEFAULT_POSITION) {
2607                warnMsg += Messages.get().container(Messages.LOG_WARN_COMPONENT_POS_EMPTY_1, component.getId()).key();
2608                warnMsg += "\n";
2609            }
2610            // check dependencies
2611            Iterator<String> itDeps = component.getDependencies().iterator();
2612            while (itDeps.hasNext()) {
2613                String dependency = itDeps.next();
2614                if (m_components.getObject(dependency) == null) {
2615                    errMsg += Messages.get().container(
2616                        Messages.LOG_WARN_COMPONENT_DEPENDENCY_BROKEN_2,
2617                        component.getId(),
2618                        dependency).key();
2619                    errMsg += "\n";
2620                }
2621            }
2622            // check modules match
2623            boolean match = false;
2624            Iterator<String> itModules = modules.iterator();
2625            while (itModules.hasNext()) {
2626                String module = itModules.next();
2627                if (component.match(module)) {
2628                    match = true;
2629                    itModules.remove();
2630                }
2631            }
2632            if (!match) {
2633                errMsg += Messages.get().container(Messages.ERR_COMPONENT_MODULES_EMPTY_1, component.getId()).key();
2634                errMsg += "\n";
2635            }
2636
2637            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(errMsg)) {
2638                m_components.removeObject(component.getId());
2639                if (LOG.isErrorEnabled()) {
2640                    LOG.error(errMsg);
2641                }
2642            }
2643            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(warnMsg)) {
2644                if (LOG.isWarnEnabled()) {
2645                    LOG.warn(warnMsg);
2646                }
2647            }
2648        }
2649        if (!modules.isEmpty()) {
2650            if (LOG.isWarnEnabled()) {
2651                LOG.warn(Messages.get().container(Messages.LOG_WARN_MODULES_LEFT_1, modules.toString()));
2652            }
2653        }
2654    }
2655
2656    /**
2657     * Returns <code>true</code> if the import thread is currently running.<p>
2658     *
2659     * @return <code>true</code> if the import thread is currently running
2660     */
2661    protected boolean isImportRunning() {
2662
2663        return (m_workplaceImportThread != null) && m_workplaceImportThread.isAlive();
2664    }
2665
2666    /**
2667     * Stores the properties of all available database configurations in a
2668     * map keyed by their database key names (e.g. "mysql", "generic" or "oracle").<p>
2669     */
2670    protected void readDatabaseConfig() {
2671
2672        m_databaseKeys = new ArrayList<String>();
2673        m_databaseProperties = new HashMap<String, Properties>();
2674
2675        FileInputStream input = null;
2676        File childResource = null;
2677
2678        List<String> databaseKeys = new ArrayList<String>();
2679        Map<String, Properties> databaseProperties = new HashMap<String, Properties>();
2680
2681        try {
2682            File databaseSetupFolder = new File(m_webAppRfsPath + FOLDER_SETUP + FOLDER_DATABASE);
2683
2684            File[] childResources = databaseSetupFolder.listFiles();
2685
2686            // collect all possible db configurations
2687            if (childResources != null) {
2688                for (int i = 0; i < childResources.length; i++) {
2689                    childResource = childResources[i];
2690                    if (childResource.exists() && childResource.isDirectory() && childResource.canRead()) {
2691                        databaseKeys.add(childResource.getName().trim());
2692                    }
2693                }
2694            }
2695
2696            // create the properties with all possible configurations
2697            if (databaseSetupFolder.exists()) {
2698                for (String key : databaseKeys) {
2699                    String dbDir = m_webAppRfsPath + CmsSetupBean.FOLDER_SETUP + "database" + File.separatorChar + key;
2700                    String configPath = dbDir + File.separatorChar + "database.properties";
2701                    try {
2702                        input = new FileInputStream(new File(configPath));
2703                        Properties databaseProps = new Properties();
2704                        databaseProps.load(input);
2705                        databaseProperties.put(key, databaseProps);
2706                    } catch (Exception e) {
2707                        System.err.println(e.toString());
2708                        e.printStackTrace(System.err);
2709                        continue;
2710                    }
2711                }
2712            }
2713
2714            // add the properties and the keys to the memeber variables if all needed files exist
2715            if (childResources != null) {
2716                for (int i = 0; i < childResources.length; i++) {
2717                    childResource = childResources[i];
2718                    if (childResource.exists() && childResource.isDirectory() && childResource.canRead()) {
2719                        String dataBasekey = childResource.getName().trim();
2720                        Properties props = databaseProperties.get(dataBasekey);
2721                        if (checkFilesExists(REQUIRED_SQL_DB_SETUP_FILES, childResource)) {
2722                            m_databaseKeys.add(childResource.getName().trim());
2723                            m_databaseProperties.put(dataBasekey, props);
2724                        }
2725                    }
2726                }
2727            }
2728        } catch (Exception e) {
2729            System.err.println(e.toString());
2730            e.printStackTrace(System.err);
2731        } finally {
2732            try {
2733                if (input != null) {
2734                    input.close();
2735                }
2736            } catch (Exception e) {
2737                // noop
2738            }
2739        }
2740    }
2741
2742    /**
2743     * This method sets the value for a given key in the extended properties.
2744     *
2745     * @param key The key of the property
2746     * @param value The value of the property
2747     */
2748    protected void setExtProperty(String key, String value) {
2749
2750        m_configuration.put(key, value);
2751    }
2752
2753    /**
2754     * Checks if the necessary files for the configuration are existent or not.<p>
2755     *
2756     * @param requiredFiles the required files
2757     * @param childResource the folder to check
2758     *
2759     * @return true if the files are existent
2760     */
2761    private boolean checkFilesExists(String[] requiredFiles, File childResource) {
2762
2763        File setupFile = null;
2764        boolean hasMissingSetupFiles = false;
2765
2766        for (int j = 0; j < requiredFiles.length; j++) {
2767            setupFile = new File(childResource.getPath() + File.separatorChar + requiredFiles[j]);
2768
2769            if (!setupFile.exists() || !setupFile.isFile() || !setupFile.canRead()) {
2770                hasMissingSetupFiles = true;
2771                System.err.println(
2772                    "[" + getClass().getName() + "] missing or unreadable database setup file: " + setupFile.getPath());
2773                break;
2774            }
2775
2776            if (!hasMissingSetupFiles) {
2777                return true;
2778            }
2779        }
2780        return false;
2781    }
2782
2783    /**
2784     * Creates an string out of the given array to store back in the property file.<p>
2785     *
2786     * @param values the array with the values to create a string from
2787     *
2788     * @return a string with the values of the array which is ready to store in the property file
2789     */
2790    private String createValueString(String[] values) {
2791
2792        StringBuffer buf = new StringBuffer();
2793
2794        for (int i = 0; i < values.length; i++) {
2795
2796            // escape commas and equals in value
2797            values[i] = CmsStringUtil.substitute(values[i], ",", "\\,");
2798            values[i] = CmsStringUtil.substitute(values[i], "=", "\\=");
2799
2800            buf.append("\t" + values[i] + ((i < (values.length - 1)) ? ",\\\n" : ""));
2801        }
2802        return buf.toString();
2803    }
2804
2805    /**
2806     * Returns a list of matching modules for the given component.<p>
2807     *
2808     * @param component the component to get the modules for
2809     *
2810     * @return a list of matching module names
2811     */
2812    private List<String> getComponentModules(CmsSetupComponent component) {
2813
2814        List<String> modules = new ArrayList<String>();
2815        Iterator<String> itModules = m_availableModules.keySet().iterator();
2816        while (itModules.hasNext()) {
2817            String moduleName = itModules.next();
2818            if (component.match(moduleName)) {
2819                modules.add(moduleName);
2820            }
2821        }
2822        return modules;
2823    }
2824
2825    /**
2826     * Returns the text which should be written to the configuration file for a given property value.<p>
2827     *
2828     * @param obj the property value
2829     *
2830     * @return the text to write for that property value
2831     */
2832    private String getPropertyValueToWrite(Object obj) {
2833
2834        String value;
2835        String valueToWrite = null;
2836        if (obj instanceof List<?>) {
2837            String[] values = {};
2838            values = CmsCollectionsGenericWrapper.list(obj).toArray(values);
2839            // write it
2840            valueToWrite = "\\\n" + createValueString(values);
2841        } else {
2842            value = String.valueOf(obj).trim();
2843            // escape commas and equals in value
2844            value = CmsStringUtil.substitute(value, ",", "\\,");
2845            // value = CmsStringUtil.substitute(value, "=", "\\=");
2846            // write it
2847            valueToWrite = value;
2848        }
2849        return valueToWrite;
2850    }
2851
2852    /**
2853     * Returns the first value of the array for the given key.<p>
2854     *
2855     * @param map the map to search the key in
2856     * @param key the key to get the first value from
2857     *
2858     * @return the first value of the array for the given key
2859     */
2860    private String getReqValue(Map<String, String[]> map, String key) {
2861
2862        return map.get(key) != null ? map.get(key)[0] : null;
2863    }
2864
2865    private String paramsToString(Map<String, String[]> request) {
2866
2867        String result = "";
2868        for (Map.Entry<String, String[]> entry : request.entrySet()) {
2869            String strEntry = entry.getKey() + "=(";
2870            for (String val : entry.getValue()) {
2871                strEntry += val + " ";
2872            }
2873            strEntry += ")";
2874            result += strEntry + " ";
2875        }
2876        return "{" + result + "}";
2877
2878    }
2879
2880    /**
2881     * Saves the properties to a file.<p>
2882     *
2883     * @param properties the properties to be saved
2884     * @param source the source file to get the keys from
2885     * @param target the target file to save the properties to
2886     * @param forceWrite the keys of the properties which should always be written, even if they don't exist in the configuration file
2887     */
2888    private void save(CmsParameterConfiguration properties, String source, String target, Set<String> forceWrite) {
2889
2890        try {
2891            Set<String> alreadyWritten = new HashSet<String>();
2892
2893            LineNumberReader lnr = new LineNumberReader(new FileReader(new File(m_configRfsPath + source)));
2894
2895            FileWriter fw = new FileWriter(new File(m_configRfsPath + target));
2896
2897            while (true) {
2898                String line = lnr.readLine();
2899                if (line == null) {
2900                    break;
2901                }
2902                line = line.trim();
2903
2904                if ("".equals(line)) {
2905                    // output empty line
2906                    fw.write("\n");
2907                } else if (line.startsWith("#")) {
2908                    // output comment
2909                    fw.write(line);
2910                    fw.write("\n");
2911                } else {
2912
2913                    int index = line.indexOf('=');
2914                    int index1 = line.indexOf("\\=");
2915                    if ((line.indexOf('=') > -1) && (index1 != (index - 1))) {
2916
2917                        String key = line.substring(0, line.indexOf('=')).trim();
2918                        if (alreadyWritten.contains(key)) {
2919                            continue;
2920                        }
2921                        String additionalPrefix = ADDITIONAL_PREFIX;
2922                        if (key.startsWith(additionalPrefix)) {
2923                            String additionalPropKey = key.substring(additionalPrefix.length());
2924                            String additionalContent = m_additionalProperties.get(additionalPropKey);
2925                            if (additionalContent == null) {
2926                                fw.write(key + "=\n");
2927                            } else {
2928                                fw.write(additionalContent + "\n");
2929                            }
2930                            continue;
2931                        }
2932                        // write key
2933                        fw.write((key + "="));
2934                        try {
2935                            Object obj = properties.getObject(key);
2936                            if (obj != null) {
2937                                String valueToWrite = getPropertyValueToWrite(obj);
2938                                fw.write(valueToWrite);
2939                            }
2940
2941                        } catch (NullPointerException e) {
2942                            // no value found - do nothing
2943                        }
2944                        // add trailing line feed
2945                        fw.write("\n");
2946
2947                        // remember that this properties is already written (multi values)
2948                        alreadyWritten.add(key);
2949                    }
2950                }
2951            }
2952            if (forceWrite != null) {
2953                for (String forced : forceWrite) {
2954                    if (!alreadyWritten.contains(forced) && properties.containsKey(forced)) {
2955                        fw.write("\n\n");
2956                        fw.write(forced + "=");
2957                        try {
2958                            Object obj = properties.getObject(forced);
2959
2960                            if (obj != null) {
2961                                String valueToWrite = getPropertyValueToWrite(obj);
2962                                fw.write(valueToWrite);
2963                            }
2964                        } catch (NullPointerException e) {
2965                            // no value found - do nothing
2966                        }
2967                        fw.write("\n");
2968
2969                    }
2970                }
2971            }
2972
2973            lnr.close();
2974            fw.close();
2975        } catch (Exception e) {
2976            m_errors.add("Could not save properties to " + target + " \n");
2977            m_errors.add(e.toString() + "\n");
2978        }
2979    }
2980
2981    /**
2982     * Sets the pool size.<p>
2983     *
2984     * @param poolSize the pool size
2985     */
2986    private void setEntityManagerPoolSize(String poolSize) {
2987
2988        setExtProperty(
2989            CmsDbPoolV11.KEY_DATABASE_POOL + '.' + getPool() + '.' + CmsDbPoolV11.KEY_ENTITY_MANAGER_POOL_SIZE,
2990            poolSize);
2991    }
2992
2993    /**
2994      * Sets the path to the OpenCms home directory.<p>
2995      *
2996      * @param webInfRfsPath path to OpenCms home directory
2997      */
2998    private void setWebAppRfsPath(String webInfRfsPath) {
2999
3000        m_webAppRfsPath = webInfRfsPath;
3001        if ("".equals(webInfRfsPath)) {
3002            // required for test cases
3003            m_configRfsPath = "";
3004            return;
3005        }
3006        if (!m_webAppRfsPath.endsWith(File.separator)) {
3007            // make sure that Path always ends with a separator, not always the case in different
3008            // environments since getServletContext().getRealPath("/") does not end with a "/" in
3009            // all servlet runtimes
3010            m_webAppRfsPath += File.separator;
3011        }
3012
3013        if (CmsStringUtil.isNotEmpty(System.getProperty(CmsSystemInfo.CONFIG_FOLDER_PROPERTY))) {
3014            m_configRfsPath = System.getProperty(CmsSystemInfo.CONFIG_FOLDER_PROPERTY);
3015        } else {
3016            m_configRfsPath = m_webAppRfsPath + CmsSystemInfo.FOLDER_WEBINF + CmsSystemInfo.FOLDER_CONFIG_DEFAULT;
3017        }
3018    }
3019}