Search in sources :

Example 1 with DBSettingMismatchException

use of soc.server.database.DBSettingMismatchException in project JSettlers2 by jdmonin.

the class SOCServer method initSocServer.

/**
 * Common init for all constructors.
 * Prints some progress messages to {@link System#err}.
 * Sets game option default values via {@link #init_propsSetGameopts(Properties)}.
 * Calls {@link SOCMessageDispatcher#setServer(SOCServer, SOCGameListAtServer)}.
 * Starts all server threads except the main thread, unless constructed in Utility Mode
 * ({@link #hasUtilityModeProp}).
 * If {@link #PROP_JSETTLERS_STARTROBOTS} is specified, those aren't started until {@link #serverUp()}.
 *<P>
 * If there are problems with the network setup ({@link #error} != null),
 * this method will throw {@link SocketException}.
 *<P>
 * If problems running a {@link SOCDBHelper#PROP_JSETTLERS_DB_SCRIPT_SETUP db setup script}
 * or {@link SOCDBHelper#PROP_JSETTLERS_DB_UPGRADE__SCHEMA schema upgrade},
 * this method will throw {@link SQLException}.
 *<P>
 * If we can't connect to a database, but it looks like we need one (because
 * {@link SOCDBHelper#PROP_JSETTLERS_DB_URL}, {@link SOCDBHelper#PROP_JSETTLERS_DB_DRIVER}
 * or {@link SOCDBHelper#PROP_JSETTLERS_DB_JAR} is specified in {@code props}),
 * or there are other problems with DB-related contents of {@code props}
 * (see {@link SOCDBHelper#initialize(String, String, Properties)}; exception's {@link Throwable#getCause()}
 * will be an {@link IllegalArgumentException} or {@link DBSettingMismatchException}) this method will
 * print details to {@link System#err} and throw {@link SQLException}.
 *
 *<H5>Utility Mode</H5>
 * If a db setup script runs successfully, or {@code props} contains the password reset parameter
 * {@link SOCDBHelper#PROP_IMPL_JSETTLERS_PW_RESET}, the server does not complete its startup;
 * this method will set {@link #hasUtilityModeProp} and (only for setup script) throw {@link EOFException}.
 *<P>
 * For the password reset parameter, the caller will need to prompt for and change the password;
 * this method will not do that.
 *
 * @param databaseUserName Used for DB connect - not retained
 * @param databasePassword Used for DB connect - not retained
 * @throws SocketException  If a network setup problem occurs
 * @throws EOFException   If db setup script ran successfully and server should exit now;
 *       thrown in Utility Mode ({@link #hasUtilityModeProp}).
 * @throws SQLException   If db setup script fails, or need db but can't connect
 * @throws IllegalArgumentException  If {@code props} contains game options ({@code jsettlers.gameopt.*})
 *       with bad syntax. See {@link #PROP_JSETTLERS_GAMEOPT_PREFIX} for expected syntax.
 *       See {@link #parseCmdline_DashedArgs(String[])} for how game option properties are checked.
 *       Also thrown if {@link SOCDBHelper#PROP_JSETTLERS_DB_UPGRADE__SCHEMA} flag
 *       is set, but {@link SOCDBHelper#isSchemaLatestVersion()}. {@link Throwable#getMessage()} will have
 *       problem details for any {@code IllegalArgumentException} thrown here.
 * @throws IllegalStateException  If {@link Version#versionNumber()} returns 0 (packaging error)
 * @since 1.1.00
 */
