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