View Javadoc
1   package de.funfried.maven.plugin.zonky;
2   
3   import java.io.IOException;
4   import java.sql.Connection;
5   import java.sql.SQLException;
6   import java.sql.Statement;
7   import java.util.List;
8   
9   import javax.sql.DataSource;
10  
11  import org.apache.maven.plugin.AbstractMojo;
12  import org.apache.maven.plugin.MojoExecutionException;
13  import org.apache.maven.plugins.annotations.LifecyclePhase;
14  import org.apache.maven.plugins.annotations.Mojo;
15  import org.apache.maven.plugins.annotations.Parameter;
16  import org.apache.maven.project.MavenProject;
17  
18  import de.funfried.maven.plugin.zonky.utils.AlreadyStartedPolicy;
19  import de.funfried.maven.plugin.zonky.utils.ZonkyUtil;
20  import io.zonky.test.db.postgres.embedded.EmbeddedPostgres;
21  
22  /**
23   * Goal which starts an embedded postgres database.
24   */
25  @Mojo(name = "start", defaultPhase = LifecyclePhase.INITIALIZE, requiresProject = true, threadSafe = true)
26  public class StartEmbeddedPostgresMojo extends AbstractMojo {
27  	/**
28  	 * The port on which the database will be accessible. A value less than or equal to 0 means auto detect a free port. The port is available through the property ${zonky.port}.
29  	 */
30  	@Parameter(defaultValue = "0", property = "port")
31  	private int port;
32  
33  	/**
34  	 * If {@code true}, a create database statement with the given database name will be executed on startup.
35  	 */
36  	@Parameter(defaultValue = "true", property = "createDatabase")
37  	private boolean createDatabase;
38  
39  	/**
40  	 * The database name to write your data. Should not be postgres!
41  	 */
42  	@Parameter(defaultValue = "data", property = "databaseName")
43  	private String databaseName;
44  
45  	/**
46  	 * Define what should be done when the database is already started and the start goal is called again. Choose between:
47  	 * <ul>
48  	 * <li>fail (lets the build fail)</li>
49  	 * <li>reinit (drops the database and if "createDatabase" is true recreates the database again)</li>
50  	 * <li>ignore (just keeps the current database and does not start a new one)</li>
51  	 * </ul>
52  	 */
53  	@Parameter(defaultValue = "reinit", property = "onAlreadyStarted")
54  	private AlreadyStartedPolicy onAlreadyStarted;
55  
56  	/**
57  	 * The working directory for the embedded database.
58  	 */
59  	@Parameter(defaultValue = "${project.build.directory}/embedded-postgres/work", property = "workingDirectory")
60  	private String workingDirectory;
61  
62  	/**
63  	 * The data directory for the embedded database.
64  	 */
65  	@Parameter(defaultValue = "${project.build.directory}/embedded-postgres/data", property = "dataDirectory")
66  	private String dataDirectory;
67  
68  	/**
69  	 * The maven project.
70  	 */
71  	@Parameter(defaultValue = "${project}", required = true, readonly = true)
72  	private MavenProject project;
73  
74  	/**
75  	 * Contains the full list of projects in the reactor.
76  	 */
77  	@Parameter(defaultValue = "${reactorProjects}", readonly = true, required = true)
78  	private List<MavenProject> reactorProjects;
79  
80  	/**
81  	 * Starts the embedded postgres database.
82  	 *
83  	 * @throws MojoExecutionException if an error occurs
84  	 */
85  	@Override
86  	public void execute() throws MojoExecutionException {
87  		EmbeddedPostgres pg;
88  
89  		Object obj = project.getProperties().get("zonky");
90  		if (obj != null && obj instanceof EmbeddedPostgres) {
91  			if (AlreadyStartedPolicy.fail.equals(onAlreadyStarted)) {
92  				throw new MojoExecutionException("Embedded database already started.");
93  			}
94  
95  			pg = (EmbeddedPostgres) obj;
96  
97  			if (AlreadyStartedPolicy.reinit.equals(onAlreadyStarted)) {
98  				DataSource dataSource = pg.getDatabase("postgres", "postgres");
99  				try (Connection connection = dataSource.getConnection()) {
100 					try (Statement stmt = connection.createStatement()) {
101 						stmt.execute("DROP DATABASE \"" + databaseName + "\";");
102 
103 						if (createDatabase) {
104 							stmt.execute("CREATE DATABASE \"" + databaseName + "\";");
105 						}
106 					}
107 				} catch (SQLException ex) {
108 					throw new MojoExecutionException("Failed to reset embedded database", ex);
109 				}
110 
111 				System.out.println("Embedded postgres database reinitialized");
112 			}
113 		} else {
114 			start(port);
115 		}
116 	}
117 
118 	private EmbeddedPostgres start(int port) throws MojoExecutionException {
119 		EmbeddedPostgres pg;
120 
121 		try {
122 			pg = ZonkyUtil.start(port, workingDirectory, dataDirectory);
123 
124 			if (createDatabase) {
125 				DataSource dataSource = pg.getDatabase("postgres", "postgres");
126 				try (Connection connection = dataSource.getConnection()) {
127 					try (Statement stmt = connection.createStatement()) {
128 						stmt.execute("DROP DATABASE IF EXISTS \"" + databaseName + "\";");
129 						stmt.execute("CREATE DATABASE \"" + databaseName + "\";");
130 					}
131 				} catch (SQLException ex) {
132 					throw new MojoExecutionException("Failed to create embedded database '" + databaseName + "'", ex);
133 				}
134 			}
135 
136 			started(pg);
137 		} catch (IOException ex) {
138 			throw new MojoExecutionException("Failed to start embedded database", ex);
139 		}
140 
141 		return pg;
142 	}
143 
144 	private void started(EmbeddedPostgres pg) {
145 		int pgPort = pg.getPort();
146 		String jdbcUrl = pg.getJdbcUrl("postgres", databaseName);
147 
148 		System.out.println("Started embedded postgres database at port " + pgPort + " (JDBC URL: " + jdbcUrl + ")");
149 
150 		project.getProperties().put("zonky.host", "localhost");
151 		project.getProperties().put("zonky.port", pgPort);
152 		project.getProperties().put("zonky.database", databaseName);
153 		project.getProperties().put("zonky.username", "postgres");
154 		project.getProperties().put("zonky.password", "postgres");
155 		project.getProperties().put("zonky.jdbcUrl", jdbcUrl);
156 		project.getProperties().put("zonky", pg);
157 
158 		for (MavenProject p : reactorProjects) {
159 			p.getProperties().put("zonky.host", "localhost");
160 			p.getProperties().put("zonky.port", pgPort);
161 			p.getProperties().put("zonky.database", databaseName);
162 			p.getProperties().put("zonky.username", "postgres");
163 			p.getProperties().put("zonky.password", "postgres");
164 			p.getProperties().put("zonky.jdbcUrl", jdbcUrl);
165 			p.getProperties().put("zonky", pg);
166 		}
167 	}
168 }