Skip to content

Commit

Permalink
SDK-271 Add support for PostgreSQL
Browse files Browse the repository at this point in the history
  • Loading branch information
dkayiwa committed Feb 23, 2021
1 parent e234db5 commit 1bd2940
Show file tree
Hide file tree
Showing 8 changed files with 14,346 additions and 11 deletions.
6 changes: 6 additions & 0 deletions maven-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.16</version>
<scope>runtime</scope>
</dependency>

<!-- Tomcat -->
<dependency>
Expand Down
152 changes: 144 additions & 8 deletions maven-plugin/src/main/java/org/openmrs/maven/plugins/Setup.java
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,45 @@ public String setup(Server server, boolean isCreatePlatform, boolean isCopyDepen
} else if (!dbReset) {
resetSearchIndex(server);
}
} else if (server.isPostgreSqlDb()){
boolean postgresqlDbCreated = connectPostgreSqlDatabase(server);
if(!postgresqlDbCreated){
throw new IllegalStateException("Failed to connect to the specified database " + server.getDbUri());
}

if (hasDbTables(server)) {
if (dbReset == null) {
dbReset = !wizard.promptYesNo("Would you like to setup the server using existing data (if not, all data will be lost)?");
}

if (dbReset) {
wipeDatabase(server);
} else {
server.setParam("create_tables", "false");
}
}

if (dbReset == null){
dbReset = true;
}


if(!"null".equals(dbSql) && dbReset){
if(dbSql != null){
importPostgreSqlDb(server, dbSql);
resetSearchIndex(server);
} else {
if (server.getPlatformVersion() != null) {
if (new Version(server.getPlatformVersion()).higher(new Version("1.9.7"))){
importPostgreSqlDb(server, Server.CLASSPATH_SCRIPT_PREFIX+ "openmrs-platform-postgres.sql");
resetSearchIndex(server);
}
}
}
} else if (!dbReset) {
resetSearchIndex(server);
}

} else {
moduleInstaller.installModule(SDKConstants.H2_ARTIFACT, server.getServerDirectory().getPath());
installOWAs(server, distroProperties);
Expand Down Expand Up @@ -308,12 +347,17 @@ private void downloadOWAs(File targetDirectory, DistroProperties distroPropertie

private void wipeDatabase(Server server) throws MojoExecutionException {
String uri = server.getDbUri();
uri = uri.substring(0, uri.lastIndexOf("/"));
uri = uri.substring(0, uri.lastIndexOf("/") + 1);
DBConnector connector = null;
try {
connector = new DBConnector(uri, server.getDbUser(), server.getDbPassword(), server.getDbName());
connector.dropDatabase();
connectMySqlDatabase(server);
if (server.isMySqlDb()) {
connectMySqlDatabase(server);
}
else if (server.isPostgreSqlDb()) {
connectPostgreSqlDatabase(server);
}
wizard.showMessage("Database " + server.getDbName() + " has been wiped.");
} catch (SQLException e) {
throw new IllegalStateException("Failed to drop " + server.getDbName() + " database");
Expand Down Expand Up @@ -396,7 +440,7 @@ private void configureVersion(Server server, DistroProperties distroProperties)

private boolean connectMySqlDatabase(Server server) throws MojoExecutionException {
String uri = server.getDbUri();
uri = uri.substring(0, uri.lastIndexOf("/"));
uri = uri.substring(0, uri.lastIndexOf("/") + 1);
DBConnector connector = null;
try {
try {
Expand All @@ -406,7 +450,7 @@ private boolean connectMySqlDatabase(Server server) throws MojoExecutionExceptio
throw new RuntimeException("Failed to load MySQL driver");
}
connector = new DBConnector(uri, server.getDbUser(), server.getDbPassword(), server.getDbName());
connector.checkAndCreate();
connector.checkAndCreate(server);
connector.close();
wizard.showMessage("Connected to the database.");
return true;
Expand All @@ -422,10 +466,39 @@ private boolean connectMySqlDatabase(Server server) throws MojoExecutionExceptio
}
}
}

private boolean connectPostgreSqlDatabase(Server server) throws MojoExecutionException {
String uri = server.getDbUri();
uri = uri.substring(0, uri.lastIndexOf("/") + 1);
DBConnector connector = null;
try {
try {
//ensure driver is registered
Class.forName("org.postgresql.Driver");
} catch (ClassNotFoundException e) {
throw new RuntimeException("Failed to load PostgreSQL driver", e);
}
connector = new DBConnector(uri, server.getDbUser(), server.getDbPassword(), server.getDbName());
connector.checkAndCreate(server);
connector.close();
wizard.showMessage("Connected to the database.");
return true;
} catch (Exception e) {
return false;
} finally {
if (connector != null){
try {
connector.close();
} catch (SQLException e) {
getLog().error(e.getMessage());
}
}
}
}

private boolean hasDbTables(Server server) throws MojoExecutionException {
String uri = server.getDbUri();
uri = uri.substring(0, uri.lastIndexOf("/"));
uri = uri.substring(0, uri.lastIndexOf("/") + 1);
DBConnector connector = null;
ResultSet rs = null;
try {
Expand All @@ -443,7 +516,7 @@ private boolean hasDbTables(Server server) throws MojoExecutionException {

return hasTables;
} catch (SQLException e) {
throw new IllegalStateException("Failed to fetch table list from \"" + server.getDbName() + "\" database.");
throw new IllegalStateException("Failed to fetch table list from \"" + server.getDbName() + "\" database.", e);
} finally {
if (rs != null) {
try {
Expand All @@ -464,11 +537,11 @@ private boolean hasDbTables(Server server) throws MojoExecutionException {

private void resetSearchIndex(Server server) throws MojoExecutionException {
String uri = server.getDbUri();
uri = uri.substring(0, uri.lastIndexOf("/"));
uri = uri.substring(0, uri.lastIndexOf("/") + 1);
DBConnector connector = null;
PreparedStatement ps = null;
try {
connector = new DBConnector(uri, server.getDbUser(), server.getDbPassword(), server.getDbName());
connector = new DBConnector(uri + server.getDbName(), server.getDbUser(), server.getDbPassword(), server.getDbName());
ps = connector.getConnection().prepareStatement(String.format(SDKConstants.RESET_SEARCH_INDEX_SQL, server.getDbName()));
ps.execute();

Expand Down Expand Up @@ -558,6 +631,69 @@ private void importMysqlDb(Server server, String sqlScriptPath) throws MojoExecu
}
}
}

private void importPostgreSqlDb(Server server, String sqlScriptPath) throws MojoExecutionException {
wizard.showMessage("Importing an initial database from " + sqlScriptPath + "...");
String uri = server.getDbUri().replace("@DBNAME@", server.getDbName());

File extractedSqlFile = null;
InputStream sqlStream;
Reader sqlReader;
if(sqlScriptPath.startsWith(Server.CLASSPATH_SCRIPT_PREFIX)){
String sqlScript = sqlScriptPath.replace(Server.CLASSPATH_SCRIPT_PREFIX, "");
sqlStream = (Setup.class.getClassLoader().getResourceAsStream(sqlScript));
if(sqlStream == null){
Artifact distroArtifact = new Artifact(server.getDistroArtifactId(), server.getVersion(), server.getDistroGroupId(), "jar");
extractedSqlFile = distroHelper.extractFileFromDistro(server.getServerDirectory(), distroArtifact, sqlScript);
try {
sqlStream = new FileInputStream(extractedSqlFile);
} catch (FileNotFoundException e) {
throw new MojoExecutionException("Error during opening sql dump script file", e);
}
}
} else {
File scriptFile = new File(sqlScriptPath);
try {
sqlStream = new FileInputStream(scriptFile);
} catch (FileNotFoundException e) {
throw new RuntimeException("Invalid path to SQL import script", e);
}
}

sqlReader = new InputStreamReader(sqlStream);
Connection connection = null;
try {
connection = DriverManager.getConnection(uri, server.getDbUser(), server.getDbPassword());
ScriptRunner scriptRunner = new ScriptRunner(connection);
//we don't want to display ~5000 lines of queries to user if there is no error
scriptRunner.setLogWriter(new PrintWriter(new NullOutputStream()));
scriptRunner.setStopOnError(true);
scriptRunner.runScript(sqlReader);
scriptRunner.closeConnection();
sqlReader.close();
wizard.showMessage("Database imported successfully.");
server.setParam("create_tables", "false");
} catch (Exception e) {
getLog().error(e.getMessage());

throw new MojoExecutionException("Failed to import database", e);
} finally {
IOUtils.closeQuietly(sqlReader);

try {
if(connection != null){
connection.close();
}
} catch (SQLException e1) {
//close quietly
}

//this file is extracted from distribution, clean it up
if(extractedSqlFile != null && extractedSqlFile.exists()){
extractedSqlFile.delete();
}
}
}

public String determineDbName(String uri, String serverId) throws MojoExecutionException {
String dbName = String.format(SDKConstants.DB_NAME_TEMPLATE, serverId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,10 @@ public void setDbDriver(String dbDriver) {
public boolean isMySqlDb() {
return getDbUri().startsWith("jdbc:mysql") || getDbDriver().equals(SDKConstants.DRIVER_MYSQL);
}

public boolean isPostgreSqlDb() {
return getDbUri().startsWith("jdbc:postgresql") || getDbDriver().equals(SDKConstants.DRIVER_POSTGRESQL);
}

public String getDbUri() {
return getParam(PROPERTY_DB_URI);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import java.sql.SQLException;
import java.sql.Statement;

import org.openmrs.maven.plugins.model.Server;

public class DBConnector {
Connection conn;
String dbName;
Expand All @@ -19,9 +21,12 @@ public DBConnector(String url, String user, String pass, String dbName) throws S
* Create db if not exists
* @throws SQLException
*/
public void checkAndCreate() throws SQLException {
public void checkAndCreate(Server server) throws SQLException {
Statement stmt = conn.createStatement();
String query = String.format("create database if not exists `%s` default character set utf8", dbName);
if (server.isPostgreSqlDb()) {
query = String.format("create database %s encoding 'utf8'", dbName);
}
stmt.executeUpdate(query);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public class DefaultWizard implements Wizard {
public static final String DB_OPTION_MYSQL = "MySQL 5.6 (requires pre-installed MySQL 5.6)";
public static final String DB_OPTION_SDK_DOCKER_MYSQL = "MySQL 5.6 in SDK docker container (requires pre-installed Docker)";
public static final String DB_OPTION_DOCKER_MYSQL = "Existing docker container (requires pre-installed Docker)";
public static final String DB_OPTION_POSTGRESQL = "PostgreSQL 8.2 and above";
public static final Map<String,String> DB_OPTIONS_MAP = new HashMap<String, String>() {{
put("mysql", DB_OPTION_MYSQL);
put("h2", DB_OPTION_H2);
Expand Down Expand Up @@ -690,6 +691,9 @@ public void promptForDb(Server server, DockerHelper dockerHelper, boolean h2supp
List<String> options = new ArrayList<>();
if(h2supported) options.add(DB_OPTION_H2);
options.addAll(Lists.newArrayList(DB_OPTION_MYSQL, DB_OPTION_SDK_DOCKER_MYSQL, DB_OPTION_DOCKER_MYSQL));
if (isAbovePlatformTwoPointThree(new Version(server.getPlatformVersion()))) {
options.add(DB_OPTION_POSTGRESQL);
}
db = promptForMissingValueWithOptions("Which database would you like to use?", db, null, options);
switch(db){
case(DB_OPTION_H2): {
Expand All @@ -712,6 +716,10 @@ public void promptForDb(Server server, DockerHelper dockerHelper, boolean h2supp
case(DB_OPTION_DOCKER_MYSQL):{
promptForDockerizedDb(server, dockerHelper, dockerHost);
}
case(DB_OPTION_POSTGRESQL):{
promptForPostgreSQLDb(server);
break;
}
}
}

Expand All @@ -731,6 +739,23 @@ public void promptForMySQLDb(Server server) throws MojoExecutionException {
server.setDbUri(dbUri);
promptForDbCredentialsIfMissing(server);
}

@Override
public void promptForPostgreSQLDb(Server server) throws MojoExecutionException {
if(server.getDbDriver() == null){
server.setDbDriver(SDKConstants.DRIVER_POSTGRESQL);
}
String dbUri = promptForValueIfMissingWithDefault(
"The distribution requires PostgreSQL database. Please specify database uri (-D%s)",
server.getDbUri(), "dbUri", SDKConstants.URI_POSTGRESQL);
if (dbUri.startsWith("jdbc:postgresql:")) {
dbUri = addPostgreSQLParamsIfMissing(dbUri);
}
dbUri = dbUri.replace(DBNAME_URL_VARIABLE, server.getServerId());

server.setDbUri(dbUri);
promptForDbCredentialsIfMissing(server);
}

public void promptForDockerizedSdkMysql(Server server, DockerHelper dockerHelper, String dockerHost) throws MojoExecutionException {
promptForDockerHostIfMissing(dockerHelper, dockerHost);
Expand Down Expand Up @@ -904,6 +929,10 @@ private String getDefaultUri(String dockerHost) {
@Override
public void promptForDbCredentialsIfMissing(Server server) {
String defaultUser = "root";
if (server.isPostgreSqlDb()) {
defaultUser = "postgres";
}

String user = promptForValueIfMissingWithDefault(
"Please specify database username (-D%s)",
server.getDbUser(), "dbUser", defaultUser);
Expand Down Expand Up @@ -951,6 +980,23 @@ public String addMySQLParamsIfMissing(String dbUri) {

return "jdbc:" + uri.toString();
}

@Override
public String addPostgreSQLParamsIfMissing(String dbUri) {
String noJdbc = dbUri.substring(5);

URIBuilder uri;
try {
uri = new URIBuilder(noJdbc);
} catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
uri.setParameter("autoReconnect", "true");
uri.setParameter("useUnicode", "true");
uri.setParameter("characterEncoding", "UTF-8");

return "jdbc:" + uri.toString();
}

public Log getLog() {
if(log == null){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public class SDKConstants {
// dbUri for different db
public static final String URI_MYSQL = "jdbc:mysql://localhost:3306/@DBNAME@";
public static final String URI_MYSQL_DOCKER = "jdbc:mysql://%s:3306/@DBNAME@";
public static final String URI_POSTGRESQL = "jdbc:postgresql://localhost:5740/@DBNAME@";
public static final String URI_POSTGRESQL = "jdbc:postgresql://localhost:5432/@DBNAME@";
public static final String URI_H2 = "jdbc:h2:@APPLICATIONDATADIR@/database/@DBNAME@;AUTO_RECONNECT=TRUE;DB_CLOSE_DELAY=-1";
// dbDriver class for different db
public static final String DRIVER_MYSQL = "com.mysql.jdbc.Driver";
Expand Down Expand Up @@ -91,7 +91,7 @@ public class SDKConstants {

public final static String NPM_VERSION = "^3.10.3";
public final static String NODE_VERSION = "^6.4.0";
public static final String RESET_SEARCH_INDEX_SQL = "DELETE FROM `%s`.global_property WHERE property = 'search.indexVersion';";
public static final String RESET_SEARCH_INDEX_SQL = "DELETE FROM global_property WHERE property = 'search.indexVersion';";

/**
* Get core modules with required versions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public interface Wizard {
void promptForDb(Server server, DockerHelper dockerHelper, boolean h2supported, String dbDriver, String dockerHost) throws MojoExecutionException;

public void promptForMySQLDb(Server server) throws MojoExecutionException;

public void promptForPostgreSQLDb(Server server) throws MojoExecutionException;

void promptForDbCredentialsIfMissing(Server server);

Expand Down Expand Up @@ -65,6 +67,8 @@ public interface Wizard {
List<String> getListOfServers();

String addMySQLParamsIfMissing(String dbUri);

String addPostgreSQLParamsIfMissing(String dbUri);

void showJdkErrorMessage(String jdk, String platform, String recommendedJdk, String pathToProps);

Expand Down
Loading

0 comments on commit 1bd2940

Please sign in to comment.