forked from liquibase/liquibase
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor start-h2 logic (liquibase#2597)
* Refactored startH2 command so the logic is contained in StartH2CommandStep and the old start-h2 standalone script is just a call to `liquibase init start-h2` * Improved "init start-h2" shutdown messaging and busy-wait logic * Updated docs to use `liquibase init start-h2` instead of `./start-h2`
- Loading branch information
Showing
11 changed files
with
224 additions
and
232 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
169 changes: 169 additions & 0 deletions
169
liquibase-core/src/main/java/liquibase/command/core/StartH2CommandStep.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
package liquibase.command.core; | ||
|
||
import liquibase.Scope; | ||
import liquibase.command.*; | ||
import liquibase.configuration.ConfigurationValueObfuscator; | ||
|
||
import java.sql.Connection; | ||
import java.sql.DriverManager; | ||
|
||
public class StartH2CommandStep extends AbstractCommandStep { | ||
|
||
public static final String[] COMMAND_NAME = {"init", "startH2"}; | ||
|
||
public static final CommandArgumentDefinition<String> BIND_ARG; | ||
public static final CommandArgumentDefinition<Integer> DB_PORT_ARG; | ||
public static final CommandArgumentDefinition<Integer> WEB_PORT_ARG; | ||
public static final CommandArgumentDefinition<String> USERNAME_ARG; | ||
public static final CommandArgumentDefinition<String> PASSWORD_ARG; | ||
public static final CommandArgumentDefinition<Boolean> LAUNCH_BROWSER_ARG; | ||
|
||
static { | ||
CommandBuilder builder = new CommandBuilder(COMMAND_NAME); | ||
DB_PORT_ARG = builder.argument("dbPort", Integer.class) | ||
.description("Port to run h2 database on") | ||
.defaultValue(9090) | ||
.build(); | ||
|
||
WEB_PORT_ARG = builder.argument("webPort", Integer.class) | ||
.description("Port to run h2's web interface on") | ||
.defaultValue(8080) | ||
.build(); | ||
|
||
USERNAME_ARG = builder.argument("username", String.class) | ||
.description("Username to create in h2") | ||
.defaultValue("dbuser") | ||
.build(); | ||
|
||
PASSWORD_ARG = builder.argument("password", String.class) | ||
.description("Password to use for created h2 user") | ||
.defaultValue("letmein") | ||
.setValueObfuscator(ConfigurationValueObfuscator.STANDARD) | ||
.build(); | ||
|
||
BIND_ARG = builder.argument("bindAddress", String.class) | ||
.description("Network address to bind to") | ||
.defaultValue("127.0.0.1") | ||
.build(); | ||
|
||
LAUNCH_BROWSER_ARG = builder.argument("launchBrowser", Boolean.class) | ||
.description("Whether to open a browser to the database's web interface") | ||
.defaultValue(true) | ||
.build(); | ||
} | ||
|
||
@Override | ||
public void run(CommandResultsBuilder resultsBuilder) throws Exception { | ||
final CommandScope commandScope = resultsBuilder.getCommandScope(); | ||
|
||
System.setProperty("h2.bindAddress", commandScope.getConfiguredValue(BIND_ARG).getValue()); | ||
|
||
System.out.println("Starting Example H2 Database..."); | ||
System.out.println("NOTE: The database does not persist data, so stopping and restarting this process will reset it back to a blank database"); | ||
System.out.println(); | ||
|
||
try { | ||
Class.forName("org.h2.Driver"); | ||
} catch (ClassNotFoundException e) { | ||
String msg = "ERROR: H2 was not configured properly. To use Liquibase and H2, you need to have the H2 JDBC driver jar file in liquibase/lib. Learn more at https://docs.liquibase.com/"; | ||
System.out.println(msg); | ||
throw e; | ||
} | ||
|
||
final String username = commandScope.getConfiguredValue(USERNAME_ARG).getValue(); | ||
final String password = commandScope.getConfiguredValue(PASSWORD_ARG).getValue(); | ||
final Integer dbPort = commandScope.getConfiguredValue(DB_PORT_ARG).getValue(); | ||
final Integer webPort = commandScope.getConfiguredValue(WEB_PORT_ARG).getValue(); | ||
|
||
try (Connection devConnection = DriverManager.getConnection("jdbc:h2:mem:dev", username, password); | ||
Connection intConnection = DriverManager.getConnection("jdbc:h2:mem:integration", username, password)) { | ||
|
||
startTcpServer(dbPort); | ||
|
||
Object webServer = startWebServer(webPort); | ||
String devUrl = createWebSession(devConnection, webServer, commandScope.getConfiguredValue(LAUNCH_BROWSER_ARG).getValue()); | ||
String intUrl = createWebSession(intConnection, webServer, false); | ||
|
||
System.out.println("Connection Information:" + System.lineSeparator() + | ||
" Dev database: " + System.lineSeparator() + | ||
" JDBC URL: jdbc:h2:tcp://localhost:" + dbPort + "/mem:dev" + System.lineSeparator() + | ||
" Username: " + username + System.lineSeparator() + | ||
" Password: " + password + System.lineSeparator() + | ||
" Integration database: " + System.lineSeparator() + | ||
" JDBC URL: jdbc:h2:tcp://localhost:" + dbPort + "/mem:integration" + System.lineSeparator() + | ||
" Username: " + username + System.lineSeparator() + | ||
" Password: " + password + System.lineSeparator() + | ||
"" + System.lineSeparator() + | ||
"Opening Database Console in Browser..." + System.lineSeparator() + | ||
" Dev Web URL: " + devUrl + System.lineSeparator() + | ||
" Integration Web URL: " + intUrl + System.lineSeparator()); | ||
|
||
|
||
Runtime.getRuntime().addShutdownHook(new Thread(() -> { | ||
Scope.getCurrentScope().getUI().sendMessage("Shutting down H2 database..."); | ||
})); | ||
|
||
Thread.sleep(Long.MAX_VALUE); | ||
} catch (InterruptedException e) { | ||
throw e; | ||
} catch (Throwable e) { | ||
e.printStackTrace(); | ||
System.exit(-1); | ||
} | ||
|
||
resultsBuilder.addResult("statusCode", 0); | ||
} | ||
|
||
@Override | ||
public String[][] defineCommandNames() { | ||
return new String[][]{COMMAND_NAME}; | ||
} | ||
|
||
@Override | ||
public void adjustCommandDefinition(CommandDefinition commandDefinition) { | ||
super.adjustCommandDefinition(commandDefinition); | ||
commandDefinition.setShortDescription( | ||
"Launches H2, an included open source in-memory database. This Java application is shipped with Liquibase, and is useful in the Getting Started experience and for testing out Liquibase commands."); | ||
commandDefinition.setGroupShortDescription(new String[]{"init"}, "Init commands"); | ||
} | ||
|
||
protected static void startTcpServer(Integer dbPort) throws Exception { | ||
final Class<?> serverClass = Class.forName("org.h2.tools.Server"); | ||
final Object tcpServer = serverClass.getMethod("createTcpServer", String[].class) | ||
.invoke(null, (Object) new String[]{"-tcpAllowOthers", "-tcpPort", dbPort.toString()}); | ||
|
||
tcpServer.getClass().getMethod("start") | ||
.invoke(tcpServer); | ||
} | ||
|
||
protected static Object startWebServer(Integer webPort) throws Exception { | ||
final Class<?> serverClass = Class.forName("org.h2.tools.Server"); | ||
|
||
final Object webServer = Class.forName("org.h2.server.web.WebServer").newInstance(); | ||
Object web = serverClass.getConstructor(Class.forName("org.h2.server.Service"), String[].class).newInstance(webServer, (Object) new String[]{"-webPort", webPort.toString()}); | ||
web.getClass().getMethod("start").invoke(web); | ||
|
||
return webServer; | ||
} | ||
|
||
private static String createWebSession(Connection connection, Object webServer, boolean openBrowser) throws Exception { | ||
final Class<?> serverClass = Class.forName("org.h2.tools.Server"); | ||
|
||
String url = (String) webServer.getClass().getMethod("addSession", Connection.class).invoke(webServer, connection); | ||
|
||
if (openBrowser) { | ||
try { | ||
serverClass.getMethod("openBrowser", String.class).invoke(null, url); | ||
} catch (Exception e) { | ||
String message = e.getMessage(); | ||
if (message == null && e.getCause() != null) { | ||
message = e.getCause().getMessage(); | ||
} | ||
System.out.println("Cannot open browser: "+ message); | ||
System.out.println(""); | ||
} | ||
} | ||
|
||
return url; | ||
} | ||
} |
112 changes: 0 additions & 112 deletions
112
liquibase-core/src/main/java/liquibase/example/StartH2Main.java
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.