org.pentaho.platform.web.hsqldb.HsqlDatabaseStarterBean.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.platform.web.hsqldb.HsqlDatabaseStarterBean.java

Source

/*!
 * This program is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
 * Foundation.
 *
 * You should have received a copy of the GNU Lesser General Public License along with this
 * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
 * or from the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * Copyright (c) 2002-2013 Pentaho Corporation..  All rights reserved.
 */

package org.pentaho.platform.web.hsqldb;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hsqldb.Server;
import org.hsqldb.server.ServerConfiguration;
import org.hsqldb.server.ServerConstants;
import org.hsqldb.server.ServerProperties;
import org.hsqldb.lib.FileUtil;
import org.hsqldb.persist.HsqlProperties;
import org.pentaho.platform.web.hsqldb.messages.Messages;

import java.io.IOException;
import java.net.ServerSocket;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * The purpose of this Java class is to startup a HSQLDB databases. This class should not installed in production
 * environments. This is for samples / demoing only.
 * 
 * You typically will configure a ServletContext parameter in your web.xml, named "hsqldb-databases" with a value that
 * follows this format: dbName@../path/to/database,@otherDbName@../path/to/other/database
 * 
 */
public class HsqlDatabaseStarterBean {

    private static final Log logger = LogFactory.getLog(HsqlDatabaseStarterBean.class);

    private Server hsqlServer;

    private int port = 9001; // Default Port
    private int failoverPort = port;

    private Map<String, String> databases = new LinkedHashMap<String, String>();

    private boolean allowFailoverToDefaultPort;

    protected boolean checkPort() {
        if ((port < 0) || (port > 65535)) {
            if (allowFailoverToDefaultPort) {
                logger.error(Messages.getErrorString("HsqlDatabaseStarterBean.ERROR_0004_INVALID_PORT", //$NON-NLS-1$
                        "" + failoverPort));
                port = failoverPort;
            } else {
                return logFailure("HsqlDatabaseStarterBean.ERROR_0004_INVALID_PORT", "" + failoverPort); //$NON-NLS-1$
            }
        }

        try {
            ServerSocket sock = new ServerSocket(port);
            sock.close();
        } catch (IOException ex1) {
            if (port == failoverPort) {
                return logFailure("HsqlDatabaseStarterBean.ERROR_0006_DEFAULT_PORT_IN_USE"); //$NON-NLS-1$
            } else {
                if (allowFailoverToDefaultPort) {
                    logger.error(Messages.getErrorString("HsqlDatabaseStarterBean.ERROR_0005_SPECIFIED_PORT_IN_USE", //$NON-NLS-1$
                            Integer.toString(port), "" + failoverPort));
                    port = failoverPort;
                    try {
                        ServerSocket sock = new ServerSocket(port);
                        sock.close();
                    } catch (IOException ex2) {
                        return logFailure("HsqlDatabaseStarterBean.ERROR_0006_DEFAULT_PORT_IN_USE"); //$NON-NLS-1$
                    }
                } else {
                    return logFailure("HsqlDatabaseStarterBean.ERROR_0008_SPECIFIED_PORT_IN_USE_NO_FAILOVER", //$NON-NLS-1$
                            Integer.toString(port));
                }
            }
        }
        return true;
    }

    // Facilitate test cases
    protected HsqlProperties getServerProperties(String[] args) {
        // From HSQLDB Server.java main method...
        String propsPath = FileUtil.getFileUtil().canonicalOrAbsolutePath("server"); //$NON-NLS-1$
        HsqlProperties fileProps = ServerConfiguration.getPropertiesFromFile(ServerConstants.SC_PROTOCOL_HSQL,
                propsPath, ".properties");
        HsqlProperties props = fileProps == null ? new HsqlProperties() : fileProps;
        HsqlProperties stringProps = null;

        try {
            stringProps = HsqlProperties.argArrayToProps(args, "server");
            props.addProperties(stringProps);
        } catch (ArrayIndexOutOfBoundsException ex) {
            logger.error(Messages.getErrorString("HsqlDatabaseStarterBean.ERROR_0001_INVALID_PARAMETERS")); //$NON-NLS-1$
            ex.printStackTrace();
            logger.warn(Messages.getString("HsqlDatabaseStarterBean.WARN_NO_DATABASES")); //$NON-NLS-1$
            return null;
        }
        return props;
    }

    // Facilitate test cases
    protected Server getNewHSQLDBServer() {
        return new Server();
    }

