1 package de.funfried.maven.plugin.zonky;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.sql.Connection;
6 import java.sql.SQLException;
7 import java.sql.Statement;
8 import java.util.HashMap;
9 import java.util.List;
10 import java.util.Map;
11 import java.util.UUID;
12 import java.util.concurrent.TimeoutException;
13
14 import javax.sql.DataSource;
15
16 import org.apache.maven.plugin.AbstractMojo;
17 import org.apache.maven.plugin.MojoExecutionException;
18 import org.apache.maven.plugins.annotations.LifecyclePhase;
19 import org.apache.maven.plugins.annotations.Mojo;
20 import org.apache.maven.plugins.annotations.Parameter;
21 import org.apache.maven.project.MavenProject;
22
23 import de.funfried.maven.plugin.zonky.utils.AlreadyStartedPolicy;
24 import de.funfried.maven.plugin.zonky.utils.MavenProjectUtil;
25 import de.funfried.maven.plugin.zonky.utils.ZonkyUtil;
26 import io.zonky.test.db.postgres.embedded.EmbeddedPostgres;
27
28
29
30
31 @Mojo(name = "start", defaultPhase = LifecyclePhase.INITIALIZE, requiresProject = true, threadSafe = false)
32 public class StartEmbeddedPostgresMojo extends AbstractMojo {
33
34
35
36 @Parameter(defaultValue = "0", property = "port")
37 private int port;
38
39
40
41
42 @Parameter(defaultValue = "true", property = "createDatabase")
43 private boolean createDatabase;
44
45
46
47
48 @Parameter(defaultValue = "true", property = "singleInstance")
49 private boolean singleInstance;
50
51
52
53
54 @Parameter(defaultValue = "data", property = "databaseName")
55 private String databaseName;
56
57
58
59
60
61
62
63
64
65
66 @Parameter(defaultValue = "reinit", property = "onAlreadyStarted")
67 private AlreadyStartedPolicy onAlreadyStarted;
68
69
70
71
72 @Parameter(defaultValue = "${project.build.directory}/embedded-postgres/work", property = "workingDirectory")
73 private String workingDirectory;
74
75
76
77
78 @Parameter(defaultValue = "${project.build.directory}/embedded-postgres/data", property = "dataDirectory")
79 private String dataDirectory;
80
81
82
83
84 @Parameter(defaultValue = "${project}", required = true, readonly = true)
85 private MavenProject project;
86
87
88
89
90 @Parameter(defaultValue = "${reactorProjects}", readonly = true, required = true)
91 private List<MavenProject> reactorProjects;
92
93
94
95
96
97
98 @Override
99 public void execute() throws MojoExecutionException {
100 EmbeddedPostgres pg = MavenProjectUtil.getProjectProperty(project, singleInstance ? reactorProjects : null, MavenProjectUtil.PROP_DB_INSTANCE);
101 if (pg != null) {
102 if (AlreadyStartedPolicy.fail.equals(onAlreadyStarted)) {
103 throw new MojoExecutionException("Embedded database already started.");
104 }
105
106 if (AlreadyStartedPolicy.reinit.equals(onAlreadyStarted)) {
107 DataSource dataSource = pg.getDatabase("postgres", "postgres");
108 try (Connection connection = dataSource.getConnection()) {
109 try (Statement stmt = connection.createStatement()) {
110 stmt.execute("DROP DATABASE \"" + databaseName + "\";");
111
112 if (createDatabase) {
113 stmt.execute("CREATE DATABASE \"" + databaseName + "\";");
114 }
115 }
116 } catch (SQLException ex) {
117 throw new MojoExecutionException("Failed to reset embedded database", ex);
118 }
119
120 String workDir = MavenProjectUtil.getProjectProperty(project, singleInstance ? reactorProjects : null, MavenProjectUtil.PROP_WORK_DIRECTORY);
121 String dataDir = MavenProjectUtil.getProjectProperty(project, singleInstance ? reactorProjects : null, MavenProjectUtil.PROP_DATA_DIRECTORY);
122
123 File workDirFile = new File(workDir);
124 File dataDirFile = new File(dataDir);
125
126 started(pg, workDirFile, dataDirFile);
127
128 getLog().info("Embedded postgres database reinitialized");
129 } else if (AlreadyStartedPolicy.restart.equals(onAlreadyStarted)) {
130 try {
131 String workDir = MavenProjectUtil.getProjectProperty(project, singleInstance ? reactorProjects : null, MavenProjectUtil.PROP_WORK_DIRECTORY);
132 String dataDir = MavenProjectUtil.getProjectProperty(project, singleInstance ? reactorProjects : null, MavenProjectUtil.PROP_DATA_DIRECTORY);
133
134 File workDirFile = new File(workDir);
135 File dataDirFile = new File(dataDir);
136
137 ZonkyUtil.stop(pg, workDirFile, dataDirFile);
138
139 start(port, workDirFile, dataDirFile);
140 } catch (IOException | InterruptedException | TimeoutException ex) {
141 getLog().error("Failed to stop database", ex);
142 }
143 }
144 } else {
145 String subDir = UUID.randomUUID().toString();
146
147 start(port, new File(workingDirectory, subDir), new File(dataDirectory, subDir));
148 }
149 }
150
151 private EmbeddedPostgres start(int port, File workingDirectory, File dataDirectory) throws MojoExecutionException {
152 EmbeddedPostgres pg;
153
154 try {
155 pg = ZonkyUtil.start(port, workingDirectory, dataDirectory);
156
157 if (createDatabase) {
158 DataSource dataSource = pg.getDatabase("postgres", "postgres");
159 try (Connection connection = dataSource.getConnection()) {
160 try (Statement stmt = connection.createStatement()) {
161 stmt.execute("DROP DATABASE IF EXISTS \"" + databaseName + "\";");
162 stmt.execute("CREATE DATABASE \"" + databaseName + "\";");
163 }
164 } catch (SQLException ex) {
165 throw new MojoExecutionException("Failed to create embedded database '" + databaseName + "'", ex);
166 }
167 }
168
169 started(pg, workingDirectory, dataDirectory);
170 } catch (IOException ex) {
171 throw new MojoExecutionException("Failed to start embedded database", ex);
172 }
173
174 return pg;
175 }
176
177 private void started(EmbeddedPostgres pg, File workingDirectory, File dataDirectory) {
178 int pgPort = pg.getPort();
179 String jdbcUrl = pg.getJdbcUrl("postgres", databaseName);
180
181 getLog().info("Started embedded postgres database at port " + pgPort + " (JDBC URL: " + jdbcUrl + ")");
182
183 Map<String, Object> properties = new HashMap<>();
184 properties.put(MavenProjectUtil.PROP_HOST, "localhost");
185 properties.put(MavenProjectUtil.PROP_PORT, pgPort);
186 properties.put(MavenProjectUtil.PROP_DATABASE, databaseName);
187 properties.put(MavenProjectUtil.PROP_USERNAME, "postgres");
188 properties.put(MavenProjectUtil.PROP_PASSWORD, "postgres");
189 properties.put(MavenProjectUtil.PROP_JDBC_URL, jdbcUrl);
190 properties.put(MavenProjectUtil.PROP_WORK_DIRECTORY, workingDirectory.getAbsolutePath());
191 properties.put(MavenProjectUtil.PROP_DATA_DIRECTORY, dataDirectory.getAbsolutePath());
192 properties.put(MavenProjectUtil.PROP_DB_INSTANCE, pg);
193
194 MavenProjectUtil.putProjectProperty(project, singleInstance ? reactorProjects : null, properties);
195 }
196 }