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