    /**
     * Starts hsqldb databases.
     * 
     * @return true if the server was started properly.
     */
    public boolean start() {
        if (!checkPort()) {
            return false;
        }
        ArrayList<String> startupArguments = getStartupArguments();

        String[] args = startupArguments.toArray(new String[] {});

        if (logger.isTraceEnabled()) {
            logger.trace("Assembled parameters"); //$NON-NLS-1$
            for (int i = 0; i < args.length; i++) {
                logger.trace(String.format("  args[%d]=%s", i, args[i])); //$NON-NLS-1$
            }
        }

        HsqlProperties props = getServerProperties(args);
        if (props == null) { // If props failed, return
            return false;
        }

        hsqlServer = getNewHSQLDBServer();

        try {
            hsqlServer.setProperties(props);
        } catch (Exception e) {
            logger.error(Messages.getErrorString("HsqlDatabaseStarterBean.ERROR_0002_INVALID_CONFIGURATION")); //$NON-NLS-1$
            e.printStackTrace();
            logger.warn(Messages.getString("HsqlDatabaseStarterBean.WARN_NO_DATABASES")); //$NON-NLS-1$
            return false;
        }
        hsqlServer.start();
        return hsqlServer.getState() == ServerConstants.SERVER_STATE_ONLINE;
    }

    /**
     * Stops the hsqldb databases.
     * 
     * @return true if the server stopped properly.
     */
    public boolean stop() {

        if (hsqlServer != null) {
            try {
                logger.debug("Stopping embedded hsqldb databases"); //$NON-NLS-1$
                logger.debug("Signaling connection close..."); //$NON-NLS-1$
                hsqlServer.signalCloseAllServerConnections();
                logger.debug("Stopping server listener threads.."); //$NON-NLS-1$
                hsqlServer.stop();
                int times = 0;
                logger.debug("Waiting for embedded server to complete shut down tasks..."); //$NON-NLS-1$
                // Give it about 15 or so seconds to quit...
                while ((hsqlServer.getState() != ServerConstants.SERVER_STATE_SHUTDOWN) && (times < 100)) {
                    try {
                        Thread.sleep(times + 1 * 100);
                    } catch (InterruptedException e) {
                        //ignore
                    }
                    times++;
                }
                if (hsqlServer.getState() != ServerConstants.SERVER_STATE_SHUTDOWN) {
                    logger.error(Messages.getErrorString("HsqlDatabaseStarterBean.ERROR_0003_DID_NOT_STOP")); //$NON-NLS-1$
                    return false;
                }
                return true;
            } finally {
                hsqlServer = null;
            }
        }
        return true;
    }

    private boolean logFailure(final String errorId) {
        logger.error(Messages.getErrorString(errorId));
        logger.warn(Messages.getString("HsqlDatabaseStarterBean.WARN_NO_DATABASES")); //$NON-NLS-1$
        return false;
    }

    private boolean logFailure(final String errorId, String param) {
        logger.error(Messages.getErrorString(errorId, param));
        logger.warn(Messages.getString("HsqlDatabaseStarterBean.WARN_NO_DATABASES")); //$NON-NLS-1$
        return false;
    }

    protected ArrayList<String> getStartupArguments() {
        ArrayList<String> rtnArgsList = new ArrayList<String>();

        if (port != 9001) {
            rtnArgsList.add("-port"); //$NON-NLS-1$
            rtnArgsList.add(Integer.toString(port));
        }
        // Prevent system.exit(0);
        rtnArgsList.add("-no_system_exit"); //$NON-NLS-1$
        rtnArgsList.add("true"); //$NON-NLS-1$

        int idx = 0;
        for (Map.Entry<String, String> entry : databases.entrySet()) {
            rtnArgsList.add("-database." + idx); //$NON-NLS-1$
            rtnArgsList.add(entry.getValue());

            rtnArgsList.add("-dbname." + idx); //$NON-NLS-1$
            rtnArgsList.add(entry.getKey());

            logger.debug(MessageFormat.format("Hsqldb database {0} configured to start with name {1}", //$NON-NLS-1$
                    entry.getValue(), entry.getKey()));
            idx++;
        }

        return rtnArgsList;
    }

    /*
     * Getters and Setters
     */

    public void setPort(int value) {
        port = value;
    }

    public int getPort() {
        return port;
    }

    public void setFailoverPort(int value) {
        failoverPort = value;
    }

    public int getFailoverPort() {
        return failoverPort;
    }

    public Map<String, String> getDatabases() {
        return databases;
    }

    public void setDatabases(Map<String, String> databases) {
        this.databases = databases;
    }

    public void setAllowPortFailover(boolean value) {
        allowFailoverToDefaultPort = value;
    }

    public boolean getAllowPortFailover() {
        return allowFailoverToDefaultPort;
    }

}