File D:\maven-qcr-plugin-testsunitaires\qcr4java\h2-1.3.170-sources\target\site\qc\lecode\tools\Server.java.html

1 /*
2 * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
3 * Version 1.0, and under the Eclipse Public License, Version 1.0
4 * (http://h2database.com/html/license.html).
5 * Initial Developer: H2 Group
6 */
7 package org.h2.tools;
8
9 import java.net.URI;
10 import java.sql.Connection;
11 import java.sql.SQLException;
12 import org.h2.constant.ErrorCode;
13 import org.h2.constant.SysProperties;
14 import org.h2.message.DbException;
15 import org.h2.message.TraceSystem;
16 import org.h2.server.Service;
17 import org.h2.server.ShutdownHandler;
18 import org.h2.server.TcpServer;
19 import org.h2.server.pg.PgServer;
20 import org.h2.server.web.WebServer;
21 import org.h2.util.StringUtils;
22 import org.h2.util.Tool;
23 import org.h2.util.Utils;
24
25 /**
26 * Starts the H2 Console (web-) server, TCP, and PG server.
27 * @h2.resource
28 */
29 public class Server extends Tool implements Runnable, ShutdownHandler {
30
31 private final Service service;
32 private Server web, tcp, pg;
33 private ShutdownHandler shutdownHandler;
34 private boolean started;
35
36 public Server() {
37 // nothing to do
38 this.service = null;
39 }
40
41 /**
42 * Create a new server for the given service.
43 *
44 * @param service the service
45 * @param args the command line arguments
46 */
47 public Server(Service service, String... args) throws SQLException {
48 verifyArgs(args);
49 this.service = service;
50 try {
51 service.init(args);
52 } catch (Exception e) {
53 throw DbException.toSQLException(e);
54 }
55 }
56
57 /**
58 * When running without options, -tcp, -web, -browser and -pg are started.
59 * <br />
60 * Options are case sensitive. Supported options are:
61 * <table>
62 * <tr><td>[-help] or [-?]</td>
63 * <td>Print the list of options</td></tr>
64 * <tr><td>[-web]</td>
65 * <td>Start the web server with the H2 Console</td></tr>
66 * <tr><td>[-webAllowOthers]</td>
67 * <td>Allow other computers to connect - see below</td></tr>
68 * <tr><td>[-webDaemon]</td>
69 * <td>Use a daemon thread</td></tr>
70 * <tr><td>[-webPort &lt;port&gt;]</td>
71 * <td>The port (default: 8082)</td></tr>
72 * <tr><td>[-webSSL]</td>
73 * <td>Use encrypted (HTTPS) connections</td></tr>
74 * <tr><td>[-browser]</td>
75 * <td>Start a browser connecting to the web server</td></tr>
76 * <tr><td>[-tcp]</td>
77 * <td>Start the TCP server</td></tr>
78 * <tr><td>[-tcpAllowOthers]</td>
79 * <td>Allow other computers to connect - see below</td></tr>
80 * <tr><td>[-tcpDaemon]</td>
81 * <td>Use a daemon thread</td></tr>
82 * <tr><td>[-tcpPort &lt;port&gt;]</td>
83 * <td>The port (default: 9092)</td></tr>
84 * <tr><td>[-tcpSSL]</td>
85 * <td>Use encrypted (SSL) connections</td></tr>
86 * <tr><td>[-tcpPassword &lt;pwd&gt;]</td>
87 * <td>The password for shutting down a TCP server</td></tr>
88 * <tr><td>[-tcpShutdown "&lt;url&gt;"]</td>
89 * <td>Stop the TCP server; example: tcp://localhost</td></tr>
90 * <tr><td>[-tcpShutdownForce]</td>
91 * <td>Do not wait until all connections are closed</td></tr>
92 * <tr><td>[-pg]</td>
93 * <td>Start the PG server</td></tr>
94 * <tr><td>[-pgAllowOthers]</td>
95 * <td>Allow other computers to connect - see below</td></tr>
96 * <tr><td>[-pgDaemon]</td>
97 * <td>Use a daemon thread</td></tr>
98 * <tr><td>[-pgPort &lt;port&gt;]</td>
99 * <td>The port (default: 5435)</td></tr>
100 * <tr><td>[-properties "&lt;dir&gt;"]</td>
101 * <td>Server properties (default: ~, disable: null)</td></tr>
102 * <tr><td>[-baseDir &lt;dir&gt;]</td>
103 * <td>The base directory for H2 databases (all servers)</td></tr>
104 * <tr><td>[-ifExists]</td>
105 * <td>Only existing databases may be opened (all servers)</td></tr>
106 * <tr><td>[-trace]</td>
107 * <td>Print additional trace information (all servers)</td></tr>
108 * </table>
109 * The options -xAllowOthers are potentially risky.
110 * <br />
111 * For details, see Advanced Topics / Protection against Remote Access.
112 * @h2.resource
113 *
114 * @param args the command line arguments
115 */
116 public static void main(String... args) throws SQLException {
117 new Server().runTool(args);
118 }
119
120 private void verifyArgs(String... args) throws SQLException {
121 for (int i = 0; args != null && i < args.length; i++) {
122 String arg = args[i];
123 if (arg == null) {
124 continue;
125 } else if ("-?".equals(arg) || "-help".equals(arg)) {
126 // ok
127 } else if (arg.startsWith("-web")) {
128 if ("-web".equals(arg)) {
129 // ok
130 } else if ("-webAllowOthers".equals(arg)) {
131 // no parameters
132 } else if ("-webDaemon".equals(arg)) {
133 // no parameters
134 } else if ("-webSSL".equals(arg)) {
135 // no parameters
136 } else if ("-webPort".equals(arg)) {
137 i++;
138 } else {
139 throwUnsupportedOption(arg);
140 }
141 } else if ("-browser".equals(arg)) {
142 // ok
143 } else if (arg.startsWith("-tcp")) {
144 if ("-tcp".equals(arg)) {
145 // ok
146 } else if ("-tcpAllowOthers".equals(arg)) {
147 // no parameters
148 } else if ("-tcpDaemon".equals(arg)) {
149 // no parameters
150 } else if ("-tcpSSL".equals(arg)) {
151 // no parameters
152 } else if ("-tcpPort".equals(arg)) {
153 i++;
154 } else if ("-tcpPassword".equals(arg)) {
155 i++;
156 } else if ("-tcpShutdown".equals(arg)) {
157 i++;
158 } else if ("-tcpShutdownForce".equals(arg)) {
159 // ok
160 } else {
161 throwUnsupportedOption(arg);
162 }
163 } else if (arg.startsWith("-pg")) {
164 if ("-pg".equals(arg)) {
165 // ok
166 } else if ("-pgAllowOthers".equals(arg)) {
167 // no parameters
168 } else if ("-pgDaemon".equals(arg)) {
169 // no parameters
170 } else if ("-pgPort".equals(arg)) {
171 i++;
172 } else {
173 throwUnsupportedOption(arg);
174 }
175 } else if (arg.startsWith("-ftp")) {
176 if ("-ftpPort".equals(arg)) {
177 i++;
178 } else if ("-ftpDir".equals(arg)) {
179 i++;
180 } else if ("-ftpRead".equals(arg)) {
181 i++;
182 } else if ("-ftpWrite".equals(arg)) {
183 i++;
184 } else if ("-ftpWritePassword".equals(arg)) {
185 i++;
186 } else if ("-ftpTask".equals(arg)) {
187 // no parameters
188 } else {
189 throwUnsupportedOption(arg);
190 }
191 } else if ("-properties".equals(arg)) {
192 i++;
193 } else if ("-trace".equals(arg)) {
194 // no parameters
195 } else if ("-ifExists".equals(arg)) {
196 // no parameters
197 } else if ("-baseDir".equals(arg)) {
198 i++;
199 } else if ("-key".equals(arg)) {
200 i += 2;
201 } else if ("-tool".equals(arg)) {
202 // no parameters
203 } else {
204 throwUnsupportedOption(arg);
205 }
206 }
207 }
208
209 public void runTool(String... args) throws SQLException {
210 boolean tcpStart = false, pgStart = false, webStart = false;
211 boolean browserStart = false;
212 boolean tcpShutdown = false, tcpShutdownForce = false;
213 String tcpPassword = "";
214 String tcpShutdownServer = "";
215 boolean startDefaultServers = true;
216 for (int i = 0; args != null && i < args.length; i++) {
217 String arg = args[i];
218 if (arg == null) {
219 continue;
220 } else if ("-?".equals(arg) || "-help".equals(arg)) {
221 showUsage();
222 return;
223 } else if (arg.startsWith("-web")) {
224 if ("-web".equals(arg)) {
225 startDefaultServers = false;
226 webStart = true;
227 } else if ("-webAllowOthers".equals(arg)) {
228 // no parameters
229 } else if ("-webDaemon".equals(arg)) {
230 // no parameters
231 } else if ("-webSSL".equals(arg)) {
232 // no parameters
233 } else if ("-webPort".equals(arg)) {
234 i++;
235 } else {
236 showUsageAndThrowUnsupportedOption(arg);
237 }
238 } else if ("-browser".equals(arg)) {
239 startDefaultServers = false;
240 browserStart = true;
241 } else if (arg.startsWith("-tcp")) {
242 if ("-tcp".equals(arg)) {
243 startDefaultServers = false;
244 tcpStart = true;
245 } else if ("-tcpAllowOthers".equals(arg)) {
246 // no parameters
247 } else if ("-tcpDaemon".equals(arg)) {
248 // no parameters
249 } else if ("-tcpSSL".equals(arg)) {
250 // no parameters
251 } else if ("-tcpPort".equals(arg)) {
252 i++;
253 } else if ("-tcpPassword".equals(arg)) {
254 tcpPassword = args[++i];
255 } else if ("-tcpShutdown".equals(arg)) {
256 startDefaultServers = false;
257 tcpShutdown = true;
258 tcpShutdownServer = args[++i];
259 } else if ("-tcpShutdownForce".equals(arg)) {
260 tcpShutdownForce = true;
261 } else {
262 showUsageAndThrowUnsupportedOption(arg);
263 }
264 } else if (arg.startsWith("-pg")) {
265 if ("-pg".equals(arg)) {
266 startDefaultServers = false;
267 pgStart = true;
268 } else if ("-pgAllowOthers".equals(arg)) {
269 // no parameters
270 } else if ("-pgDaemon".equals(arg)) {
271 // no parameters
272 } else if ("-pgPort".equals(arg)) {
273 i++;
274 } else {
275 showUsageAndThrowUnsupportedOption(arg);
276 }
277 } else if ("-properties".equals(arg)) {
278 i++;
279 } else if ("-trace".equals(arg)) {
280 // no parameters
281 } else if ("-ifExists".equals(arg)) {
282 // no parameters
283 } else if ("-baseDir".equals(arg)) {
284 i++;
285 } else if ("-key".equals(arg)) {
286 i += 2;
287 } else {
288 showUsageAndThrowUnsupportedOption(arg);
289 }
290 }
291 verifyArgs(args);
292 if (startDefaultServers) {
293 tcpStart = true;
294 pgStart = true;
295 webStart = true;
296 browserStart = true;
297 }
298 // TODO server: maybe use one single properties file?
299 if (tcpShutdown) {
300 out.println("Shutting down TCP Server at " + tcpShutdownServer);
301 shutdownTcpServer(tcpShutdownServer, tcpPassword, tcpShutdownForce, false);
302 }
303 try {
304 if (webStart) {
305 web = createWebServer(args);
306 web.setShutdownHandler(this);
307 SQLException result = null;
308 try {
309 web.start();
310 } catch (Exception e) {
311 result = DbException.toSQLException(e);
312 }
313 out.println(web.getStatus());
314 // start browser in any case (even if the server is already running)
315 // because some people don't look at the output,
316 // but are wondering why nothing happens
317 if (browserStart) {
318 try {
319 openBrowser(web.getURL());
320 } catch (Exception e) {
321 out.println(e.getMessage());
322 }
323 }
324 if (result != null) {
325 throw result;
326 }
327 } else if (browserStart) {
328 out.println("The browser can only start if a web server is started (-web)");
329 }
330 if (tcpStart) {
331 tcp = createTcpServer(args);
332 tcp.start();
333 out.println(tcp.getStatus());
334 tcp.setShutdownHandler(this);
335 }
336 if (pgStart) {
337 pg = createPgServer(args);
338 pg.start();
339 out.println(pg.getStatus());
340 }
341 } catch (SQLException e) {
342 stopAll();
343 throw e;
344 }
345 }
346
347 /**
348 * Shutdown one or all TCP server. If force is set to false, the server will not
349 * allow new connections, but not kill existing connections, instead it will
350 * stop if the last connection is closed. If force is set to true, existing
351 * connections are killed. After calling the method with force=false, it is
352 * not possible to call it again with force=true because new connections are
353 * not allowed. Example:
354 *
355 * <pre>
356 * Server.shutdownTcpServer(
357 * &quot;tcp://localhost:9094&quot;, password, true, false);
358 * </pre>
359 *
360 * @param url example: tcp://localhost:9094
361 * @param password the password to use ("" for no password)
362 * @param force the shutdown (don't wait)
363 * @param all whether all TCP servers that are running in the JVM
364 * should be stopped
365 */
366 public static void shutdownTcpServer(String url, String password, boolean force, boolean all) throws SQLException {
367 TcpServer.shutdown(url, password, force, all);
368 }
369
370 /**
371 * Get the status of this server.
372 *
373 * @return the status
374 */
375 public String getStatus() {
376 StringBuilder buff = new StringBuilder();
377 if (!started) {
378 buff.append("Not started");
379 } else if (isRunning(false)) {
380 buff.append(service.getType()).
381 append(" server running at ").
382 append(service.getURL()).
383 append(" (");
384 if (service.getAllowOthers()) {
385 buff.append("others can connect");
386 } else {
387 buff.append("only local connections");
388 }
389 buff.append(')');
390 } else {
391 buff.append("The ").
392 append(service.getType()).
393 append(" server could not be started. Possible cause: another server is already running at ").
394 append(service.getURL());
395 }
396 return buff.toString();
397 }
398
399 /**
400 * Create a new web server, but does not start it yet. Example:
401 *
402 * <pre>
403 * Server server = Server.createWebServer(
404 * new String[] { "-trace" }).start();
405 * </pre>
406 *
407 * @param args the argument list
408 * @return the server
409 */
410 public static Server createWebServer(String... args) throws SQLException {
411 WebServer service = new WebServer();
412 Server server = new Server(service, args);
413 service.setShutdownHandler(server);
414 return server;
415 }
416
417 /**
418 * Create a new TCP server, but does not start it yet. Example:
419 *
420 * <pre>
421 * Server server = Server.createTcpServer(
422 * new String[] { "-tcpPort", "9123", "-tcpAllowOthers" }).start();
423 * </pre>
424 *
425 * @param args the argument list
426 * @return the server
427 */
428 public static Server createTcpServer(String... args) throws SQLException {
429 TcpServer service = new TcpServer();
430 Server server = new Server(service, args);
431 service.setShutdownHandler(server);
432 return server;
433 }
434
435 /**
436 * Create a new PG server, but does not start it yet.
437 * Example:
438 * <pre>
439 * Server server =
440 * Server.createPgServer("-pgAllowOthers").start();
441 * </pre>
442 *
443 * @param args the argument list
444 * @return the server
445 */
446 public static Server createPgServer(String... args) throws SQLException {
447 return new Server(new PgServer(), args);
448 }
449
450 /**
451 * Tries to start the server.
452 * @return the server if successful
453 * @throws SQLException if the server could not be started
454 */
455 public Server start() throws SQLException {
456 try {
457 started = true;
458 service.start();
459 String name = service.getName() + " (" + service.getURL() + ")";
460 Thread t = new Thread(this, name);
461 t.setDaemon(service.isDaemon());
462 t.start();
463 for (int i = 1; i < 64; i += i) {
464 wait(i);
465 if (isRunning(false)) {
466 return this;
467 }
468 }
469 if (isRunning(true)) {
470 return this;
471 }
472 throw DbException.get(ErrorCode.EXCEPTION_OPENING_PORT_2, name, "timeout; " +
473 "please check your network configuration, specially the file /etc/hosts");
474 } catch (DbException e) {
475 throw DbException.toSQLException(e);
476 }
477 }
478
479 private static void wait(int i) {
480 try {
481 // sleep at most 4096 ms
482 long sleep = (long) i * (long) i;
483 Thread.sleep(sleep);
484 } catch (InterruptedException e) {
485 // ignore
486 }
487 }
488
489 private void stopAll() {
490 if (web != null && web.isRunning(false)) {
491 web.stop();
492 web = null;
493 }
494 if (tcp != null && tcp.isRunning(false)) {
495 tcp.stop();
496 tcp = null;
497 }
498 if (pg != null && pg.isRunning(false)) {
499 pg.stop();
500 pg = null;
501 }
502 }
503
504 /**
505 * Checks if the server is running.
506 *
507 * @param traceError if errors should be written
508 * @return if the server is running
509 */
510 public boolean isRunning(boolean traceError) {
511 return service.isRunning(traceError);
512 }
513
514 /**
515 * Stops the server.
516 */
517 public void stop() {
518 started = false;
519 if (service != null) {
520 service.stop();
521 }
522 }
523
524 /**
525 * Gets the URL of this server.
526 *
527 * @return the url
528 */
529 public String getURL() {
530 return service.getURL();
531 }
532
533 /**
534 * Gets the port this server is listening on.
535 *
536 * @return the port
537 */
538 public int getPort() {
539 return service.getPort();
540 }
541
542 /**
543 * INTERNAL
544 */
545 public void run() {
546 try {
547 service.listen();
548 } catch (Exception e) {
549 TraceSystem.traceThrowable(e);
550 }
551 }
552
553 /**
554 * INTERNAL
555 */
556 public void setShutdownHandler(ShutdownHandler shutdownHandler) {
557 this.shutdownHandler = shutdownHandler;
558 }
559
560 /**
561 * INTERNAL
562 */
563 public void shutdown() {
564 if (shutdownHandler != null) {
565 shutdownHandler.shutdown();
566 } else {
567 stopAll();
568 }
569 }
570
571 /**
572 * Get the service attached to this server.
573 *
574 * @return the service
575 */
576 public Service getService() {
577 return service;
578 }
579
580 /**
581 * Open a new browser tab or window with the given URL.
582 *
583 * @param url the URL to open
584 */
585 public static void openBrowser(String url) throws Exception {
586 try {
587 String osName = StringUtils.toLowerEnglish(Utils.getProperty("os.name", "linux"));
588 Runtime rt = Runtime.getRuntime();
589 String browser = Utils.getProperty(SysProperties.H2_BROWSER, null);
590 if (browser != null) {
591 if (browser.startsWith("call:")) {
592 browser = browser.substring("call:".length());
593 Utils.callStaticMethod(browser, url);
594 } else if (browser.indexOf("%url") >= 0) {
595 String[] args = StringUtils.arraySplit(browser, ',', false);
596 for (int i = 0; i < args.length; i++) {
597 args[i] = StringUtils.replaceAll(args[i], "%url", url);
598 }
599 rt.exec(args);
600 } else if (osName.indexOf("windows") >= 0) {
601 rt.exec(new String[] { "cmd.exe", "/C", browser, url });
602 } else {
603 rt.exec(new String[] { browser, url });
604 }
605 return;
606 }
607 try {
608 Class<?> desktopClass = Class.forName("java.awt.Desktop");
609 // Desktop.isDesktopSupported()
610 Boolean supported = (Boolean) desktopClass.
611 getMethod("isDesktopSupported").
612 invoke(null, new Object[0]);
613 URI uri = new URI(url);
614 if (supported) {
615 // Desktop.getDesktop();
616 Object desktop = desktopClass.getMethod("getDesktop").
617 invoke(null, new Object[0]);
618 // desktop.browse(uri);
619 desktopClass.getMethod("browse", URI.class).
620 invoke(desktop, uri);
621 return;
622 }
623 } catch (Exception e) {
624 // ignore
625 }
626 if (osName.indexOf("windows") >= 0) {
627 rt.exec(new String[] { "rundll32", "url.dll,FileProtocolHandler", url });
628 } else if (osName.indexOf("mac") >= 0 || osName.indexOf("darwin") >= 0) {
629 // Mac OS: to open a page with Safari, use "open -a Safari"
630 Runtime.getRuntime().exec(new String[] { "open", url });
631 } else {
632 String[] browsers = { "google-chrome", "firefox", "mozilla-firefox",
633 "mozilla", "konqueror", "netscape", "opera", "midori" };
634 boolean ok = false;
635 for (String b : browsers) {
636 try {
637 rt.exec(new String[] { b, url });
638 ok = true;
639 break;
640 } catch (Exception e) {
641 // ignore and try the next
642 }
643 }
644 if (!ok) {
645 // No success in detection.
646 throw new Exception("Browser detection failed and system property " + SysProperties.H2_BROWSER + " not set");
647 }
648 }
649 } catch (Exception e) {
650 throw new Exception("Failed to start a browser to open the URL " + url + ": " + e.getMessage());
651 }
652 }
653
654 /**
655 * Start a web server and a browser that uses the given connection. The
656 * current transaction is preserved. This is specially useful to manually
657 * inspect the database when debugging. This method return as soon as the
658 * user has disconnected.
659 *
660 * @param conn the database connection (the database must be open)
661 */
662 public static void startWebServer(Connection conn) throws SQLException {
663 WebServer webServer = new WebServer();
664 Server web = new Server(webServer, new String[] { "-webPort", "0" });
665 web.start();
666 Server server = new Server();
667 server.web = web;
668 webServer.setShutdownHandler(server);
669 String url = webServer.addSession(conn);
670 try {
671 Server.openBrowser(url);
672 while (!webServer.isStopped()) {
673 Thread.sleep(1000);
674 }
675 } catch (Exception e) {
676 // ignore
677 }
678 }
679
680 }
681