private void initSocServer(String databaseUserName, String databasePassword) throws SocketException, EOFException, SQLException, IllegalArgumentException, IllegalStateException {
    Version.printVersionText(System.err, "Java Settlers Server ");
    if (Version.versionNumber() == 0) {
        throw new IllegalStateException("Packaging error: Cannot determine JSettlers version");
    }
    /**
     * If true, connect to DB (like validate_config_mode) but start no threads.
     * Will run the requested tests and exit.
     */
    final boolean test_mode_with_db = getConfigBoolProperty(PROP_JSETTLERS_TEST_DB, false);
    final boolean validate_config_mode = getConfigBoolProperty(PROP_JSETTLERS_TEST_VALIDATE__CONFIG, false);
    final boolean wants_upg_schema = getConfigBoolProperty(SOCDBHelper.PROP_JSETTLERS_DB_UPGRADE__SCHEMA, false);
    boolean db_test_bcrypt_mode = false;
    final String val = props.getProperty(SOCDBHelper.PROP_JSETTLERS_DB_BCRYPT_WORK__FACTOR);
    if (val != null) {
        db_test_bcrypt_mode = (val.equalsIgnoreCase("test"));
        if (db_test_bcrypt_mode)
            // make sure DBH.initialize won't try to parse "test" as an integer
            props.remove(SOCDBHelper.PROP_JSETTLERS_DB_BCRYPT_WORK__FACTOR);
    }
    // Set this flag as early as possible
    hasUtilityModeProp = validate_config_mode || test_mode_with_db || wants_upg_schema || db_test_bcrypt_mode || (null != props.getProperty(SOCDBHelper.PROP_JSETTLERS_DB_SCRIPT_SETUP)) || props.containsKey(SOCDBHelper.PROP_JSETTLERS_DB_SETTINGS) || (null != props.getProperty(SOCDBHelper.PROP_IMPL_JSETTLERS_PW_RESET));
    if (test_mode_with_db)
        System.err.println("* DB Test Mode: Will run tests and exit.");
    if (validate_config_mode)
        System.err.println("* Config Validation Mode: Checking configuration and exiting.");
    /* Check for problems during super setup (such as port already in use).
         * Ignore net errors if we're running a DB setup script and then exiting.
         */
    if ((error != null) && !hasUtilityModeProp) {
        final String errMsg = "* Exiting due to network setup problem: " + error.toString();
        throw new SocketException(errMsg);
    }
    if (!props.containsKey(PROP_JSETTLERS_STARTROBOTS))
        props.setProperty(PROP_JSETTLERS_STARTROBOTS, Integer.toString(SOC_STARTROBOTS_DEFAULT));
    // Set game option defaults from any jsettlers.gameopt.* properties found.
    // If problems found, throws IllegalArgumentException with details.
    // Does not apply scenario's game options, if any.
    // Ignores unknown scenario ("SC"), see init_checkScenarioOpts for that.
    init_propsSetGameopts(props);
    int v = getConfigIntProperty(PROP_JSETTLERS_BOTS_FAST__PAUSE__PERCENT, -1);
    if (v != -1) {
        if ((v >= 0) && (v <= 100))
            SOCRobotBrain.BOTS_ONLY_FAST_PAUSE_FACTOR = .01f * v;
        else
            throw new IllegalArgumentException("Error: Property out of range (0 to 100): " + PROP_JSETTLERS_BOTS_FAST__PAUSE__PERCENT);
    }
    ((SOCMessageDispatcher) inboundMsgDispatcher).setServer(this, srvMsgHandler, gameList);
    if (allowDebugUser) {
        System.err.println("Warning: Remote debug commands are allowed.");
    }
    /**
     * See if the user specified a non-random robot cookie value.
     */
    if (props.containsKey(PROP_JSETTLERS_BOTS_COOKIE)) {
        final String cook = props.getProperty(PROP_JSETTLERS_BOTS_COOKIE).trim();
        if (cook.length() > 0) {
            if (SOCMessage.isSingleLineAndSafe(cook)) {
                robotCookie = cook;
            } else {
                final String errmsg = "Error: The robot cookie value (param " + PROP_JSETTLERS_BOTS_COOKIE + ") can't contain comma or pipe characters.";
                System.err.println(errmsg);
                throw new IllegalArgumentException(errmsg);
            }
        }
    // else robotCookie remains null
    } else {
        robotCookie = generateRobotCookie();
    }
    final boolean accountsRequired = getConfigBoolProperty(PROP_JSETTLERS_ACCOUNTS_REQUIRED, false);
    /**
     * Try to connect to the DB, if any.
     * Running SOCDBHelper.initialize(..) will handle some Utility Mode properties
     * like PROP_JSETTLERS_DB_SETTINGS if present.
     */
    boolean db_err_printed = false;
    try {
        SOCDBHelper.initialize(databaseUserName, databasePassword, props);
        features.add(SOCServerFeatures.FEAT_ACCTS);
        System.err.println("User database initialized.");
        if (props.getProperty(SOCDBHelper.PROP_JSETTLERS_DB_SCRIPT_SETUP) != null) {
            // the sql script was ran by initialize
            final String msg = "DB setup script successful";
            utilityModeMessage = msg;
            throw new EOFException(msg);
        }
        // set some DB-related SOCServer fields: acctsNotOpenRegButNoUsers, databaseUserAdmins
        initSocServer_dbParamFields(accountsRequired, wants_upg_schema);
        // check schema version, upgrade if requested:
        if (!SOCDBHelper.isSchemaLatestVersion()) {
            if (wants_upg_schema) {
                try {
                    SOCDBHelper.upgradeSchema(databaseUserAdmins);
                    String msg = "DB schema upgrade was successful";
                    if (SOCDBHelper.doesSchemaUpgradeNeedBGTasks())
                        msg += "; some upgrade tasks will complete in the background during normal server operation";
                    utilityModeMessage = msg;
                    throw new EOFException(msg);
                } catch (EOFException e) {
                    throw e;
                } catch (Exception e) {
                    db_err_printed = true;
                    if (e instanceof MissingResourceException)
                        System.err.println("* To begin schema upgrade, please fix and rerun: " + e.getMessage());
                    else
                        System.err.println(e);
                    if (e instanceof SQLException) {
                        throw (SQLException) e;
                    } else {
                        SQLException sqle = new SQLException("Error during DB schema upgrade");
                        sqle.initCause(e);
                        throw sqle;
                    }
                }
            } else {
                System.err.println("\n* Database schema upgrade is recommended: To upgrade, use -D" + SOCDBHelper.PROP_JSETTLERS_DB_UPGRADE__SCHEMA + "=Y command line flag.\n");
            }
        } else if (wants_upg_schema) {
            db_err_printed = true;
            final String errmsg = "* Cannot upgrade database schema: Already at latest version";
            System.err.println(errmsg);
            throw new IllegalArgumentException(errmsg);
        }
    // reminder: if props.getProperty(SOCDBHelper.PROP_IMPL_JSETTLERS_PW_RESET),
    // caller will need to prompt for and change the password
    } catch (// just a warning at this point; other code checks if db failed but is required
    SQLException sqle) {
        if (wants_upg_schema && db_err_printed) {
            throw sqle;
        }
        System.err.println("Warning: No user database available: " + sqle.getMessage());
        Throwable cause = sqle.getCause();
        while ((cause != null) && !(cause instanceof ClassNotFoundException)) {
            System.err.println("\t" + cause);
            cause = cause.getCause();
        }
        if (wants_upg_schema || (props.getProperty(SOCDBHelper.PROP_JSETTLERS_DB_SCRIPT_SETUP) != null)) {
            throw sqle;
        }
        String propReqDB = null;
        if (accountsRequired)
            propReqDB = PROP_JSETTLERS_ACCOUNTS_REQUIRED;
        else if (props.containsKey(PROP_JSETTLERS_ACCOUNTS_ADMINS))
            propReqDB = PROP_JSETTLERS_ACCOUNTS_ADMINS;
        if (propReqDB != null) {
            final String errMsg = "* Property " + propReqDB + " requires a database.";
            System.err.println(errMsg);
            System.err.println("\n* Exiting because current startup properties specify a database.");
            throw new SQLException(errMsg);
        }
        if (props.containsKey(SOCDBHelper.PROP_JSETTLERS_DB_URL) || props.containsKey(SOCDBHelper.PROP_JSETTLERS_DB_JAR) || props.containsKey(SOCDBHelper.PROP_JSETTLERS_DB_DRIVER)) {
            // If other db props were asked for, the user is expecting a DB.
            // So, fail instead of silently continuing without it.
            System.err.println("* Exiting because current startup properties specify a database.");
            throw sqle;
        }
        if (props.containsKey(SOCDBHelper.PROP_IMPL_JSETTLERS_PW_RESET)) {
            System.err.println("* Exiting because --pw-reset requires a database.");
            throw sqle;
        }
        System.err.println("Users will not be authenticated.");
    } catch (// successfully ran script or schema upgrade, signal to exit
    EOFException eox) {
        throw eox;
    } catch (// error from requested script
    IOException iox) {
        System.err.println("\n* Could not run database setup script: " + iox.getMessage());
        Throwable cause = iox.getCause();
        while ((cause != null) && !(cause instanceof ClassNotFoundException)) {
            System.err.println("\t" + cause);
            cause = cause.getCause();
        }
        try {
            SOCDBHelper.cleanup(true);
        } catch (SQLException x) {
        }
        SQLException sqle = new SQLException("Error running DB setup script");
        sqle.initCause(iox);
        throw sqle;
    } catch (IllegalArgumentException iax) {
        System.err.println("\n* Error in specified database properties: " + iax.getMessage());
        SQLException sqle = new SQLException("Error with DB props");
        sqle.initCause(iax);
        throw sqle;
    } catch (DBSettingMismatchException dx) {
        // initialize(..) already printed details to System.err
        System.err.println("\n* Mismatch between database settings and specified properties");
        SQLException sqle = new SQLException("DB settings mismatch");
        sqle.initCause(dx);
        throw sqle;
    }
    if (db_test_bcrypt_mode)
        SOCDBHelper.testBCryptSpeed();
    if (hasUtilityModeProp && !(test_mode_with_db || validate_config_mode)) {
        // <--- don't continue startup if Utility Mode ---
        return;
    }
    if (SOCDBHelper.isInitialized()) {
        if (accountsRequired)
            System.err.println("User database accounts are required for all players.");
        // https://bugs.eclipse.org/bugs/show_bug.cgi?id=38016  "WONTFIX/README" since 2007-07-18
        try {
            Runtime.getRuntime().addShutdownHook(new Thread() {

                @Override
                public void run() {
                    System.err.println("\n--\n-- shutdown; disconnecting from db --\n--\n");
                    System.err.flush();
                    try {
                        // Before disconnect, do a final check for unexpected DB settings changes
                        try {
                            SOCDBHelper.checkSettings(true, false);
                        } catch (Exception x) {
                        }
                        SOCDBHelper.cleanup(true);
                    } catch (SQLException x) {
                    }
                }
            });
        } catch (Throwable th) {
            // just a warning
            System.err.println("Warning: Could not register shutdown hook for database disconnect. Check java security settings.");
        }
    }
    startTime = System.currentTimeMillis();
    numberOfGamesStarted = 0;
    numberOfGamesFinished = 0;
    numberOfUsers = 0;
    clientPastVersionStats = new HashMap<Integer, Integer>();
    numRobotOnlyGamesRemaining = getConfigIntProperty(PROP_JSETTLERS_BOTS_BOTGAMES_TOTAL, 0);
    if (numRobotOnlyGamesRemaining > 0) {
        final int n = SOCGame.MAXPLAYERS_STANDARD;
        if (n > getConfigIntProperty(PROP_JSETTLERS_STARTROBOTS, 0)) {
            final String errmsg = ("*** To start robot-only games, server needs at least " + n + " robots started.");
            System.err.println(errmsg);
            throw new IllegalArgumentException(errmsg);
        }
    }
    if (CLIENT_MAX_CREATE_CHANNELS != 0)
        features.add(SOCServerFeatures.FEAT_CHANNELS);
    /**
     * Start various threads.
     */
    if (!(test_mode_with_db || validate_config_mode)) {
        serverRobotPinger = new SOCServerRobotPinger(this, robots);
        serverRobotPinger.start();
        gameTimeoutChecker = new SOCGameTimeoutChecker(this);
        gameTimeoutChecker.start();
    }
    this.databaseUserName = databaseUserName;
    this.databasePassword = databasePassword;
    /**
     * Print game options if we've set them on commandline, or if
     * any option defaults require a minimum client version.
     */
    if (hasSetGameOptions || validate_config_mode || (SOCVersionedItem.itemsMinimumVersion(SOCGameOption.getAllKnownOptions()) > -1)) {
        // wait for other output to appear first
        Thread.yield();
        try {
            Thread.sleep(200);
        } catch (InterruptedException ie) {
        }
        printGameOptions();
    }
    if (getConfigBoolProperty(PROP_JSETTLERS_BOTS_SHOWCOOKIE, false))
        System.err.println("Robot cookie: " + robotCookie);
    if (validate_config_mode) {
        // Print configured known properties (ignore if not in PROPS_LIST);
        // this also gives them in the same order as PROPS_LIST,
        // which is the same order --help prints them out.
        System.err.println();
        System.err.println("-- Configured server properties: --");
        for (int i = 0; i < PROPS_LIST.length; i += 2) {
            final String pkey = PROPS_LIST[i];
            if ((!pkey.equals(PROP_JSETTLERS_TEST_VALIDATE__CONFIG)) && props.containsKey(pkey))
                System.err.format("%-40s %s\n", pkey, props.getProperty(pkey));
        }
        System.err.println();
        System.err.println("* Config Validation Mode: No problems found.");
    }
    if (test_mode_with_db) {
        // failures/errors throw SQLException for our caller to catch
        SOCDBHelper.testDBHelper();
    }
    if (!(test_mode_with_db || validate_config_mode)) {
        System.err.print("The server is ready.");
        if (port > 0)
            System.err.print(" Listening on port " + port);
        System.err.println();
        if (SOCDBHelper.isInitialized() && SOCDBHelper.doesSchemaUpgradeNeedBGTasks())
            // includes 5-second sleep before conversions begin
            SOCDBHelper.startSchemaUpgradeBGTasks();
    }
    System.err.println();
}
Also used : SocketException(java.net.SocketException) SQLException(java.sql.SQLException) DBSettingMismatchException(soc.server.database.DBSettingMismatchException) MissingResourceException(java.util.MissingResourceException) IOException(java.io.IOException) MissingResourceException(java.util.MissingResourceException) EOFException(java.io.EOFException) DBSettingMismatchException(soc.server.database.DBSettingMismatchException) SocketException(java.net.SocketException) SQLException(java.sql.SQLException) IOException(java.io.IOException) EOFException(java.io.EOFException)

Aggregations

EOFException (java.io.EOFException)1 IOException (java.io.IOException)1 SocketException (java.net.SocketException)1 SQLException (java.sql.SQLException)1 MissingResourceException (java.util.MissingResourceException)1 DBSettingMismatchException (soc.server.database.DBSettingMismatchException)1