001/*
002 * File   : $Source$
003 * Date   : $Date$
004 * Version: $Revision$
005 *
006 * This library is part of OpenCms -
007 * the Open Source Content Management System
008 *
009 * Copyright (C) 2002 - 2009 Alkacon Software (http://www.alkacon.com)
010 *
011 * This library is free software; you can redistribute it and/or
012 * modify it under the terms of the GNU Lesser General Public
013 * License as published by the Free Software Foundation; either
014 * version 2.1 of the License, or (at your option) any later version.
015 *
016 * This library is distributed in the hope that it will be useful,
017 * but WITHOUT ANY WARRANTY; without even the implied warranty of
018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019 * Lesser General Public License for more details.
020 *
021 * For further information about Alkacon Software, please see the
022 * company website: http://www.alkacon.com
023 *
024 * For further information about OpenCms, please see the
025 * project website: http://www.opencms.org
026 *
027 * You should have received a copy of the GNU Lesser General Public
028 * License along with this library; if not, write to the Free Software
029 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
030 */
031
032package org.opencms.setup;
033
034import org.opencms.main.CmsLog;
035import org.opencms.setup.comptest.CmsSetupTestResult;
036import org.opencms.setup.comptest.CmsSetupTests;
037import org.opencms.util.CmsStringUtil;
038
039import java.io.File;
040import java.io.PrintStream;
041import java.util.Date;
042import java.util.List;
043import java.util.Map;
044
045import org.apache.commons.logging.Log;
046
047/**
048 * A bean to perform a OpenCms setup automatically.<p>
049 *
050 * @since 9.0
051 */
052public class CmsAutoSetup {
053
054    /** The log object for this class. */
055    private static final Log LOG = CmsLog.getLog(CmsAutoSetup.class);
056
057    /** A constant for the path, where the "setup.properties" files is placed on the local file system. */
058    private static final String PARAM_CONFIG_PATH = "-path";
059
060    /** Set this parameter to create DB and tables only. */
061    private static final String PARAM_DB_ONLY = "-dbonly";
062
063    /** Horizontal ruler - ASCII style. */
064    private static final String HR = "-----------------------------------------------------------";
065
066    /** The setup bean. */
067    private CmsSetupBean m_bean;
068
069    /** The setup properties to use. */
070    private CmsAutoSetupProperties m_props;
071
072    /**
073     * A bean for a automatically performed setup of OpenCms.<p>
074     *
075     * @param props the properties to use
076     */
077    public CmsAutoSetup(CmsAutoSetupProperties props) {
078
079        m_props = props;
080        m_bean = new CmsSetupBean();
081        m_bean.init(props.getSetupWebappPath(), props.getServeltMapping(), props.getSetupDefaultWebappName());
082    }
083
084    /**
085     * Main program entry point when started via the command line.<p>
086     *
087     * @param args parameters passed to the application via the command line
088     */
089    public static void main(String[] args) {
090
091        System.out.println();
092        System.out.println(HR);
093        System.out.println("OpenCms setup started at: " + new Date(System.currentTimeMillis()));
094        System.out.println(HR);
095        System.out.println();
096
097        String path = null;
098
099        boolean setupDBOnly = false;
100        if ((args.length > 0) && (args[0] != null)) {
101            for (int i = 0; i < args.length; i++) {
102                if (args[i] != null) {
103                    if (PARAM_CONFIG_PATH.equals(args[i]) && (args.length > (i + 1))) {
104                        path = args[i + 1];
105                    } else if (args[i].startsWith(PARAM_CONFIG_PATH)) {
106                        path = args[i].substring(PARAM_CONFIG_PATH.length()).trim();
107                    } else if (PARAM_DB_ONLY.equals(args[i])) {
108                        setupDBOnly = true;
109                    }
110                }
111            }
112        }
113        if ((null != path) && (new File(path).exists())) {
114            System.out.println("Using config file: " + path + "\n");
115            try {
116                CmsAutoSetupProperties props = new CmsAutoSetupProperties(path);
117                System.out.println("Webapp path     : " + props.getSetupWebappPath());
118                System.out.println("Ethernet address: " + props.getEthernetAddress());
119                System.out.println("Server URL      : " + props.getServerUrl());
120                System.out.println("Server name     : " + props.getServerName());
121                System.out.println("Show progress   : " + props.isShowProgress());
122                System.out.println();
123                for (Map.Entry<String, String[]> entry : props.toParameterMap().entrySet()) {
124                    System.out.println(entry.getKey() + " = " + entry.getValue()[0]);
125                }
126                System.out.println();
127                CmsAutoSetup setup = new CmsAutoSetup(props);
128                if (setupDBOnly) {
129                    System.out.println("Creating DB and tables only.");
130                    System.out.println(
131                        "The opencms.properties file will not be written and no modules will be installed.\n\n");
132                    setup.initSetupBean();
133                    setup.setupDB();
134                } else {
135                    setup.run();
136                }
137            } catch (Exception e) {
138                System.out.println("An error occurred during the setup process with the following error message:");
139                System.out.println(e.getMessage());
140                System.out.println("Please have a look into the opencms log file for detailed information.");
141                LOG.error(e.getMessage(), e);
142                System.exit(1);
143            }
144        } else {
145            System.out.println("");
146            System.err.println(
147                "Config file not found, please specify a path where to find the setup properties to use.");
148            System.out.println("Usage example (Unix): setup.sh  -path /path/to/setup.properties");
149            System.out.println("Usage example (Win):  setup.bat -path C:\\setup.properties");
150            System.out.println("");
151            System.out.println("Have a look at the package: org/opencms/setup/setup.properties.example");
152            System.out.println("in order to find a sample configuration file.");
153        }
154        System.exit(0);
155    }
156
157    /**
158     * Initializes the setup bean with the auto setup properties.<p>
159     */
160    public void initSetupBean() {
161
162        m_bean.setAutoMode(true);
163        m_bean.setDatabase(m_props.getDbProduct());
164        m_bean.setDb(m_props.getDbName());
165        m_bean.setDbCreateUser(m_props.getCreateUser());
166        m_bean.setDbCreatePwd(m_props.getCreatePwd() == null ? "" : m_props.getCreatePwd());
167        m_bean.setDbWorkUser(m_props.getWorkerUser());
168        m_bean.setDbWorkPwd(m_props.getWorkerPwd() == null ? "" : m_props.getWorkerPwd());
169        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(m_props.getConStrParams())) {
170            m_bean.setDbConStrParams(m_props.getConStrParams());
171        }
172        m_bean.setDbCreateConStr(m_props.getConnectionUrl());
173        m_bean.setDbWorkConStr(m_props.getConnectionUrl());
174        m_bean.setDbParamaters(m_props.toParameterMap(), m_props.getDbProvider(), "/opencms/", null);
175
176        m_bean.setServerName(m_props.getServerName());
177        m_bean.setWorkplaceSite(m_props.getServerUrl());
178        m_bean.setEthernetAddress(
179            m_props.getEthernetAddress() == null ? CmsStringUtil.getEthernetAddress() : m_props.getEthernetAddress());
180
181        // initialize the available modules
182        m_bean.getAvailableModules();
183        List<String> componentsToInstall = m_props.getInstallComponents();
184        String modules = m_bean.getComponentModules(componentsToInstall);
185        m_bean.setInstallModules(modules);
186    }
187
188    /**
189     * Performs the setup.<p>
190     *
191     * @throws Exception in case the setup fails
192     */
193    public void run() throws Exception {
194
195        if (m_bean.getWizardEnabled()) {
196
197            long timeStarted = System.currentTimeMillis();
198
199            CmsSetupTests setupTests = new CmsSetupTests();
200            setupTests.runTests(m_bean, "No server info present, because this test is running in auto mode.");
201            if (setupTests.isRed()) {
202                for (CmsSetupTestResult result : setupTests.getTestResults()) {
203                    if (result.isRed()) {
204                        throw new Exception(result.getInfo());
205                    }
206                }
207            }
208            if (CmsStringUtil.isEmpty(m_bean.getDatabaseConfigPage(m_props.getDbProduct()))) {
209                throw new Exception("DB product: " + m_props.getDbProduct() + " not supported.");
210            }
211            System.out.println("System requirements tested successfully.");
212
213            initSetupBean();
214
215            setupDB();
216
217            if (m_bean.prepareStep8()) {
218                System.out.println("Configuration files written successfully.");
219                m_bean.prepareStep8b();
220            }
221
222            if (m_props.isShowProgress()) {
223                // show a simple progress indicator
224                // this is only needed in case you do an automated installation and watch the console
225                System.out.println("\nImporting modules:");
226                // System.out will be redirected by the setup bean, so keep a reference for the progress indicator
227                PrintStream out = System.out;
228                int timecount = 0;
229                StringBuffer points = new StringBuffer(100);
230                while (m_bean.isImportRunning()) {
231                    if ((++timecount % 10) == 0) {
232                        points.append('.');
233                        out.println(points);
234                    }
235                    Thread.sleep(500);
236                }
237                System.out.println("\nModule import is finished!");
238            } else {
239                // no progress indicator
240                System.out.println("Importing modules.");
241                while (m_bean.isImportRunning()) {
242                    Thread.sleep(500);
243                }
244            }
245            System.out.println("Modules imported successfully.");
246
247            m_bean.prepareStep10();
248            System.out.println();
249            System.out.println(HR);
250            System.out.println(
251                "OpenCms setup finished successfully in "
252                    + Math.round((System.currentTimeMillis() - timeStarted) / 1000)
253                    + " seconds.");
254            System.out.println(HR);
255        } else {
256            throw new Exception("Error starting Alkacon OpenCms setup wizard.");
257        }
258    }
259
260    /**
261     * Creates DB and tables when necessary.<p>
262     *
263     * @throws Exception in case creating DB or tables fails
264     */
265    public void setupDB() throws Exception {
266
267        if (m_bean.isInitialized()) {
268            System.out.println("Setup-Bean initialized successfully.");
269            CmsSetupDb db = new CmsSetupDb(m_bean.getWebAppRfsPath());
270            try {
271                // try to connect as the runtime user
272                db.setConnection(
273                    m_bean.getDbDriver(),
274                    m_bean.getDbWorkConStr(),
275                    m_bean.getDbConStrParams(),
276                    m_bean.getDbWorkUser(),
277                    m_bean.getDbWorkPwd(),
278                    false);
279                if (!db.noErrors()) {
280                    // try to connect as the setup user
281                    db.closeConnection();
282                    db.clearErrors();
283                    db.setConnection(
284                        m_bean.getDbDriver(),
285                        m_bean.getDbCreateConStr(),
286                        m_bean.getDbConStrParams(),
287                        m_bean.getDbCreateUser(),
288                        m_bean.getDbCreatePwd());
289                }
290                if (!db.noErrors() || !m_bean.validateJdbc()) {
291                    throw new Exception("DB Connection test faild.");
292                }
293            } finally {
294                db.clearErrors();
295                db.closeConnection();
296            }
297        }
298
299        System.out.println("DB connection tested successfully.");
300
301        CmsSetupDb db = null;
302        boolean dbExists = false;
303        if (m_bean.isInitialized()) {
304            if (m_props.isCreateDb() || m_props.isCreateTables()) {
305                db = new CmsSetupDb(m_bean.getWebAppRfsPath());
306                // check if database exists
307                if (m_bean.getDatabase().startsWith("oracle")
308                    || m_bean.getDatabase().startsWith("db2")
309                    || m_bean.getDatabase().startsWith("as400")) {
310                    db.setConnection(
311                        m_bean.getDbDriver(),
312                        m_bean.getDbWorkConStr(),
313                        m_bean.getDbConStrParams(),
314                        m_bean.getDbWorkUser(),
315                        m_bean.getDbWorkPwd());
316                } else {
317                    db.setConnection(
318                        m_bean.getDbDriver(),
319                        m_bean.getDbWorkConStr(),
320                        m_bean.getDbConStrParams(),
321                        m_bean.getDbCreateUser(),
322                        m_bean.getDbCreatePwd(),
323                        false);
324                    dbExists = db.noErrors();
325                    if (dbExists) {
326                        db.closeConnection();
327                    } else {
328                        db.clearErrors();
329                    }
330                }
331                if (!dbExists || m_props.isDropDb()) {
332                    db.closeConnection();
333                    if (!m_bean.getDatabase().startsWith("db2") && !m_bean.getDatabase().startsWith("as400")) {
334                        db.setConnection(
335                            m_bean.getDbDriver(),
336                            m_bean.getDbCreateConStr(),
337                            m_bean.getDbConStrParams(),
338                            m_bean.getDbCreateUser(),
339                            m_bean.getDbCreatePwd());
340                    }
341                }
342            }
343        }
344        if (!m_props.isCreateDb() && !m_props.isCreateTables() && !dbExists) {
345            throw new Exception("You have not created the Alkacon OpenCms database.");
346        }
347        if (dbExists && m_props.isCreateTables() && !m_props.isDropDb() && (db != null)) {
348            throw new Exception("You have selected to not drop existing DBs, but a DB with the given name exists.");
349        }
350        if (dbExists && m_props.isCreateDb() && m_props.isDropDb() && (db != null)) {
351            // drop the DB
352            db.closeConnection();
353            db.setConnection(
354                m_bean.getDbDriver(),
355                m_bean.getDbWorkConStr(),
356                m_bean.getDbConStrParams(),
357                m_bean.getDbCreateUser(),
358                m_bean.getDbCreatePwd());
359            db.dropDatabase(m_bean.getDatabase(), m_bean.getReplacer());
360            if (!db.noErrors()) {
361                for (String error : db.getErrors()) {
362                    System.err.println(error + "\n");
363                    System.err.println(HR + "\n");
364                }
365                db.clearErrors();
366                throw new Exception("Error ocurred while dropping the DB!");
367            }
368            System.out.println("Database dropped successfully.");
369        }
370
371        if (m_props.isCreateDb() && (db != null)) {
372            // Create Database
373            db.createDatabase(m_bean.getDatabase(), m_bean.getReplacer());
374            if (!db.noErrors()) {
375                for (String error : db.getErrors()) {
376                    System.err.println(error + "\n");
377                    System.err.println(HR + "\n");
378                }
379                db.clearErrors();
380                throw new Exception("Error ocurred while creating the DB!");
381            }
382            db.closeConnection();
383            System.out.println("Database created successfully.");
384        }
385
386        if (m_props.isCreateTables() && (db != null)) {
387            db.setConnection(
388                m_bean.getDbDriver(),
389                m_bean.getDbWorkConStr(),
390                m_bean.getDbConStrParams(),
391                m_bean.getDbWorkUser(),
392                m_bean.getDbWorkPwd());
393            //Drop Tables (intentionally quiet)
394            db.dropTables(m_bean.getDatabase());
395            db.clearErrors();
396            db.closeConnection();
397            // reopen the connection in order to display errors
398            db.setConnection(
399                m_bean.getDbDriver(),
400                m_bean.getDbWorkConStr(),
401                m_bean.getDbConStrParams(),
402                m_bean.getDbWorkUser(),
403                m_bean.getDbWorkPwd());
404            //Create Tables
405            db.createTables(m_bean.getDatabase(), m_bean.getReplacer());
406            if (!db.noErrors()) {
407                for (String error : db.getErrors()) {
408                    System.err.println(error + "\n");
409                    System.err.println(HR + "\n");
410                }
411                db.clearErrors();
412                throw new Exception("Error ocurred while creating tables.");
413            }
414            db.closeConnection();
415            System.out.println("Tables created successfully.");
416        }
417        if (db != null) {
418            db.closeConnection();
419        }
420        System.out.println("Database setup was successful.");
421    }
422}