Source Code Cross Referenced for Server.java in  » Database-DBMS » hsql » org » hsqldb » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database DBMS » hsql » org.hsqldb 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* Copyright (c) 2001-2005, The HSQL Development Group
0002:         * All rights reserved.
0003:         *
0004:         * Redistribution and use in source and binary forms, with or without
0005:         * modification, are permitted provided that the following conditions are met:
0006:         *
0007:         * Redistributions of source code must retain the above copyright notice, this
0008:         * list of conditions and the following disclaimer.
0009:         *
0010:         * Redistributions in binary form must reproduce the above copyright notice,
0011:         * this list of conditions and the following disclaimer in the documentation
0012:         * and/or other materials provided with the distribution.
0013:         *
0014:         * Neither the name of the HSQL Development Group nor the names of its
0015:         * contributors may be used to endorse or promote products derived from this
0016:         * software without specific prior written permission.
0017:         *
0018:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019:         * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020:         * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021:         * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
0022:         * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0023:         * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0024:         * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0025:         * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0026:         * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0027:         * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0028:         * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0029:         */
0030:
0031:        package org.hsqldb;
0032:
0033:        import java.io.File;
0034:        import java.io.IOException;
0035:        import java.io.PrintWriter;
0036:        import java.net.ServerSocket;
0037:        import java.net.Socket;
0038:        import java.net.UnknownHostException;
0039:        import java.util.Enumeration;
0040:        import java.util.StringTokenizer;
0041:
0042:        import org.hsqldb.lib.ArrayUtil;
0043:        import org.hsqldb.lib.FileUtil;
0044:        import org.hsqldb.lib.HashSet;
0045:        import org.hsqldb.lib.Iterator;
0046:        import org.hsqldb.lib.StopWatch;
0047:        import org.hsqldb.lib.StringUtil;
0048:        import org.hsqldb.lib.WrapperIterator;
0049:        import org.hsqldb.lib.java.JavaSystem;
0050:        import org.hsqldb.persist.HsqlDatabaseProperties;
0051:        import org.hsqldb.persist.HsqlProperties;
0052:        import org.hsqldb.resources.BundleHandler;
0053:
0054:        // fredt@users 20020215 - patch 1.7.0
0055:        // methods reorganised to use new HsqlProperties class
0056:        // fredt@users 20020424 - patch 1.7.0 - shutdown without exit
0057:        // see the comments in ServerConnection.java
0058:        // unsaved@users 20021113 - patch 1.7.2 - SSL support
0059:        // boucherb@users 20030510-14 - 1.7.2 - SSL support moved to factory interface
0060:        // boucherb@users 20030510-14 - 1.7.2 - service control, JavaBean API
0061:        // fredt@users 20030916 - 1.7.2 - review, simplification and multiple DB's
0062:        // fredt@users 20040320 - 1.7.2 - review and correction
0063:        // fredt@users 20050225 - 1.8.0 - minor corrections
0064:        // fredt@users 20051231 - 1.8.1 - support for remote opening of databases
0065:
0066:        /**
0067:         * The HSQLDB HSQL protocol network database server. <p>
0068:         *
0069:         * A Server object acts as a network database server and is one way of using
0070:         * the client-server mode of HSQLDB Database Engine. Instances of this
0071:         * class handle native HSQL protocol connections exclusively, allowing database
0072:         * queries to be performed efficienly across the network.  Server's direct
0073:         * descendent, WebServer, handles HTTP protocol connections exclusively,
0074:         * allowing HSQL protocol to be tunneled over HTTP to avoid sandbox and
0075:         * firewall issues, albeit less efficiently. <p>
0076:         *
0077:         * There are a number of ways to configure and start a Server instance. <p>
0078:         *
0079:         * When started from the command line or programatically via the main(String[])
0080:         * method, configuration occurs in three phases, with later phases overriding
0081:         * properties set by previous phases:
0082:         *
0083:         * <ol>
0084:         *   <li>Upon construction, a Server object is assigned a set of default
0085:         *       properties. <p>
0086:         *
0087:         *   <li>If it exists, properties are loaded from a file named
0088:         *       'server.properties' in the present working directory. <p>
0089:         *
0090:         *   <li>The command line arguments (alternatively, the String[] passed to
0091:         *       main()) are parsed and used to further configure the Server's
0092:         *       properties. <p>
0093:         *
0094:         * </ol> <p>
0095:         *
0096:         * From the command line, the options are as follows: <p>
0097:         * <pre>
0098:         * +----------------+-------------+----------+------------------------------+
0099:         * |    OPTION      |    TYPE     | DEFAULT  |         DESCRIPTION          |
0100:         * +----------------+-------------+----------+------------------------------|
0101:         * | -?             | --          | --       | prints this message          |
0102:         * | -address       | name|number | any      | server inet address          |
0103:         * | -port          | number      | 9001/544 | port at which server listens |
0104:         * | -database.i    | [type]spec  | 0=test   | path of database i           |
0105:         * | -dbname.i      | alias       | --       | url alias for database i     |
0106:         * | -silent        | true|false  | true     | false => display all queries |
0107:         * | -trace         | true|false  | false    | display JDBC trace messages  |
0108:         * | -tls           | true|false  | false    | TLS/SSL (secure) sockets     |
0109:         * | -no_system_exit| true|false  | false    | do not issue System.exit()   |
0110:         * | -remote_open   | true|false  | false    | can open databases remotely  |
0111:         * +----------------+-------------+----------+------------------------------+
0112:         * </pre>
0113:         *
0114:         * The <em>database.i</em> and <em>dbname.i</em> options need further
0115:         * explanation:
0116:         *
0117:         * <ul>
0118:         *   <li>Multiple databases can be served by each instance of the Server.
0119:         *       The value of <em>i</em> is currently limited to the range 0..9,
0120:         *       allowing up to 10 different databases. Any number is this range
0121:         *       can be used.<p>
0122:         *
0123:         *   <li>The value assigned to <em>database.i</em> is interpreted using the
0124:         *       format <b>'[type]spec'</b>, where the optional <em>type</em> component
0125:         *       is one of <b>'file:'</b>, <b>'res:'</b> or <b>'mem:'</b> and the
0126:         *       <em>spec</em> component is interpreted in the context of the
0127:         *       <em>type</em> component.  <p>
0128:         *
0129:         *       If omitted, the <em>type</em> component is taken to be
0130:         *       <b>'file:'</b>.  <p>
0131:         *
0132:         *        A full description of how
0133:         *       <b>'[type]spec'</b> values are interpreted appears in the overview for
0134:         *       {@link org.hsqldb.jdbc.jdbcConnection jdbcConnection}. <p>
0135:         *
0136:         *   <li>The value assigned to <em>dbname.i</em> is taken to be the key used to
0137:         *       look up the desired database instance and thus corresponds to the
0138:         *       <b>&lt;alias&gt;</b> component of the HSQLDB HSQL protocol database
0139:         *       connection url:
0140:         *       'jdbc:hsqldb:hsql[s]://host[port][/<b>&lt;alias&gt;</b>]'. <p>
0141:         *
0142:         *   <li>The value of <em>database.0</em> is special. If  <em>dbname.0</em>
0143:         *       is not specified, then this defaults to an empty string and
0144:         *       a connection is made to <em>database.0</em> path when
0145:         *       the <b>&lt;alias&gt;</b> component of an HSQLDB HSQL protocol database
0146:         *       connection url is omitted. If a <em>database</em> key/value pair is
0147:         *       found in the properties when the main method is called, this
0148:         *       pair is supersedes the <em>database.0</em> setting<p>
0149:         *
0150:         *       This behaviour allows the previous
0151:         *       database connection url format to work with essentially unchanged
0152:         *       semantics.<p>
0153:         *
0154:         *   <li>When the  <em>remote_open</em> property is true, a connection attempt
0155:         *       to an unopened database results in the database being opened. The URL
0156:         *       for connection should include the property filepath to specify the path.
0157:         *       'jdbc:hsqldb:hsql[s]://host[port]/<b>&lt;alias&gt;;filepath=hsqldb:file:&lt;database path&gt;</b>'.
0158:         *       the given alias and filepath value will be associated together. The
0159:         *       database user and password to start this connection must be valid.
0160:         *       If this form of connection is used again, after the database has been
0161:         *       opened, the filepath property is ignored.<p>
0162:         *
0163:         *   <li>Once an alias such as "mydb" has been associated with a path, it cannot
0164:         *       be  reassigned to a different path.<p>
0165:         *
0166:         *   <li>If a database is closed with the SHUTDOWN command, its
0167:         *       alias is removed. It is then possible to connect to this database again
0168:         *       with a different (or the same) alias.<p>
0169:         *
0170:         *   <li>If the same database is connected to via two different
0171:         *       aliases, and then one of the is closed with the SHUTDOWN command, the
0172:         *       other is also closed.<p>
0173:         * </ul>
0174:         *
0175:         * From the 'server.properties' file, options can be set similarly, using a
0176:         * slightly different format. <p>
0177:         *
0178:         * Here is an example 'server.properties' file:
0179:         *
0180:         * <pre>
0181:         * server.port=9001
0182:         * server.database.0=test
0183:         * server.dbname.0=...
0184:         * ...
0185:         * server.database.n=...
0186:         * server.dbname.n=...
0187:         * server.silent=true
0188:         * </pre>
0189:         *
0190:         * Starting with 1.7.2, Server has been refactored to become a simple JavaBean
0191:         * with non-blocking start() and stop() service methods.  It is possible to
0192:         * configure a Server instance through the JavaBean API as well, but this
0193:         * part of the public interface is still under review and will not be finalized
0194:         * or documented fully until the final 1.7.2 release. <p>
0195:         *
0196:         * <b>Note:</b> <p>
0197:         *
0198:         * The 'no_system_exit' property is of particular interest. <p>
0199:         *
0200:         * If a Server instance is to run embedded in, say, an application server,
0201:         * such as when the jdbcDataSource or HsqlServerFactory classes are used, it
0202:         * is typically necessary to avoid calling System.exit() when the Server
0203:         * instance shuts down. <p>
0204:         *
0205:         * By default, 'no_system_exit' is set: <p>
0206:         *
0207:         * <ol>
0208:         *    <li><b>true</b> when a Server is started directly from the start()
0209:         *        method. <p>
0210:         *
0211:         *    <li><b>false</b> when a Server is started from the main(String[])
0212:         *         method.
0213:         * </ol> <p>
0214:         *
0215:         * These values are natural to their context because the first case allows
0216:         * the JVM to exit by default on Server shutdown when a Server instance is
0217:         * started from a command line environment, whereas the second case prevents
0218:         * a typically unwanted JVM exit on Server shutdown when a Server intance
0219:         * is started as part of a larger framework. <p>
0220:         *
0221:         * Replaces original Hypersonic source of the same name.
0222:         *
0223:         * @author fredt@users
0224:         * @version 1.8.0
0225:         * @since 1.7.2
0226:         *
0227:         * @jmx.mbean
0228:         *    description="HSQLDB Server"
0229:         *    extends="org.hsqldb.mx.mbean.RegistrationSupportBaseMBean"
0230:         *
0231:         * @jboss.xmbean
0232:         */
0233:        public class Server implements  HsqlSocketRequestHandler {
0234:
0235:            //
0236:            protected static final int serverBundleHandle = BundleHandler
0237:                    .getBundleHandle("org_hsqldb_Server_messages", null);
0238:
0239:            //
0240:            HsqlProperties serverProperties;
0241:
0242:            //
0243:            HashSet serverConnSet;
0244:
0245:            //
0246:            private String[] dbAlias;
0247:            private String[] dbType;
0248:            private String[] dbPath;
0249:            private HsqlProperties[] dbProps;
0250:            private int[] dbID;
0251:
0252:            //  Currently unused
0253:            private int maxConnections;
0254:
0255:            //
0256:            protected String serverId;
0257:            protected int serverProtocol;
0258:            protected ThreadGroup serverConnectionThreadGroup;
0259:            protected HsqlSocketFactory socketFactory;
0260:            protected ServerSocket socket;
0261:
0262:            //
0263:            private Thread serverThread;
0264:            private Throwable serverError;
0265:            private volatile int serverState;
0266:            private volatile boolean isSilent;
0267:            private volatile boolean isRemoteOpen;
0268:            private PrintWriter logWriter;
0269:            private PrintWriter errWriter;
0270:
0271:            //
0272:
0273:            /**
0274:             * A specialized Thread inner class in which the run() method of this
0275:             * server executes.
0276:             */
0277:            private class ServerThread extends Thread {
0278:
0279:                /**
0280:                 * Constructs a new thread in which to execute the run method
0281:                 * of this server.
0282:                 *
0283:                 * @param name The thread name
0284:                 */
0285:                ServerThread(String name) {
0286:
0287:                    super (name);
0288:
0289:                    setName(name + '@'
0290:                            + Integer.toString(Server.this .hashCode(), 16));
0291:                }
0292:
0293:                /**
0294:                 * Executes the run() method of this server
0295:                 */
0296:                public void run() {
0297:                    Server.this .run();
0298:                    printWithThread("ServerThread.run() exited");
0299:                }
0300:            }
0301:
0302:            /**
0303:             * Creates a new Server instance handling HSQL protocol connections.
0304:             */
0305:            public Server() {
0306:                this (ServerConstants.SC_PROTOCOL_HSQL);
0307:            }
0308:
0309:            /**
0310:             * Creates a new Server instance handling the specified connection
0311:             * protocol. <p>
0312:             *
0313:             * For example, the no-args WebServer constructor invokes this constructor
0314:             * with ServerConstants.SC_PROTOCOL_HTTP, while the Server() no args
0315:             * contructor invokes this constructor with
0316:             * ServerConstants.SC_PROTOCOL_HSQL. <p>
0317:             *
0318:             * @param protocol the ServerConstants code indicating which
0319:             *      connection protocol to handle
0320:             */
0321:            protected Server(int protocol) {
0322:                init(protocol);
0323:            }
0324:
0325:            /**
0326:             * Creates and starts a new Server.  <p>
0327:             *
0328:             * Allows starting a Server via the command line interface. <p>
0329:             *
0330:             * @param args the command line arguments for the Server instance
0331:             */
0332:            public static void main(String[] args) {
0333:
0334:                String propsPath = FileUtil.canonicalOrAbsolutePath("server");
0335:                HsqlProperties fileProps = ServerConfiguration
0336:                        .getPropertiesFromFile(propsPath);
0337:                HsqlProperties props = fileProps == null ? new HsqlProperties()
0338:                        : fileProps;
0339:                HsqlProperties stringProps = null;
0340:                try {
0341:                    stringProps = HsqlProperties.argArrayToProps(args,
0342:                            ServerConstants.SC_KEY_PREFIX);
0343:                } catch (ArrayIndexOutOfBoundsException aioob) {
0344:                    // I'd like to exit with 0 here, but it's possible that user
0345:                    // has called main() programmatically and does not want us to
0346:                    // exit.
0347:                    printHelp("server.help");
0348:                    return;
0349:                }
0350:
0351:                if (stringProps != null) {
0352:                    if (stringProps.getErrorKeys().length != 0) {
0353:                        printHelp("server.help");
0354:
0355:                        return;
0356:                    }
0357:
0358:                    props.addProperties(stringProps);
0359:                }
0360:
0361:                ServerConfiguration.translateDefaultDatabaseProperty(props);
0362:
0363:                // Standard behaviour when started from the command line
0364:                // is to halt the VM when the server shuts down.  This may, of
0365:                // course, be overridden by whatever, if any, security policy
0366:                // is in place.
0367:                ServerConfiguration.translateDefaultNoSystemExitProperty(props);
0368:
0369:                // finished setting up properties;
0370:                Server server = new Server();
0371:
0372:                try {
0373:                    server.setProperties(props);
0374:                } catch (Exception e) {
0375:                    server.printError("Failed to set properties");
0376:                    server.printStackTrace(e);
0377:
0378:                    return;
0379:                }
0380:
0381:                // now messages go to the channel specified in properties
0382:                server.print("Startup sequence initiated from main() method");
0383:
0384:                if (fileProps != null) {
0385:                    server.print("Loaded properties from [" + propsPath
0386:                            + ".properties]");
0387:                } else {
0388:                    server.print("Could not load properties from file");
0389:                    server.print("Using cli/default properties only");
0390:                }
0391:
0392:                server.start();
0393:            }
0394:
0395:            /**
0396:             * Checks if this Server object is or is not running and throws if the
0397:             * current state does not match the specified value.
0398:             *
0399:             * @param running if true, ensure the server is running, else ensure the
0400:             *      server is not running
0401:             * @throws RuntimeException if the supplied value does not match the
0402:             *      current running status
0403:             */
0404:            public void checkRunning(boolean running) throws RuntimeException {
0405:
0406:                int state;
0407:                boolean error;
0408:
0409:                printWithThread("checkRunning(" + running + ") entered");
0410:
0411:                state = getState();
0412:                error = (running && state != ServerConstants.SERVER_STATE_ONLINE)
0413:                        || (!running && state != ServerConstants.SERVER_STATE_SHUTDOWN);
0414:
0415:                if (error) {
0416:                    String msg = "server is " + (running ? "not " : "")
0417:                            + "running";
0418:
0419:                    throw new RuntimeException(msg);
0420:                }
0421:
0422:                printWithThread("checkRunning(" + running + ") exited");
0423:            }
0424:
0425:            /**
0426:             * Closes all connections to this Server.
0427:             *
0428:             * @jmx.managed-operation
0429:             *  impact="ACTION"
0430:             *  description="Closes all open connections"
0431:             */
0432:            public synchronized void signalCloseAllServerConnections() {
0433:
0434:                Iterator it;
0435:
0436:                printWithThread("signalCloseAllServerConnections() entered");
0437:
0438:                synchronized (serverConnSet) {
0439:
0440:                    // snapshot
0441:                    it = new WrapperIterator(serverConnSet.toArray(null));
0442:                }
0443:
0444:                for (; it.hasNext();) {
0445:                    ServerConnection sc = (ServerConnection) it.next();
0446:
0447:                    printWithThread("Closing " + sc);
0448:
0449:                    // also removes all but one connection from serverConnSet
0450:                    sc.signalClose();
0451:                }
0452:
0453:                printWithThread("signalCloseAllServerConnections() exited");
0454:            }
0455:
0456:            protected void finalize() throws Throwable {
0457:
0458:                if (serverThread != null) {
0459:                    releaseServerSocket();
0460:                }
0461:            }
0462:
0463:            /**
0464:             * Retrieves, in string form, this server's host address.
0465:             *
0466:             * @return this server's host address
0467:             *
0468:             * @jmx.managed-attribute
0469:             *  access="read-write"
0470:             *  description="Host InetAddress"
0471:             */
0472:            public String getAddress() {
0473:
0474:                return socket == null ? serverProperties
0475:                        .getProperty(ServerConstants.SC_KEY_ADDRESS) : socket
0476:                        .getInetAddress().getHostAddress();
0477:            }
0478:
0479:            /**
0480:             * Retrieves the url alias (network name) of the i'th database
0481:             * that this Server hosts.
0482:             *
0483:             * @param index the index of the url alias upon which to report
0484:             * @param asconfigured if true, report the configured value, else
0485:             *      the live value
0486:             * @return the url alias component of the i'th database
0487:             *      that this Server hosts, or null if no such name exists.
0488:             *
0489:             * @jmx.managed-operation
0490:             *  impact="INFO"
0491:             *  description="url alias component of the i'th hosted Database"
0492:             *
0493:             * @jmx.managed-operation-parameter
0494:             *      name="index"
0495:             *      type="int"
0496:             *      position="0"
0497:             *      description="This Server's index for the hosted Database"
0498:             *
0499:             * @jmx.managed-operation-parameter
0500:             *      name="asconfigured"
0501:             *      type="boolean"
0502:             *      position="1"
0503:             *      description="if true, the configured value, else the live value"
0504:             */
0505:            public String getDatabaseName(int index, boolean asconfigured) {
0506:
0507:                if (asconfigured) {
0508:                    return serverProperties
0509:                            .getProperty(ServerConstants.SC_KEY_DBNAME + "."
0510:                                    + index);
0511:                } else if (getState() == ServerConstants.SERVER_STATE_ONLINE) {
0512:                    return (dbAlias == null || index < 0 || index >= dbAlias.length) ? null
0513:                            : dbAlias[index];
0514:                } else {
0515:                    return null;
0516:                }
0517:            }
0518:
0519:            /**
0520:             * Retrieves the HSQLDB path descriptor (uri) of the i'th
0521:             * Database that this Server hosts.
0522:             *
0523:             * @param index the index of the uri upon which to report
0524:             * @param asconfigured if true, report the configured value, else
0525:             *      the live value
0526:             * @return the HSQLDB database path descriptor of the i'th database
0527:             *      that this Server hosts, or null if no such path descriptor
0528:             *      exists
0529:             *
0530:             * @jmx.managed-operation
0531:             *  impact="INFO"
0532:             *  description="For i'th hosted database"
0533:             *
0534:             * @jmx.managed-operation-parameter
0535:             *      name="index"
0536:             *      type="int"
0537:             *      position="0"
0538:             *      description="This Server's index for the hosted Database"
0539:             *
0540:             * @jmx.managed-operation-parameter
0541:             *      name="asconfigured"
0542:             *      type="boolean"
0543:             *      position="1"
0544:             *      description="if true, the configured value, else the live value"
0545:             */
0546:            public String getDatabasePath(int index, boolean asconfigured) {
0547:
0548:                if (asconfigured) {
0549:                    return serverProperties
0550:                            .getProperty(ServerConstants.SC_KEY_DATABASE + "."
0551:                                    + index);
0552:                } else if (getState() == ServerConstants.SERVER_STATE_ONLINE) {
0553:                    return (dbPath == null || index < 0 || index >= dbPath.length) ? null
0554:                            : dbPath[index];
0555:                } else {
0556:                    return null;
0557:                }
0558:            }
0559:
0560:            public String getDatabaseType(int index) {
0561:                return (dbType == null || index < 0 || index >= dbType.length) ? null
0562:                        : dbType[index];
0563:            }
0564:
0565:            /**
0566:             * Retrieves the name of the web page served when no page is specified.
0567:             * This attribute is relevant only when server protocol is HTTP(S).
0568:             *
0569:             * @return the name of the web page served when no page is specified
0570:             *
0571:             * @jmx.managed-attribute
0572:             *  access="read-write"
0573:             *  description="Used when server protocol is HTTP(S)"
0574:             */
0575:            public String getDefaultWebPage() {
0576:                return "[IGNORED]";
0577:            }
0578:
0579:            /**
0580:             * Retrieves a String object describing the command line and
0581:             * properties options for this Server.
0582:             *
0583:             * @return the command line and properties options help for this Server
0584:             */
0585:            public String getHelpString() {
0586:                return BundleHandler.getString(serverBundleHandle,
0587:                        "server.help");
0588:            }
0589:
0590:            /**
0591:             * Retrieves the PrintWriter to which server errors are printed.
0592:             *
0593:             * @return the PrintWriter to which server errors are printed.
0594:             */
0595:            public PrintWriter getErrWriter() {
0596:                return errWriter;
0597:            }
0598:
0599:            /**
0600:             * Retrieves the PrintWriter to which server messages are printed.
0601:             *
0602:             * @return the PrintWriter to which server messages are printed.
0603:             */
0604:            public PrintWriter getLogWriter() {
0605:                return logWriter;
0606:            }
0607:
0608:            /**
0609:             * Retrieves this server's host port.
0610:             *
0611:             * @return this server's host port
0612:             *
0613:             * @jmx.managed-attribute
0614:             *  access="read-write"
0615:             *  description="At which ServerSocket listens for connections"
0616:             */
0617:            public int getPort() {
0618:
0619:                return serverProperties.getIntegerProperty(
0620:                        ServerConstants.SC_KEY_PORT, ServerConfiguration
0621:                                .getDefaultPort(serverProtocol, isTls()));
0622:            }
0623:
0624:            /**
0625:             * Retrieves this server's product name.  <p>
0626:             *
0627:             * Typically, this will be something like: "HSQLDB xxx server".
0628:             *
0629:             * @return the product name of this server
0630:             *
0631:             * @jmx.managed-attribute
0632:             *  access="read-only"
0633:             *  description="Of Server"
0634:             */
0635:            public String getProductName() {
0636:                return "HSQLDB server";
0637:            }
0638:
0639:            /**
0640:             * Retrieves the server's product version, as a String.  <p>
0641:             *
0642:             * Typically, this will be something like: "1.x.x" or "2.x.x" and so on.
0643:             *
0644:             * @return the product version of the server
0645:             *
0646:             * @jmx.managed-attribute
0647:             *  access="read-only"
0648:             *  description="Of Server"
0649:             */
0650:            public String getProductVersion() {
0651:                return HsqlDatabaseProperties.THIS_VERSION;
0652:            }
0653:
0654:            /**
0655:             * Retrieves a string respresentaion of the network protocol
0656:             * this server offers, typically one of 'HTTP', HTTPS', 'HSQL' or 'HSQLS'.
0657:             *
0658:             * @return string respresentation of this server's protocol
0659:             *
0660:             * @jmx.managed-attribute
0661:             *  access="read-only"
0662:             *  description="Used to handle connections"
0663:             */
0664:            public String getProtocol() {
0665:                return isTls() ? "HSQLS" : "HSQL";
0666:            }
0667:
0668:            /**
0669:             * Retrieves a Throwable indicating the last server error, if any. <p>
0670:             *
0671:             * @return a Throwable indicating the last server error
0672:             *
0673:             * @jmx.managed-attribute
0674:             *  access="read-only"
0675:             *  description="Indicating last exception state"
0676:             */
0677:            public Throwable getServerError() {
0678:                return serverError;
0679:            }
0680:
0681:            /**
0682:             * Retrieves a String identifying this Server object.
0683:             *
0684:             * @return a String identifying this Server object
0685:             *
0686:             * @jmx.managed-attribute
0687:             *  access="read-only"
0688:             *  description="Identifying Server"
0689:             */
0690:            public String getServerId() {
0691:                return serverId;
0692:            }
0693:
0694:            /**
0695:             * Retrieves current state of this server in numerically coded form. <p>
0696:             *
0697:             * Typically, this will be one of: <p>
0698:             *
0699:             * <ol>
0700:             * <li>ServerProperties.SERVER_STATE_ONLINE (1)
0701:             * <li>ServerProperties.SERVER_STATE_OPENING (4)
0702:             * <li>ServerProperties.SERVER_STATE_CLOSING (8)
0703:             * <li>ServerProperties.SERVER_STATE_SHUTDOWN (16)
0704:             * </ol>
0705:             *
0706:             * @return this server's state code.
0707:             *
0708:             * @jmx.managed-attribute
0709:             *  access="read-only"
0710:             *  description="1:ONLINE 4:OPENING 8:CLOSING, 16:SHUTDOWN"
0711:             */
0712:            public synchronized int getState() {
0713:                return serverState;
0714:            }
0715:
0716:            /**
0717:             * Retrieves a character sequence describing this server's current state,
0718:             * including the message of the last exception, if there is one and it
0719:             * is still in context.
0720:             *
0721:             * @return this server's state represented as a character sequence.
0722:             *
0723:             * @jmx.managed-attribute
0724:             *  access="read-only"
0725:             *  description="State as string"
0726:             */
0727:            public String getStateDescriptor() {
0728:
0729:                String state;
0730:                Throwable t = getServerError();
0731:
0732:                switch (serverState) {
0733:
0734:                case ServerConstants.SERVER_STATE_SHUTDOWN:
0735:                    state = "SHUTDOWN";
0736:                    break;
0737:
0738:                case ServerConstants.SERVER_STATE_OPENING:
0739:                    state = "OPENING";
0740:                    break;
0741:
0742:                case ServerConstants.SERVER_STATE_CLOSING:
0743:                    state = "CLOSING";
0744:                    break;
0745:
0746:                case ServerConstants.SERVER_STATE_ONLINE:
0747:                    state = "ONLINE";
0748:                    break;
0749:
0750:                default:
0751:                    state = "UNKNOWN";
0752:                    break;
0753:                }
0754:
0755:                return state;
0756:            }
0757:
0758:            /**
0759:             * Retrieves the root context (directory) from which web content
0760:             * is served.  This property is relevant only when the server
0761:             * protocol is HTTP(S).  Although unlikely, it may be that in the future
0762:             * other contexts, such as jar urls may be supported, so that pages can
0763:             * be served from the contents of a jar or from the JVM class path.
0764:             *
0765:             * @return the root context (directory) from which web content is served
0766:             *
0767:             * @jmx.managed-attribute
0768:             *  access="read-write"
0769:             *  description="Context (directory)"
0770:             */
0771:            public String getWebRoot() {
0772:                return "[IGNORED]";
0773:            }
0774:
0775:            /**
0776:             * Assigns the specified socket to a new conection handler and
0777:             * starts the handler in a new Thread.
0778:             *
0779:             * @param s the socket to connect
0780:             */
0781:            public void handleConnection(Socket s) {
0782:
0783:                Thread t;
0784:                Runnable r;
0785:                String ctn;
0786:
0787:                printWithThread("handleConnection(" + s + ") entered");
0788:
0789:                if (!allowConnection(s)) {
0790:                    try {
0791:                        s.close();
0792:                    } catch (Exception e) {
0793:                    }
0794:
0795:                    printWithThread("allowConnection(): connection refused");
0796:                    printWithThread("handleConnection() exited");
0797:
0798:                    return;
0799:                }
0800:
0801:                // Maybe set up socket options, SSL
0802:                // Session tracing/callbacks, etc.
0803:                if (socketFactory != null) {
0804:                    socketFactory.configureSocket(s);
0805:                }
0806:
0807:                if (serverProtocol == ServerConstants.SC_PROTOCOL_HSQL) {
0808:                    r = new ServerConnection(s, this );
0809:                    ctn = ((ServerConnection) r).getConnectionThreadName();
0810:
0811:                    synchronized (serverConnSet) {
0812:                        serverConnSet.add(r);
0813:                    }
0814:                } else {
0815:                    r = new WebServerConnection(s, (WebServer) this );
0816:                    ctn = ((WebServerConnection) r).getConnectionThreadName();
0817:                }
0818:
0819:                t = new Thread(serverConnectionThreadGroup, r, ctn);
0820:
0821:                t.start();
0822:                printWithThread("handleConnection() exited");
0823:            }
0824:
0825:            /**
0826:             * Retrieves whether this server calls System.exit() when shutdown.
0827:             *
0828:             * @return true if this server does not call System.exit()
0829:             *
0830:             * @jmx.managed-attribute
0831:             *  access="read-write"
0832:             *  description="When Shutdown"
0833:             */
0834:            public boolean isNoSystemExit() {
0835:                return serverProperties
0836:                        .isPropertyTrue(ServerConstants.SC_KEY_NO_SYSTEM_EXIT);
0837:            }
0838:
0839:            /**
0840:             * Retrieves whether this server restarts on shutdown.
0841:             *
0842:             * @return true this server restarts on shutdown
0843:             *
0844:             * @jmx.managed-attribute
0845:             *  access="read-write"
0846:             *  description="Automatically?"
0847:             */
0848:            public boolean isRestartOnShutdown() {
0849:                return serverProperties
0850:                        .isPropertyTrue(ServerConstants.SC_KEY_AUTORESTART_SERVER);
0851:            }
0852:
0853:            /**
0854:             * Retrieves whether silent mode operation was requested in
0855:             * the server properties.
0856:             *
0857:             * @return if true, silent mode was requested, else trace messages
0858:             *      are to be printed
0859:             *
0860:             * @jmx.managed-attribute
0861:             *  access="read-write"
0862:             *  description="No trace messages?"
0863:             */
0864:            public boolean isSilent() {
0865:                return isSilent;
0866:            }
0867:
0868:            /**
0869:             * Retrieves whether the use of secure sockets was requested in the
0870:             * server properties.
0871:             *
0872:             * @return if true, secure sockets are requested, else not
0873:             *
0874:             * @jmx.managed-attribute
0875:             *  access="read-write"
0876:             *  description="Use TLS/SSL sockets?"
0877:             */
0878:            public boolean isTls() {
0879:                return serverProperties
0880:                        .isPropertyTrue(ServerConstants.SC_KEY_TLS);
0881:            }
0882:
0883:            /**
0884:             * Retrieves whether JDBC trace messages are to go to System.out or the
0885:             * DriverManger PrintStream/PrintWriter, if any.
0886:             *
0887:             * @return true if tracing is on (JDBC trace messages to system out)
0888:             *
0889:             * @jmx.managed-attribute
0890:             *  access="read-write"
0891:             *  description="JDBC trace messages to System.out?"
0892:             */
0893:            public boolean isTrace() {
0894:                return serverProperties
0895:                        .isPropertyTrue(ServerConstants.SC_KEY_TRACE);
0896:            }
0897:
0898:            /**
0899:             * Attempts to put properties from the file
0900:             * with the specified path. The file
0901:             * extension '.properties' is implicit and should not
0902:             * be included in the path specification.
0903:             *
0904:             * @param path the path of the desired properties file, without the
0905:             *      '.properties' file extension
0906:             * @throws RuntimeException if this server is running
0907:             * @return true if the indicated file was read sucessfully, else false
0908:             *
0909:             * @jmx.managed-operation
0910:             *  impact="ACTION"
0911:             *  description="Reads in properties"
0912:             *
0913:             * @jmx.managed-operation-parameter
0914:             *   name="path"
0915:             *   type="java.lang.String"
0916:             *   position="0"
0917:             *   description="(optional) returns false if path is empty"
0918:             */
0919:            public boolean putPropertiesFromFile(String path) {
0920:
0921:                if (getState() != ServerConstants.SERVER_STATE_SHUTDOWN) {
0922:                    throw new RuntimeException();
0923:                }
0924:
0925:                path = FileUtil.canonicalOrAbsolutePath(path);
0926:
0927:                HsqlProperties p = ServerConfiguration
0928:                        .getPropertiesFromFile(path);
0929:
0930:                if (p == null || p.isEmpty()) {
0931:                    return false;
0932:                }
0933:
0934:                printWithThread("putPropertiesFromFile(): [" + path
0935:                        + ".properties]");
0936:
0937:                try {
0938:                    setProperties(p);
0939:                } catch (Exception e) {
0940:                    throw new RuntimeException("Failed to set properties: " + e);
0941:                }
0942:
0943:                return true;
0944:            }
0945:
0946:            /**
0947:             * Puts properties from the supplied string argument.  The relevant
0948:             * key value pairs are the same as those for the (web)server.properties
0949:             * file format, except that the 'server.' prefix should not be specified.
0950:             *
0951:             * @param s semicolon-delimited key=value pair string,
0952:             *      e.g. k1=v1;k2=v2;k3=v3...
0953:             * @throws RuntimeException if this server is running
0954:             *
0955:             * @jmx.managed-operation
0956:             *   impact="ACTION"
0957:             *   description="'server.' key prefix automatically supplied"
0958:             *
0959:             * @jmx.managed-operation-parameter
0960:             *   name="s"
0961:             *   type="java.lang.String"
0962:             *   position="0"
0963:             *   description="semicolon-delimited key=value pairs"
0964:             */
0965:            public void putPropertiesFromString(String s) {
0966:
0967:                if (getState() != ServerConstants.SERVER_STATE_SHUTDOWN) {
0968:                    throw new RuntimeException();
0969:                }
0970:
0971:                if (StringUtil.isEmpty(s)) {
0972:                    return;
0973:                }
0974:
0975:                printWithThread("putPropertiesFromString(): [" + s + "]");
0976:
0977:                HsqlProperties p = HsqlProperties.delimitedArgPairsToProps(s,
0978:                        "=", ";", ServerConstants.SC_KEY_PREFIX);
0979:
0980:                try {
0981:                    setProperties(p);
0982:                } catch (Exception e) {
0983:                    throw new RuntimeException("Failed to set properties: " + e);
0984:                }
0985:            }
0986:
0987:            /**
0988:             * Sets the InetAddress with which this server's ServerSocket will be
0989:             * constructed.  A null or empty string or the special value "0.0.0.0"
0990:             * can be used to bypass explicit selection, causing the ServerSocket
0991:             * to be constructed without specifying an InetAddress.
0992:             *
0993:             * @param address A string representing the desired InetAddress as would
0994:             *    be retrieved by InetAddres.getByName(), or a null or empty string
0995:             *    or "0.0.0.0" to signify that the server socket should be constructed
0996:             *    using the signature that does not specify the InetAddress.
0997:             * @throws RuntimeException if this server is running
0998:             *
0999:             * @jmx.managed-attribute
1000:             */
1001:            public void setAddress(String address) throws RuntimeException {
1002:
1003:                checkRunning(false);
1004:
1005:                if (org.hsqldb.lib.StringUtil.isEmpty(address)) {
1006:                    address = ServerConstants.SC_DEFAULT_ADDRESS;
1007:                }
1008:
1009:                printWithThread("setAddress(" + address + ")");
1010:                serverProperties.setProperty(ServerConstants.SC_KEY_ADDRESS,
1011:                        address);
1012:            }
1013:
1014:            /**
1015:             * Sets the external name (url alias) of the i'th hosted database.
1016:             *
1017:             * @param name external name (url alias) of the i'th HSQLDB database
1018:             *      instance this server is to host.
1019:             * @throws RuntimeException if this server is running
1020:             *
1021:             * @jmx.managed-operation
1022:             *      impact="ACTION"
1023:             *      description="Sets the url alias by which is known the i'th hosted Database"
1024:             *
1025:             * @jmx.managed-operation-parameter
1026:             *      name="index"
1027:             *      type="int"
1028:             *      position="0"
1029:             *      description="This Server's index for the hosted Database"
1030:             *
1031:             * @jmx.managed-operation-parameter
1032:             *      name="name"
1033:             *      type="java.lang.String"
1034:             *      position="1"
1035:             *      description="url alias component for the hosted Database"
1036:             */
1037:            public void setDatabaseName(int index, String name)
1038:                    throws RuntimeException {
1039:
1040:                checkRunning(false);
1041:                printWithThread("setDatabaseName(" + index + "," + name + ")");
1042:                serverProperties.setProperty(ServerConstants.SC_KEY_DBNAME
1043:                        + "." + index, name);
1044:            }
1045:
1046:            /**
1047:             * Sets the path of the hosted database.
1048:             *
1049:             * @param path The path of the i'th HSQLDB database instance this server
1050:             *      is to host.
1051:             *
1052:             * @jmx.managed-operation
1053:             *      impact="ACTION"
1054:             *      description="Sets the database uri path for the i'th hosted Database"
1055:             *
1056:             * @jmx.managed-operation-parameter
1057:             *      name="index"
1058:             *      type="int"
1059:             *      position="0"
1060:             *      description="This Server's index for the hosted Database"
1061:             *
1062:             * @jmx.managed-operation-parameter
1063:             *      name="path"
1064:             *      type="java.lang.String"
1065:             *      position="1"
1066:             *      description="database uri path of the hosted Database"
1067:             */
1068:            public void setDatabasePath(int index, String path)
1069:                    throws RuntimeException {
1070:
1071:                checkRunning(false);
1072:                printWithThread("setDatabasePath(" + index + "," + path + ")");
1073:                serverProperties.setProperty(ServerConstants.SC_KEY_DATABASE
1074:                        + "." + index, path);
1075:            }
1076:
1077:            /**
1078:             * Sets the name of the web page served when no page is specified.
1079:             *
1080:             * @param file the name of the web page served when no page is specified
1081:             *
1082:             * @jmx.managed-attribute
1083:             */
1084:            public void setDefaultWebPage(String file) {
1085:
1086:                checkRunning(false);
1087:                printWithThread("setDefaultWebPage(" + file + ")");
1088:
1089:                if (serverProtocol != ServerConstants.SC_PROTOCOL_HTTP) {
1090:                    return;
1091:                }
1092:
1093:                serverProperties.setProperty(
1094:                        ServerConstants.SC_KEY_WEB_DEFAULT_PAGE, file);
1095:            }
1096:
1097:            /**
1098:             * Sets the server listen port.
1099:             *
1100:             * @param port the port at which this server listens
1101:             *
1102:             * @jmx.managed-attribute
1103:             */
1104:            public void setPort(int port) throws RuntimeException {
1105:
1106:                checkRunning(false);
1107:                printWithThread("setPort(" + port + ")");
1108:                serverProperties.setProperty(ServerConstants.SC_KEY_PORT, port);
1109:            }
1110:
1111:            /**
1112:             * Sets the PrintWriter to which server errors are logged. <p>
1113:             *
1114:             * Setting this attribute to null disables server error logging
1115:             *
1116:             * @param pw the PrintWriter to which server messages are logged
1117:             */
1118:            public void setErrWriter(PrintWriter pw) {
1119:                errWriter = pw;
1120:            }
1121:
1122:            /**
1123:             * Sets the PrintWriter to which server messages are logged. <p>
1124:             *
1125:             * Setting this attribute to null disables server message logging
1126:             *
1127:             * @param pw the PrintWriter to which server messages are logged
1128:             */
1129:            public void setLogWriter(PrintWriter pw) {
1130:                logWriter = pw;
1131:            }
1132:
1133:            /**
1134:             * Sets whether this server calls System.exit() when shutdown.
1135:             *
1136:             * @param noExit if true, System.exit() will not be called.
1137:             *
1138:             * @jmx.managed-attribute
1139:             */
1140:            public void setNoSystemExit(boolean noExit) {
1141:
1142:                printWithThread("setNoSystemExit(" + noExit + ")");
1143:                serverProperties.setProperty(
1144:                        ServerConstants.SC_KEY_NO_SYSTEM_EXIT, noExit);
1145:            }
1146:
1147:            /**
1148:             * Sets whether this server restarts on shutdown.
1149:             *
1150:             * @param restart if true, this server restarts on shutdown
1151:             *
1152:             * @jmx.managed-attribute
1153:             */
1154:            public void setRestartOnShutdown(boolean restart) {
1155:
1156:                printWithThread("setRestartOnShutdown(" + restart + ")");
1157:                serverProperties.setProperty(
1158:                        ServerConstants.SC_KEY_AUTORESTART_SERVER, restart);
1159:            }
1160:
1161:            /**
1162:             * Sets silent mode operation
1163:             *
1164:             * @param silent if true, then silent mode, else trace messages
1165:             *  are to be printed
1166:             *
1167:             * @jmx.managed-attribute
1168:             */
1169:            public void setSilent(boolean silent) {
1170:
1171:                printWithThread("setSilent(" + silent + ")");
1172:                serverProperties.setProperty(ServerConstants.SC_KEY_SILENT,
1173:                        silent);
1174:
1175:                isSilent = silent;
1176:            }
1177:
1178:            /**
1179:             * Sets whether to use secure sockets
1180:             *
1181:             * @param tls true for secure sockets, else false
1182:             * @throws RuntimeException if this server is running
1183:             *
1184:             * @jmx.managed-attribute
1185:             */
1186:            public void setTls(boolean tls) {
1187:
1188:                checkRunning(false);
1189:                printWithThread("setTls(" + tls + ")");
1190:                serverProperties.setProperty(ServerConstants.SC_KEY_TLS, tls);
1191:            }
1192:
1193:            /**
1194:             * Sets whether trace messages go to System.out or the
1195:             * DriverManger PrintStream/PrintWriter, if any.
1196:             *
1197:             * @param trace if true, route JDBC trace messages to System.out
1198:             *
1199:             * @jmx.managed-attribute
1200:             */
1201:            public void setTrace(boolean trace) {
1202:
1203:                printWithThread("setTrace(" + trace + ")");
1204:                serverProperties.setProperty(ServerConstants.SC_KEY_TRACE,
1205:                        trace);
1206:                JavaSystem.setLogToSystem(trace);
1207:            }
1208:
1209:            /**
1210:             * Sets the path of the root directory from which web content is served.
1211:             *
1212:             * @param root the root (context) directory from which web content
1213:             *      is served
1214:             *
1215:             * @jmx.managed-attribute
1216:             */
1217:            public void setWebRoot(String root) {
1218:
1219:                checkRunning(false);
1220:
1221:                root = (new File(root)).getAbsolutePath();
1222:
1223:                printWithThread("setWebRoot(" + root + ")");
1224:
1225:                if (serverProtocol != ServerConstants.SC_PROTOCOL_HTTP) {
1226:                    return;
1227:                }
1228:
1229:                serverProperties.setProperty(ServerConstants.SC_KEY_WEB_ROOT,
1230:                        root);
1231:            }
1232:
1233:            /**
1234:             * Sets server properties using the specified properties object
1235:             *
1236:             * @param p The object containing properties to set
1237:             */
1238:            public void setProperties(HsqlProperties p) {
1239:
1240:                checkRunning(false);
1241:
1242:                if (p != null) {
1243:                    serverProperties.addProperties(p);
1244:                    ServerConfiguration
1245:                            .translateAddressProperty(serverProperties);
1246:                }
1247:
1248:                maxConnections = serverProperties.getIntegerProperty(
1249:                        ServerConstants.SC_KEY_MAX_CONNECTIONS, 16);
1250:
1251:                JavaSystem.setLogToSystem(isTrace());
1252:
1253:                isSilent = serverProperties
1254:                        .isPropertyTrue(ServerConstants.SC_KEY_SILENT);
1255:                isRemoteOpen = serverProperties
1256:                        .isPropertyTrue(ServerConstants.SC_KEY_REMOTE_OPEN_DB);
1257:            }
1258:
1259:            /**
1260:             * Starts this server synchronously. <p>
1261:             *
1262:             * This method waits for current state to change from
1263:             * SERVER_STATE_OPENNING. In order to discover the success or failure
1264:             * of this operation, server state must be polled or a subclass of Server
1265:             * must be used that overrides the setState method to provide state
1266:             * change notification.
1267:             *
1268:             * @return the server state noted at entry to this method
1269:             *
1270:             * @jmx.managed-operation
1271:             *  impact="ACTION_INFO"
1272:             *  description="Invokes asynchronous startup sequence; returns previous state"
1273:             */
1274:            public int start() {
1275:
1276:                printWithThread("start() entered");
1277:
1278:                int previousState = getState();
1279:
1280:                if (serverThread != null) {
1281:                    printWithThread("start(): serverThread != null; no action taken");
1282:
1283:                    return previousState;
1284:                }
1285:
1286:                setState(ServerConstants.SERVER_STATE_OPENING);
1287:
1288:                serverThread = new ServerThread("HSQLDB Server ");
1289:
1290:                serverThread.start();
1291:
1292:                // call synchronized getState() to become owner of the Server Object's monitor
1293:                while (getState() == ServerConstants.SERVER_STATE_OPENING) {
1294:                    try {
1295:                        Thread.sleep(100);
1296:                    } catch (InterruptedException e) {
1297:                    }
1298:                }
1299:
1300:                printWithThread("start() exiting");
1301:
1302:                return previousState;
1303:            }
1304:
1305:            /**
1306:             * Stops this server asynchronously. <p>
1307:             *
1308:             * This method returns immediately, regardless of current state.  In order
1309:             * to discover the success or failure of this operation, server state must
1310:             * be polled or a subclass of Server must be used that overrides the
1311:             * setState method to provide state change notification.
1312:             *
1313:             * @return the server state noted at entry to this method
1314:             *
1315:             * @jmx.managed-operation
1316:             *  impact="ACTION_INFO"
1317:             *  description="Invokes asynchronous shutdown sequence; returns previous state"
1318:             */
1319:            public int stop() {
1320:
1321:                printWithThread("stop() entered");
1322:
1323:                int previousState = getState();
1324:
1325:                if (serverThread == null) {
1326:                    printWithThread("stop() serverThread is null; no action taken");
1327:
1328:                    return previousState;
1329:                }
1330:
1331:                releaseServerSocket();
1332:                printWithThread("stop() exiting");
1333:
1334:                return previousState;
1335:            }
1336:
1337:            /**
1338:             * Retrieves whether the specified socket should be allowed
1339:             * to make a connection.  By default, this method always returns
1340:             * true, but it can be overidden to implement hosts allow-deny
1341:             * functionality.
1342:             *
1343:             * @param socket the socket to test.
1344:             */
1345:            protected boolean allowConnection(Socket socket) {
1346:                return true;
1347:            }
1348:
1349:            /**
1350:             * Initializes this server, setting the accepted connection protocol.
1351:             *
1352:             * @param protocol typically either SC_PROTOCOL_HTTP or SC_PROTOCOL_HSQL
1353:             */
1354:            protected void init(int protocol) {
1355:
1356:                // PRE:  This method is only called from the constructor
1357:                serverState = ServerConstants.SERVER_STATE_SHUTDOWN;
1358:                serverConnSet = new HashSet();
1359:                serverId = toString();
1360:                serverId = serverId.substring(serverId.lastIndexOf('.') + 1);
1361:                serverProtocol = protocol;
1362:                serverProperties = ServerConfiguration
1363:                        .newDefaultProperties(protocol);
1364:                logWriter = new PrintWriter(System.out);
1365:                errWriter = new PrintWriter(System.err);
1366:
1367:                JavaSystem.setLogToSystem(isTrace());
1368:            }
1369:
1370:            /**
1371:             * Sets the server state value.
1372:             *
1373:             * @param state the new value
1374:             */
1375:            protected synchronized void setState(int state) {
1376:                serverState = state;
1377:            }
1378:
1379:            /**
1380:             * This is called from org.hsqldb.DatabaseManager when a database is
1381:             * shutdown. This shuts the server down if it is the last database
1382:             *
1383:             * @param action a code indicating what has happend
1384:             */
1385:            final void notify(int action, int id) {
1386:
1387:                printWithThread("notifiy(" + action + "," + id + ") entered");
1388:
1389:                if (action != ServerConstants.SC_DATABASE_SHUTDOWN) {
1390:                    return;
1391:                }
1392:
1393:                releaseDatabase(id);
1394:
1395:                boolean shutdown = true;
1396:
1397:                for (int i = 0; i < dbID.length; i++) {
1398:                    if (dbAlias[i] != null) {
1399:                        shutdown = false;
1400:                    }
1401:                }
1402:
1403:                if (!isRemoteOpen && shutdown) {
1404:                    stop();
1405:                }
1406:            }
1407:
1408:            /**
1409:             * This releases the resources used for a database.
1410:             * Is called with id 0 multiple times for non-existent databases
1411:             */
1412:            final synchronized void releaseDatabase(int id) {
1413:
1414:                Iterator it;
1415:                boolean found = false;
1416:
1417:                printWithThread("releaseDatabase(" + id + ") entered");
1418:
1419:                // check all slots as a database may be opened by multiple aliases
1420:                for (int i = 0; i < dbID.length; i++) {
1421:                    if (dbID[i] == id && dbAlias[i] != null) {
1422:                        dbID[i] = 0;
1423:                        dbAlias[i] = null;
1424:                        dbPath[i] = null;
1425:                        dbType[i] = null;
1426:                        dbProps[i] = null;
1427:                    }
1428:                }
1429:
1430:                synchronized (serverConnSet) {
1431:                    it = new WrapperIterator(serverConnSet.toArray(null));
1432:                }
1433:
1434:                while (it.hasNext()) {
1435:                    ServerConnection sc = (ServerConnection) it.next();
1436:
1437:                    if (sc.dbID == id) {
1438:                        sc.signalClose();
1439:                        serverConnSet.remove(sc);
1440:                    }
1441:                }
1442:
1443:                printWithThread("releaseDatabase(" + id + ") exiting");
1444:            }
1445:
1446:            /**
1447:             * Prints the specified message, s, formatted to identify that the print
1448:             * operation is against this server instance.
1449:             *
1450:             * @param msg The message to print
1451:             */
1452:            protected synchronized void print(String msg) {
1453:
1454:                PrintWriter writer = logWriter;
1455:
1456:                if (writer != null) {
1457:                    writer.println("[" + serverId + "]: " + msg);
1458:                    writer.flush();
1459:                }
1460:            }
1461:
1462:            /**
1463:             * Prints value from server's resource bundle, formatted to
1464:             * identify that the print operation is against this server instance.
1465:             * Value may be localized according to the default JVM locale
1466:             *
1467:             * @param key the resource key
1468:             */
1469:            final void printResource(String key) {
1470:
1471:                String resource;
1472:                StringTokenizer st;
1473:
1474:                if (serverBundleHandle < 0) {
1475:                    return;
1476:                }
1477:
1478:                resource = BundleHandler.getString(serverBundleHandle, key);
1479:
1480:                if (resource == null) {
1481:                    return;
1482:                }
1483:
1484:                st = new StringTokenizer(resource, "\n\r");
1485:
1486:                while (st.hasMoreTokens()) {
1487:                    print(st.nextToken());
1488:                }
1489:            }
1490:
1491:            /**
1492:             * Prints the stack trace of the Throwable, t, to this Server object's
1493:             * errWriter. <p>
1494:             *
1495:             * @param t the Throwable whose stack trace is to be printed
1496:             */
1497:            protected synchronized void printStackTrace(Throwable t) {
1498:
1499:                if (errWriter != null) {
1500:                    t.printStackTrace(errWriter);
1501:                    errWriter.flush();
1502:                }
1503:            }
1504:
1505:            /**
1506:             * Prints the specified message, s, prepended with a timestamp representing
1507:             * the current date and time, formatted to identify that the print
1508:             * operation is against this server instance.
1509:             *
1510:             * @param msg the message to print
1511:             */
1512:            final void printWithTimestamp(String msg) {
1513:                print(HsqlDateTime.getSytemTimeString() + " " + msg);
1514:            }
1515:
1516:            /**
1517:             * Prints a message formatted similarly to print(String), additionally
1518:             * identifying the current (calling) thread. Replaces old method
1519:             * trace(String msg).
1520:             *
1521:             * @param msg the message to print
1522:             */
1523:            protected void printWithThread(String msg) {
1524:
1525:                if (!isSilent()) {
1526:                    print("[" + Thread.currentThread() + "]: " + msg);
1527:                }
1528:            }
1529:
1530:            /**
1531:             * Prints an error message to this Server object's errWriter.
1532:             * The message is formatted similarly to print(String),
1533:             * additionally identifying the current (calling) thread.
1534:             *
1535:             * @param msg the message to print
1536:             */
1537:            protected synchronized void printError(String msg) {
1538:
1539:                PrintWriter writer = errWriter;
1540:
1541:                if (writer != null) {
1542:                    writer.print("[" + serverId + "]: ");
1543:                    writer.print("[" + Thread.currentThread() + "]: ");
1544:                    writer.println(msg);
1545:                    writer.flush();
1546:                }
1547:            }
1548:
1549:            /**
1550:             * Prints a description of the request encapsulated by the
1551:             * Result argument, r.
1552:             *
1553:             * Printing occurs iff isSilent() is false. <p>
1554:             *
1555:             * The message is formatted similarly to print(String), additionally
1556:             * indicating the connection identifier.  <p>
1557:             *
1558:             * For Server instances, cid is typically the value assigned to each
1559:             * ServerConnection object that is unique amongst all such identifiers
1560:             * in each distinct JVM session / class loader
1561:             * context. <p>
1562:             *
1563:             * For WebServer instances, a single logical connection actually spawns
1564:             * a new physical WebServerConnection object for each request, so the
1565:             * cid is typically the underlying session id, since that does not
1566:             * change for the duration of the logical connection.
1567:             *
1568:             * @param cid the connection identifier
1569:             * @param r the request whose description is to be printed
1570:             */
1571:            final void printRequest(int cid, Result r) {
1572:
1573:                if (isSilent()) {
1574:                    return;
1575:                }
1576:
1577:                StringBuffer sb = new StringBuffer();
1578:
1579:                sb.append(cid);
1580:                sb.append(':');
1581:
1582:                switch (r.mode) {
1583:
1584:                case ResultConstants.SQLPREPARE: {
1585:                    sb.append("SQLCLI:SQLPREPARE ");
1586:                    sb.append(r.getMainString());
1587:
1588:                    break;
1589:                }
1590:                case ResultConstants.SQLEXECDIRECT: {
1591:                    if (r.getSize() < 2) {
1592:                        sb.append(r.getMainString());
1593:                    } else {
1594:                        sb.append("SQLCLI:SQLEXECDIRECT:BATCHMODE\n");
1595:
1596:                        Iterator it = r.iterator();
1597:
1598:                        while (it.hasNext()) {
1599:                            Object[] data = (Object[]) it.next();
1600:
1601:                            sb.append(data[0]).append('\n');
1602:                        }
1603:                    }
1604:
1605:                    break;
1606:                }
1607:                case ResultConstants.SQLEXECUTE: {
1608:                    sb.append("SQLCLI:SQLEXECUTE:");
1609:
1610:                    if (r.getSize() > 1) {
1611:                        sb.append("BATCHMODE:");
1612:                    }
1613:
1614:                    sb.append(r.getStatementID());
1615:
1616:                    /**
1617:                     * todo - fredt - NOW - fix this without appendStringValueOf
1618:                     */
1619:                    /*
1620:                     if (r.getSize() == 1) {
1621:                     sb.append('\n');
1622:                     StringUtil.appendStringValueOf(r.getParameterData(), sb, true);
1623:                     }
1624:                     */
1625:                    break;
1626:                }
1627:                case ResultConstants.SQLFREESTMT: {
1628:                    sb.append("SQLCLI:SQLFREESTMT:");
1629:                    sb.append(r.getStatementID());
1630:
1631:                    break;
1632:                }
1633:                case ResultConstants.GETSESSIONATTR: {
1634:                    sb.append("HSQLCLI:GETSESSIONATTR");
1635:
1636:                    break;
1637:                }
1638:                case ResultConstants.SETSESSIONATTR: {
1639:                    sb.append("HSQLCLI:SETSESSIONATTR:");
1640:                    sb.append("AUTOCOMMIT ");
1641:                    sb.append(r.rRoot.data[Session.INFO_AUTOCOMMIT]);
1642:                    sb.append(" CONNECTION_READONLY ");
1643:                    sb.append(r.rRoot.data[Session.INFO_CONNECTION_READONLY]);
1644:
1645:                    break;
1646:                }
1647:                case ResultConstants.SQLENDTRAN: {
1648:                    sb.append("SQLCLI:SQLENDTRAN:");
1649:
1650:                    switch (r.getEndTranType()) {
1651:
1652:                    case ResultConstants.COMMIT:
1653:                        sb.append("COMMIT");
1654:                        break;
1655:
1656:                    case ResultConstants.ROLLBACK:
1657:                        sb.append("ROLLBACK");
1658:                        break;
1659:
1660:                    case ResultConstants.SAVEPOINT_NAME_RELEASE:
1661:                        sb.append("SAVEPOINT_NAME_RELEASE ");
1662:                        sb.append(r.getMainString());
1663:                        break;
1664:
1665:                    case ResultConstants.SAVEPOINT_NAME_ROLLBACK:
1666:                        sb.append("SAVEPOINT_NAME_ROLLBACK ");
1667:                        sb.append(r.getMainString());
1668:                        break;
1669:
1670:                    default:
1671:                        sb.append(r.getEndTranType());
1672:                    }
1673:
1674:                    break;
1675:                }
1676:                case ResultConstants.SQLSTARTTRAN: {
1677:                    sb.append("SQLCLI:SQLSTARTTRAN");
1678:
1679:                    break;
1680:                }
1681:                case ResultConstants.SQLDISCONNECT: {
1682:                    sb.append("SQLCLI:SQLDISCONNECT");
1683:
1684:                    break;
1685:                }
1686:                case ResultConstants.SQLSETCONNECTATTR: {
1687:                    sb.append("SQLCLI:SQLSETCONNECTATTR:");
1688:
1689:                    switch (r.getConnectionAttrType()) {
1690:
1691:                    case ResultConstants.SQL_ATTR_SAVEPOINT_NAME: {
1692:                        sb.append("SQL_ATTR_SAVEPOINT_NAME ");
1693:                        sb.append(r.getMainString());
1694:
1695:                        break;
1696:                    }
1697:                    default: {
1698:                        sb.append(r.getConnectionAttrType());
1699:                    }
1700:                    }
1701:
1702:                    break;
1703:                }
1704:                default: {
1705:                    sb.append("SQLCLI:MODE:");
1706:                    sb.append(r.mode);
1707:
1708:                    break;
1709:                }
1710:                }
1711:
1712:                print(sb.toString());
1713:            }
1714:
1715:            /**
1716:             * return database ID
1717:             */
1718:            synchronized final int getDBID(String aliasPath)
1719:                    throws HsqlException {
1720:
1721:                int semipos = aliasPath.indexOf(';');
1722:                String alias = aliasPath;
1723:                String filepath = null;
1724:
1725:                if (semipos != -1) {
1726:                    alias = aliasPath.substring(0, semipos);
1727:                    filepath = aliasPath.substring(semipos + 1);
1728:                }
1729:
1730:                int dbIndex = ArrayUtil.find(dbAlias, alias);
1731:
1732:                if (dbIndex == -1) {
1733:                    if (filepath == null) {
1734:                        RuntimeException e = new RuntimeException(
1735:                                "database alias does not exist");
1736:
1737:                        printError("database alias=" + alias
1738:                                + " does not exist");
1739:                        setServerError(e);
1740:
1741:                        throw e;
1742:                    } else {
1743:                        return openDatabase(alias, filepath);
1744:                    }
1745:                } else {
1746:                    return dbID[dbIndex];
1747:                }
1748:            }
1749:
1750:            /**
1751:             * Open and return database ID
1752:             */
1753:            final int openDatabase(String alias, String filepath)
1754:                    throws HsqlException {
1755:
1756:                if (!isRemoteOpen) {
1757:                    RuntimeException e = new RuntimeException(
1758:                            "remote open not allowed");
1759:
1760:                    printError("Remote database open not allowed");
1761:                    setServerError(e);
1762:
1763:                    throw e;
1764:                }
1765:
1766:                int i = getFirstEmptyDatabaseIndex();
1767:
1768:                if (i < -1) {
1769:                    RuntimeException e = new RuntimeException(
1770:                            "limit of open databases reached");
1771:
1772:                    printError("limit of open databases reached");
1773:                    setServerError(e);
1774:
1775:                    throw e;
1776:                }
1777:
1778:                HsqlProperties newprops = DatabaseURL.parseURL(filepath, false);
1779:
1780:                if (newprops == null) {
1781:                    RuntimeException e = new RuntimeException(
1782:                            "invalid database path");
1783:
1784:                    printError("invalid database path");
1785:                    setServerError(e);
1786:
1787:                    throw e;
1788:                }
1789:
1790:                String path = newprops.getProperty("database");
1791:                String type = newprops.getProperty("connection_type");
1792:
1793:                try {
1794:                    int dbid = DatabaseManager.getDatabase(type, path, this ,
1795:                            newprops);
1796:
1797:                    dbID[i] = dbid;
1798:                    dbAlias[i] = alias;
1799:                    dbPath[i] = path;
1800:                    dbType[i] = type;
1801:                    dbProps[i] = newprops;
1802:
1803:                    return dbid;
1804:                } catch (HsqlException e) {
1805:                    printError("Database [index=" + i + "db=" + dbType[i]
1806:                            + dbPath[i] + ", alias=" + dbAlias[i]
1807:                            + "] did not open: " + e.toString());
1808:                    setServerError(e);
1809:
1810:                    throw e;
1811:                }
1812:            }
1813:
1814:            final int getFirstEmptyDatabaseIndex() {
1815:
1816:                for (int i = 0; i < dbAlias.length; i++) {
1817:                    if (dbAlias[i] == null) {
1818:                        return i;
1819:                    }
1820:                }
1821:
1822:                return -1;
1823:            }
1824:
1825:            /**
1826:             * Opens this server's database instances. This method returns true If
1827:             * at least one database goes online, otherwise it returns false.
1828:             *
1829:             * If openning any of the databases is attempted and an exception is
1830:             * thrown, the server error is set to this exception.
1831:             *
1832:             * @throws HsqlException if a database access error occurs
1833:             */
1834:            final boolean openDatabases() {
1835:
1836:                printWithThread("openDatabases() entered");
1837:
1838:                boolean success = false;
1839:
1840:                setDBInfoArrays();
1841:
1842:                for (int i = 0; i < dbAlias.length; i++) {
1843:                    if (dbAlias[i] == null) {
1844:                        continue;
1845:                    }
1846:
1847:                    printWithThread("Opening database: [" + dbType[i]
1848:                            + dbPath[i] + "]");
1849:
1850:                    StopWatch sw = new StopWatch();
1851:                    int id;
1852:
1853:                    try {
1854:                        id = DatabaseManager.getDatabase(dbType[i], dbPath[i],
1855:                                this , dbProps[i]);
1856:                        dbID[i] = id;
1857:                        success = true;
1858:                    } catch (HsqlException e) {
1859:                        printError("Database [index=" + i + "db=" + dbType[i]
1860:                                + dbPath[i] + ", alias=" + dbAlias[i]
1861:                                + "] did not open: " + e.toString());
1862:                        setServerError(e);
1863:
1864:                        dbAlias[i] = null;
1865:                        dbPath[i] = null;
1866:                        dbType[i] = null;
1867:                        dbProps[i] = null;
1868:
1869:                        continue;
1870:                    }
1871:
1872:                    sw.stop();
1873:
1874:                    String msg = "Database [index=" + i + ", id=" + id + ", "
1875:                            + "db=" + dbType[i] + dbPath[i] + ", alias="
1876:                            + dbAlias[i] + "] opened sucessfully";
1877:
1878:                    print(sw.elapsedTimeToMessage(msg));
1879:                }
1880:
1881:                printWithThread("openDatabases() exiting");
1882:
1883:                if (isRemoteOpen) {
1884:                    success = true;
1885:                }
1886:
1887:                if (!success && getServerError() == null) {
1888:
1889:                    // database alias / path list is empty or without full info for any DB
1890:                    setServerError(Trace.error(Trace.SERVER_NO_DATABASE));
1891:                }
1892:
1893:                return success;
1894:            }
1895:
1896:            /**
1897:             * Initialises the database attributes lists from the server properties object.
1898:             */
1899:            private void setDBInfoArrays() {
1900:
1901:                dbAlias = getDBNameArray();
1902:                dbPath = new String[dbAlias.length];
1903:                dbType = new String[dbAlias.length];
1904:                dbID = new int[dbAlias.length];
1905:                dbProps = new HsqlProperties[dbAlias.length];
1906:
1907:                for (int i = 0; i < dbAlias.length; i++) {
1908:                    if (dbAlias[i] == null) {
1909:                        continue;
1910:                    }
1911:
1912:                    String path = getDatabasePath(i, true);
1913:
1914:                    if (path == null) {
1915:                        dbAlias[i] = null;
1916:
1917:                        continue;
1918:                    }
1919:
1920:                    HsqlProperties dbURL = DatabaseURL.parseURL(path, false);
1921:
1922:                    if (dbURL == null) {
1923:                        dbAlias[i] = null;
1924:
1925:                        continue;
1926:                    }
1927:
1928:                    dbPath[i] = dbURL.getProperty("database");
1929:                    dbType[i] = dbURL.getProperty("connection_type");
1930:                    dbProps[i] = dbURL;
1931:                }
1932:            }
1933:
1934:            /**
1935:             * Returns a possibly sparse array of all server.dbname.n values
1936:             * from the properties object.
1937:             */
1938:            private String[] getDBNameArray() {
1939:
1940:                final String prefix = ServerConstants.SC_KEY_DBNAME + ".";
1941:                final int prefixLen = prefix.length();
1942:                String[] dblist = new String[10];
1943:                int maxindex = 0;
1944:
1945:                try {
1946:                    Enumeration en = serverProperties.propertyNames();
1947:
1948:                    for (; en.hasMoreElements();) {
1949:                        String key = (String) en.nextElement();
1950:
1951:                        if (!key.startsWith(prefix)) {
1952:                            continue;
1953:                        }
1954:
1955:                        try {
1956:                            int dbnum = Integer.parseInt(key
1957:                                    .substring(prefixLen));
1958:
1959:                            maxindex = dbnum < maxindex ? maxindex : dbnum;
1960:                            dblist[dbnum] = serverProperties.getProperty(key)
1961:                                    .toLowerCase();
1962:                        } catch (NumberFormatException e) {
1963:                            printWithThread("dblist: " + e.toString());
1964:                        }
1965:                    }
1966:                } catch (ArrayIndexOutOfBoundsException e) {
1967:                    printWithThread("dblist: " + e.toString());
1968:                }
1969:
1970:                return dblist;
1971:            }
1972:
1973:            /**
1974:             * Constructs and installs a new ServerSocket instance for this server.
1975:             *
1976:             * @throws Exception if it is not possible to construct and install
1977:             *      a new ServerSocket
1978:             */
1979:            private void openServerSocket() throws Exception {
1980:
1981:                String address;
1982:                int port;
1983:                String[] candidateAddrs;
1984:                String emsg;
1985:                StopWatch sw;
1986:
1987:                printWithThread("openServerSocket() entered");
1988:
1989:                if (isTls()) {
1990:                    printWithThread("Requesting TLS/SSL-encrypted JDBC");
1991:                }
1992:
1993:                sw = new StopWatch();
1994:                socketFactory = HsqlSocketFactory.getInstance(isTls());
1995:                address = getAddress();
1996:                port = getPort();
1997:
1998:                if (org.hsqldb.lib.StringUtil.isEmpty(address)
1999:                        || ServerConstants.SC_DEFAULT_ADDRESS
2000:                                .equalsIgnoreCase(address.trim())) {
2001:                    socket = socketFactory.createServerSocket(port);
2002:                } else {
2003:                    try {
2004:                        socket = socketFactory
2005:                                .createServerSocket(port, address);
2006:                    } catch (UnknownHostException e) {
2007:                        candidateAddrs = ServerConfiguration
2008:                                .listLocalInetAddressNames();
2009:
2010:                        int messageID;
2011:                        Object[] messageParameters;
2012:
2013:                        if (candidateAddrs.length > 0) {
2014:                            messageID = Trace.Server_openServerSocket;
2015:                            messageParameters = new Object[] { address,
2016:                                    candidateAddrs };
2017:                        } else {
2018:                            messageID = Trace.Server_openServerSocket2;
2019:                            messageParameters = new Object[] { address };
2020:                        }
2021:
2022:                        throw new UnknownHostException(Trace.getMessage(
2023:                                messageID, true, messageParameters));
2024:                    }
2025:                }
2026:
2027:                /*
2028:                 * Following line necessary for Java 1.3 on UNIX.  See accept()
2029:                 * comment elsewhere in this file.
2030:                 */
2031:                socket.setSoTimeout(1000);
2032:                printWithThread("Got server socket: " + socket);
2033:                print(sw
2034:                        .elapsedTimeToMessage("Server socket opened successfully"));
2035:
2036:                if (socketFactory.isSecure()) {
2037:                    print("Using TLS/SSL-encrypted JDBC");
2038:                }
2039:
2040:                printWithThread("openServerSocket() exiting");
2041:            }
2042:
2043:            /** Prints a timestamped message indicating that this server is online */
2044:            private void printServerOnlineMessage() {
2045:
2046:                String s = getProductName() + " " + getProductVersion()
2047:                        + " is online";
2048:
2049:                printWithTimestamp(s);
2050:                printResource("online.help");
2051:            }
2052:
2053:            /**
2054:             * Prints a description of the server properties iff !isSilent().
2055:             */
2056:            protected void printProperties() {
2057:
2058:                Enumeration e;
2059:                String key;
2060:                String value;
2061:
2062:                // Avoid the waste of generating each description,
2063:                // only for trace() to silently discard it
2064:                if (isSilent()) {
2065:                    return;
2066:                }
2067:
2068:                e = serverProperties.propertyNames();
2069:
2070:                while (e.hasMoreElements()) {
2071:                    key = (String) e.nextElement();
2072:                    value = serverProperties.getProperty(key);
2073:
2074:                    printWithThread(key + "=" + value);
2075:                }
2076:            }
2077:
2078:            /**
2079:             * Puts this server into the SERVER_CLOSING state, closes the ServerSocket
2080:             * and nullifies the reference to it. If the ServerSocket is already null,
2081:             * this method exists immediately, otherwise, the result is to fully
2082:             * shut down the server.
2083:             */
2084:            private void releaseServerSocket() {
2085:
2086:                printWithThread("releaseServerSocket() entered");
2087:
2088:                if (socket != null) {
2089:                    printWithThread("Releasing server socket: [" + socket + "]");
2090:                    setState(ServerConstants.SERVER_STATE_CLOSING);
2091:
2092:                    try {
2093:                        socket.close();
2094:                    } catch (IOException e) {
2095:                        printError("Exception closing server socket");
2096:                        printError("releaseServerSocket(): " + e);
2097:                    }
2098:
2099:                    socket = null;
2100:                }
2101:
2102:                printWithThread("releaseServerSocket() exited");
2103:            }
2104:
2105:            /**
2106:             * Attempts to bring this server fully online by opening
2107:             * a new ServerSocket, obtaining the hosted databases,
2108:             * notifying the status waiter thread (if any) and
2109:             * finally entering the listen loop if all else succeeds.
2110:             * If any part of the process fails, then this server enters
2111:             * its shutdown sequence.
2112:             */
2113:            private void run() {
2114:
2115:                StopWatch sw;
2116:                ThreadGroup tg;
2117:                String tgName;
2118:
2119:                printWithThread("run() entered");
2120:                print("Initiating startup sequence...");
2121:                printProperties();
2122:
2123:                sw = new StopWatch();
2124:
2125:                setServerError(null);
2126:
2127:                try {
2128:
2129:                    // Faster init first:
2130:                    // It is huge waste to fully open the databases, only
2131:                    // to find that the socket address is already in use
2132:                    openServerSocket();
2133:                } catch (Exception e) {
2134:                    setServerError(e);
2135:                    printError("run()/openServerSocket(): ");
2136:                    printStackTrace(e);
2137:                    shutdown(true);
2138:
2139:                    return;
2140:                }
2141:
2142:                tgName = "HSQLDB Connections @"
2143:                        + Integer.toString(this .hashCode(), 16);
2144:                tg = new ThreadGroup(tgName);
2145:
2146:                tg.setDaemon(false);
2147:
2148:                serverConnectionThreadGroup = tg;
2149:
2150:                // Mount the databases this server is supposed to host.
2151:                // This may take some time if the databases are not all
2152:                // already open.
2153:                if (openDatabases() == false) {
2154:                    setServerError(null);
2155:                    printError("Shutting down because there are no open databases");
2156:                    shutdown(true);
2157:
2158:                    return;
2159:                }
2160:
2161:                // At this point, we have a valid server socket and
2162:                // a valid hosted database set, so its OK to start
2163:                // listening for connections.
2164:                setState(ServerConstants.SERVER_STATE_ONLINE);
2165:                print(sw.elapsedTimeToMessage("Startup sequence completed"));
2166:                printServerOnlineMessage();
2167:
2168:                try {
2169:                    /*
2170:                     * This loop is necessary for UNIX w/ Sun Java 1.3 because
2171:                     * in that case the socket.close() elsewhere will not
2172:                     * interrupt this accept().
2173:                     */
2174:                    while (true) {
2175:                        try {
2176:                            handleConnection(socket.accept());
2177:                        } catch (java.io.InterruptedIOException e) {
2178:                        }
2179:                    }
2180:                } catch (IOException e) {
2181:                    if (getState() == ServerConstants.SERVER_STATE_ONLINE) {
2182:                        setServerError(e);
2183:                        printError(this  + ".run()/handleConnection(): ");
2184:                        printStackTrace(e);
2185:                    }
2186:                } catch (Throwable t) {
2187:                    printWithThread(t.toString());
2188:                } finally {
2189:                    shutdown(false); // or maybe getServerError() != null?
2190:                }
2191:            }
2192:
2193:            /**
2194:             * Sets this Server's last encountered error state.
2195:             *
2196:             * @param t The new value for the server error
2197:             */
2198:            protected void setServerError(Throwable t) {
2199:                serverError = t;
2200:            }
2201:
2202:            /**
2203:             * External method to shut down this server.
2204:             */
2205:            public void shutdown() {
2206:                shutdown(false);
2207:            }
2208:
2209:            /**
2210:             * Shuts down this server.
2211:             *
2212:             * @param error true if shutdown is in response to an error
2213:             *      state, else false
2214:             */
2215:            protected synchronized void shutdown(boolean error) {
2216:
2217:                if (serverState == ServerConstants.SERVER_STATE_SHUTDOWN) {
2218:                    return;
2219:                }
2220:
2221:                StopWatch sw;
2222:
2223:                printWithThread("shutdown() entered");
2224:
2225:                sw = new StopWatch();
2226:
2227:                print("Initiating shutdown sequence...");
2228:                releaseServerSocket();
2229:                DatabaseManager.deRegisterServer(this );
2230:
2231:                if (dbPath != null) {
2232:                    for (int i = 0; i < dbPath.length; i++) {
2233:                        releaseDatabase(dbID[i]);
2234:                    }
2235:                }
2236:
2237:                // Be nice and let applications exit if there are no
2238:                // running connection threads
2239:                if (serverConnectionThreadGroup != null) {
2240:                    if (!serverConnectionThreadGroup.isDestroyed()) {
2241:                        for (int i = 0; serverConnectionThreadGroup
2242:                                .activeCount() > 0; i++) {
2243:                            int count;
2244:
2245:                            try {
2246:                                Thread.sleep(100);
2247:                            } catch (Exception e) {
2248:
2249:                                // e.getMessage();
2250:                            }
2251:                        }
2252:
2253:                        try {
2254:                            serverConnectionThreadGroup.destroy();
2255:                            printWithThread(serverConnectionThreadGroup
2256:                                    .getName()
2257:                                    + " destroyed");
2258:                        } catch (Throwable t) {
2259:                            printWithThread(serverConnectionThreadGroup
2260:                                    .getName()
2261:                                    + " not destroyed");
2262:                            printWithThread(t.toString());
2263:                        }
2264:                    }
2265:
2266:                    serverConnectionThreadGroup = null;
2267:                }
2268:
2269:                serverThread = null;
2270:
2271:                setState(ServerConstants.SERVER_STATE_SHUTDOWN);
2272:                print(sw.elapsedTimeToMessage("Shutdown sequence completed"));
2273:
2274:                if (isNoSystemExit()) {
2275:                    printWithTimestamp("SHUTDOWN : System.exit() was not called");
2276:                    printWithThread("shutdown() exited");
2277:                } else {
2278:                    printWithTimestamp("SHUTDOWN : System.exit() is called next");
2279:                    printWithThread("shutdown() exiting...");
2280:
2281:                    try {
2282:                        System.exit(0);
2283:                    } catch (Throwable t) {
2284:                        printWithThread(t.toString());
2285:                    }
2286:                }
2287:            }
2288:
2289:            /**
2290:             * Prints message for the specified key, without any special
2291:             * formatting. The message content comes from the server
2292:             * resource bundle and thus may localized according to the default
2293:             * JVM locale.<p>
2294:             *
2295:             * Uses System.out directly instead of Trace.printSystemOut() so it
2296:             * always prints, regardless of Trace settings.
2297:             *
2298:             * @param key for message
2299:             */
2300:            protected static void printHelp(String key) {
2301:                System.out.println(BundleHandler.getString(serverBundleHandle,
2302:                        key));
2303:            }
2304:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.