001package io.ebean.docker.commands;
002
003import io.ebean.docker.container.ContainerConfig;
004
005import java.sql.Connection;
006import java.sql.SQLException;
007import java.util.Properties;
008
009/**
010 * Configuration for an DBMS like Postgres, MySql, Oracle, SQLServer
011 */
012public abstract class BaseConfig implements ContainerConfig {
013
014  /**
015   * The database platform.
016   * <p>
017   * Expected to be one of 'postgres','mysql', 'oracle' or 'sqlserver'.
018   */
019  protected final String platform;
020
021  /**
022   * Container name.
023   */
024  protected String containerName;
025
026  /**
027   * The host name. When running in Docker this is often set to <code>172.17.0.1</code.
028   */
029  protected String host = "localhost";
030
031  /**
032   * The exposed port.
033   */
034  protected int port;
035
036  /**
037   * The internal port.
038   */
039  protected int internalPort;
040
041  /**
042   * The exposed port.
043   */
044  protected int adminPort;
045
046  /**
047   * The internal port.
048   */
049  protected int adminInternalPort;
050
051  /**
052   * Image name.
053   */
054  protected String image;
055
056  /**
057   * The mode used when starting (create, dropCreate, container [only]).
058   */
059  protected StartMode startMode = StartMode.Create;
060
061  /**
062   * The mode used when stopping (stop, remove).
063   */
064  protected StopMode stopMode = StopMode.Stop;
065
066  /**
067   * Set when we want to automatically stop or remove the container via JVM shutdown hook.
068   */
069  protected StopMode shutdownMode = StopMode.None;
070
071  /**
072   * The character set to use.
073   */
074  protected String characterSet;
075
076  /**
077   * The collation to use.
078   */
079  protected String collation;
080
081  /**
082   * Maximum number of attempts to find the 'database ready to accept connections' log message in the container.
083   * <p>
084   * 100 attempts equates to 10 seconds.
085   * </p>
086   */
087  protected int maxReadyAttempts = 300;
088
089  /**
090   * Docker command.
091   */
092  protected String docker = "docker";
093
094  protected final String version;
095
096  BaseConfig(String platform, int port, int internalPort, String version) {
097    this.platform = platform;
098    this.port = port;
099    this.internalPort = internalPort;
100    this.containerName = "ut_" + platform;
101    this.image = platform + ":" + version;
102    this.version = version;
103  }
104
105  /**
106   * Return a description of the configuration.
107   */
108  @Override
109  public String startDescription() {
110    return "starting " + platform + " container:" + containerName + " port:" + port + " startMode:" + startMode;
111  }
112
113  @Override
114  public String stopDescription() {
115    return "stopping " + platform + " container:" + containerName + " stopMode:" + stopMode;
116  }
117
118  @Override
119  public String platform() {
120    return platform;
121  }
122
123  @Override
124  public String containerName() {
125    return containerName;
126  }
127
128  @Override
129  public String version() {
130    return version;
131  }
132
133  @Override
134  public void setStartMode(StartMode startMode) {
135    this.startMode = startMode;
136  }
137
138  @Override
139  public void setStopMode(StopMode stopMode) {
140    this.stopMode = stopMode;
141  }
142
143  @Override
144  public void setShutdownMode(StopMode shutdownMode) {
145    this.shutdownMode = shutdownMode;
146  }
147
148  /**
149   * Return a Connection to the database (make sure you close it).
150   */
151  @Override
152  public Connection createConnection() throws SQLException {
153    throw new IllegalStateException("Not valid for this type");
154  }
155
156  @Override
157  public Connection createConnectionNoSchema() throws SQLException {
158    throw new IllegalStateException("Not valid for this type");
159  }
160
161  @Override
162  public Connection createAdminConnection() throws SQLException {
163    throw new IllegalStateException("Not valid for this type");
164  }
165
166  @Override
167  public String jdbcUrl() {
168    throw new IllegalStateException("Not valid for this type");
169  }
170
171  @Override
172  public String jdbcAdminUrl() {
173    return jdbcUrl();
174  }
175
176  /**
177   * Load configuration from properties.
178   */
179  public BaseConfig setProperties(Properties properties) {
180    if (properties == null) {
181      return this;
182    }
183    docker = properties.getProperty("docker", docker);
184
185    containerName = prop(properties, "containerName", containerName);
186    image = prop(properties, "image", image);
187    host = prop(properties, "host", host);
188    port = prop(properties, "port", port);
189    internalPort = prop(properties, "internalPort", internalPort);
190    adminPort = prop(properties, "adminPort", adminPort);
191    adminInternalPort = prop(properties, "adminInternalPort", adminInternalPort);
192    characterSet = prop(properties, "characterSet", characterSet);
193    collation = prop(properties, "collation", collation);
194
195    String start = properties.getProperty("startMode", startMode.name());
196    startMode = StartMode.of(prop(properties, "startMode", start));
197
198    String stop = properties.getProperty("stopMode", stopMode.name());
199    stopMode = StopMode.of(prop(properties, "stopMode", stop));
200
201    String shutdown = properties.getProperty("shutdown", shutdownMode.name());
202    shutdownMode = StopMode.of(prop(properties, "shutdown", shutdown));
203
204    String maxVal = prop(properties, "maxReadyAttempts", null);
205    if (maxVal != null) {
206      try {
207        this.maxReadyAttempts = Integer.parseInt(maxVal);
208      } catch (NumberFormatException e) {
209        // ignore error
210      }
211    }
212    return this;
213  }
214
215  protected String prop(Properties properties, String key, String defaultValue) {
216    String val = properties.getProperty("ebean.test." + platform + "." + key, defaultValue);
217    return properties.getProperty(platform + "." + key, val);
218  }
219
220  protected int prop(Properties properties, String key, int defaultValue) {
221    String val = properties.getProperty("ebean.test." + platform + "." + key);
222    val = properties.getProperty(platform + "." + key, val);
223    return val == null ? defaultValue : Integer.parseInt(val);
224  }
225
226  /**
227   * Set the container name.
228   */
229  public BaseConfig setContainerName(String containerName) {
230    this.containerName = containerName;
231    return this;
232  }
233
234  /**
235   * Set the exposed port.
236   */
237  public BaseConfig setPort(int port) {
238    this.port = port;
239    return this;
240  }
241
242  /**
243   * Set the internal (to the container) port.
244   */
245  public BaseConfig setInternalPort(int internalPort) {
246    this.internalPort = internalPort;
247    return this;
248  }
249
250  /**
251   * Set the exposed admin port.
252   */
253  public BaseConfig setAdminPort(int adminPort) {
254    this.adminPort = adminPort;
255    return this;
256  }
257
258  /**
259   * Set the internal admin (to the container) port.
260   */
261  public BaseConfig setAdminInternalPort(int adminInternalPort) {
262    this.adminInternalPort = adminInternalPort;
263    return this;
264  }
265
266  /**
267   * Set the docker image to use.
268   */
269  public BaseConfig setImage(String image) {
270    this.image = image;
271    return this;
272  }
273
274  /**
275   * Set the character set to use.
276   */
277  public BaseConfig setCharacterSet(String characterSet) {
278    this.characterSet = characterSet;
279    return this;
280  }
281
282  /**
283   * Set the collation to use.
284   */
285  public BaseConfig setCollation(String collation) {
286    this.collation = collation;
287    return this;
288  }
289
290  /**
291   * Set the max attempts to wait for DB ready.
292   */
293  public BaseConfig setMaxReadyAttempts(int maxReadyAttempts) {
294    this.maxReadyAttempts = maxReadyAttempts;
295    return this;
296  }
297
298  /**
299   * Set the docker command to use (defaults to 'docker').
300   */
301  public BaseConfig setDocker(String docker) {
302    this.docker = docker;
303    return this;
304  }
305
306  public String getHost() {
307    return host;
308  }
309
310  public int getPort() {
311    return port;
312  }
313
314  public int getInternalPort() {
315    return internalPort;
316  }
317
318  public int getAdminPort() {
319    return adminPort;
320  }
321
322  public int getAdminInternalPort() {
323    return adminInternalPort;
324  }
325
326  public String getImage() {
327    return image;
328  }
329
330  public StartMode getStartMode() {
331    return startMode;
332  }
333
334  public StopMode getStopMode() {
335    return stopMode;
336  }
337
338  public int getMaxReadyAttempts() {
339    return maxReadyAttempts;
340  }
341
342  public String getDocker() {
343    return docker;
344  }
345
346  public StopMode shutdownMode() {
347    return shutdownMode;
348  }
349
350  public String getCharacterSet() {
351    return characterSet;
352  }
353
354  public String getCollation() {
355    return collation;
356  }
357
358  public boolean isExplicitCollation() {
359    return collation != null || characterSet != null;
360  }
361
362  public boolean isDefaultCollation() {
363    return "default".equals(collation);
364  }
365
366  public boolean isStopModeNone() {
367    return StopMode.None == stopMode;
368  }
369
370  /**
371   * Clear the stopMode when detect already running.
372   */
373  public void clearStopMode() {
374    this.stopMode = StopMode.None;
375  }
376}