PageRenderTime 26ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/amps-maven-plugin/src/main/java/com/atlassian/maven/plugins/amps/DataSource.java

https://bitbucket.org/atlassian/amps
Java | 434 lines | 211 code | 69 blank | 154 comment | 25 complexity | 1d315fdccae75396e253056d9a9a38da MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause
  1. package com.atlassian.maven.plugins.amps;
  2. import org.apache.commons.lang3.StringUtils;
  3. import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
  4. import org.springframework.jdbc.datasource.DriverManagerDataSource;
  5. import org.springframework.jdbc.support.DatabaseMetaDataCallback;
  6. import org.springframework.jdbc.support.JdbcUtils;
  7. import org.springframework.jdbc.support.MetaDataAccessException;
  8. import javax.annotation.Nonnull;
  9. import javax.annotation.Nullable;
  10. import java.util.ArrayList;
  11. import java.util.List;
  12. import java.util.Optional;
  13. import static com.atlassian.maven.plugins.amps.util.PropertyUtils.parse;
  14. import static com.google.common.base.MoreObjects.firstNonNull;
  15. import static org.apache.commons.lang3.StringUtils.isBlank;
  16. import static org.apache.commons.lang3.StringUtils.trimToEmpty;
  17. import static org.apache.commons.lang3.builder.ToStringStyle.SHORT_PREFIX_STYLE;
  18. /**
  19. * Definition of a datasource.
  20. * For more information about the properties, see http://cargo.codehaus.org/DataSource+and+Resource+Support
  21. *
  22. * @since 3.11
  23. */
  24. public class DataSource {
  25. private static final String[] FIELDS_TO_EXCLUDE_FROM_TO_STRING = {"password", "systemPassword"};
  26. private static final char PROPERTY_DELIMITER = ';';
  27. private static final char PROPERTY_KEY_VALUE_DELIMITER = '=';
  28. /**
  29. * Connection url, such as "jdbc:h2:file:/path/to/database/file"
  30. */
  31. private String url;
  32. /**
  33. * database schema, such as "public", "dbo"
  34. */
  35. private String schema;
  36. /**
  37. * Driver, such as "org.h2.Driver"
  38. */
  39. private String driver;
  40. /**
  41. * Username, e.g. "sa"
  42. */
  43. private String username;
  44. /**
  45. * Password. May be empty.
  46. */
  47. private String password;
  48. /**
  49. * JNDI name, such as jdbc/JiraDS
  50. */
  51. private String jndi;
  52. /**
  53. * Type of driver: "java.sql.Driver" or "javax.sql.XADataSource".
  54. * Will not be forwarded to Cargo if empty.
  55. */
  56. private String type;
  57. /**
  58. * Which transaction support. LOCAL_TRANSACTION or XA_TRANSACTION.
  59. * Will not be forwarded to Cargo if empty.
  60. */
  61. private String transactionSupport;
  62. /**
  63. * Properties to pass to the driver. Semi-colon delimited string.
  64. * Will not be forwarded to Cargo if empty.
  65. */
  66. private String properties;
  67. /**
  68. * Cargo-style string to pass to Cargo in the "cargo.datasource.datasource" property.
  69. * If set, the other properties will not be read.
  70. *
  71. * <p>Example:
  72. * cargo.datasource.username=sa|cargo.datasource.password...|...
  73. * </p>
  74. */
  75. private String cargoString;
  76. /**
  77. * Additional libraries required in the container (e.g. Tomcat) to support the driver.
  78. * Example with a random library:
  79. *
  80. * <pre>
  81. * {@code
  82. * <libArtifacts>
  83. * <libArtifact>
  84. * <groupId>postgres</groupId>
  85. * <artifactId>postgres</artifactId>
  86. * <version>9.1-901-1.jdbc4</artifactId>
  87. * </libArtifact>
  88. * </libArtifacts>
  89. * }
  90. * </pre>
  91. */
  92. private List<LibArtifact> libArtifacts = new ArrayList<>();
  93. /**
  94. * The JDBC URL of the system database, being the one to which a DBA would connect in order to drop or create a
  95. * schema, database, user, etc.
  96. *
  97. * N.B. renaming this field to (for example) "systemUrl" would break field injection for existing AMPS configurations
  98. */
  99. private String defaultDatabase;
  100. /**
  101. * The username of a database user who can drop and create schemas, databases, users, etc.
  102. */
  103. private String systemUsername;
  104. /**
  105. * The password of the user identified by the {@code systemUsername}. May be empty.
  106. */
  107. private String systemPassword;
  108. /**
  109. * The file from which to import data. If not null, the file to which this points
  110. * should be in the correct format for the configured {@link #importMethod}.
  111. */
  112. private String dumpFilePath;
  113. /**
  114. * How AMPS should import the dump file:
  115. * sql : AMPS will use JDBC to import SQL dump file, file must contain standard SQL
  116. * psql: AMPS will use Postgres psql to import SQL dump file. Eg: psql -f jira_63_postgres91_dump.sql -U jira_user jiradb
  117. * impdp: AMPS will use Oracle impdp to import dump file. Eg: impdp jira_user/jira_pwd directory=data_pump_dir DUMPFILE=<dumpFilePath>
  118. * sqlcmd: AMPS will use SQL Server sqlcmd to restore backup file. Eg: sqlcmd -s localhost -Q "RESTORE DATABASE JIRA FROM DISK='d:\jira_63_sqlserver_2008.bak'"
  119. */
  120. private String importMethod = "sql";
  121. /**
  122. * Whether the prepare-database goal should drop and re-create the database and the product's user.
  123. */
  124. @SuppressWarnings("unused")
  125. private boolean dropAndReCreateDatabase;
  126. /**
  127. * An optional SQL-92 query for validating the database connection. Not all products use this.
  128. *
  129. * @since 8.3
  130. */
  131. private String validationQuery;
  132. /**
  133. * Constructor.
  134. */
  135. public DataSource() {
  136. // Empty
  137. }
  138. /**
  139. * Indicates whether AMPS should drop and re-create the application database during the pre-integration-test phase.
  140. *
  141. * @since 8.3
  142. */
  143. public boolean isDropAndReCreateDatabase() {
  144. return dropAndReCreateDatabase;
  145. }
  146. public String getCargoString() {
  147. if (cargoString != null) {
  148. return cargoString;
  149. }
  150. final List<String> cargoProperties = new ArrayList<>();
  151. cargoProperties.add("cargo.datasource.url=" + firstNonNull(url, ""));
  152. cargoProperties.add("cargo.datasource.driver=" + firstNonNull(driver, ""));
  153. cargoProperties.add("cargo.datasource.username=" + firstNonNull(username, ""));
  154. cargoProperties.add("cargo.datasource.password=" + firstNonNull(password, ""));
  155. cargoProperties.add("cargo.datasource.jndi=" + firstNonNull(jndi, ""));
  156. if (!isBlank(type)) {
  157. cargoProperties.add("cargo.datasource.type=" + type);
  158. }
  159. if (!isBlank(transactionSupport)) {
  160. cargoProperties.add("cargo.datasource.transactionsupport=" + transactionSupport);
  161. }
  162. if (!isBlank(properties)) {
  163. cargoProperties.add("cargo.datasource.properties=" + properties);
  164. }
  165. cargoString = StringUtils.join(cargoProperties, "|");
  166. return cargoString;
  167. }
  168. /**
  169. * Fills in any missing fields of {@code this} datasource with the values of the given datasource.
  170. *
  171. * @param defaultValues the datasource from which to read the default values
  172. */
  173. public void copyMissingValuesFrom(final DataSource defaultValues) {
  174. if (this.jndi == null) this.jndi = defaultValues.jndi;
  175. if (this.url == null) this.url = defaultValues.url;
  176. if (this.schema == null) this.schema = defaultValues.schema;
  177. if (this.driver == null) this.driver = defaultValues.driver;
  178. if (this.username == null) this.username = defaultValues.username;
  179. if (this.password == null) this.password = defaultValues.password;
  180. if (this.type == null) this.type = defaultValues.type;
  181. if (this.transactionSupport == null) this.transactionSupport = defaultValues.transactionSupport;
  182. if (this.properties == null) this.properties = defaultValues.properties;
  183. }
  184. public String getUrl() {
  185. return url;
  186. }
  187. public void setUrl(String url) {
  188. this.url = url;
  189. }
  190. public String getSchema() {
  191. return schema;
  192. }
  193. public void setSchema(String schema) {
  194. this.schema = schema;
  195. }
  196. public String getDriver() {
  197. return driver;
  198. }
  199. public void setDriver(String driver) {
  200. this.driver = driver;
  201. }
  202. public String getUsername() {
  203. return username;
  204. }
  205. public void setUsername(String username) {
  206. this.username = username;
  207. }
  208. public String getPassword() {
  209. return password;
  210. }
  211. public void setPassword(String password) {
  212. this.password = password;
  213. }
  214. public String getJndi() {
  215. return jndi;
  216. }
  217. public void setJndi(String jndi) {
  218. this.jndi = jndi;
  219. }
  220. public String getType() {
  221. return type;
  222. }
  223. public void setType(String type) {
  224. this.type = type;
  225. }
  226. public String getTransactionSupport() {
  227. return transactionSupport;
  228. }
  229. public void setTransactionSupport(String transactionSupport) {
  230. this.transactionSupport = transactionSupport;
  231. }
  232. public String getProperties() {
  233. return properties;
  234. }
  235. public void setProperties(String properties) {
  236. this.properties = properties;
  237. }
  238. public List<LibArtifact> getLibArtifacts() {
  239. return libArtifacts;
  240. }
  241. public void setLibArtifacts(List<LibArtifact> libArtifacts) {
  242. this.libArtifacts = libArtifacts;
  243. }
  244. public void setCargoString(String cargoString) {
  245. this.cargoString = cargoString;
  246. }
  247. /**
  248. * Returns the URL of the default database, i.e. the one to which
  249. * a DBA would connect to drop or create databases and users.
  250. *
  251. * @return a JDBC URL
  252. */
  253. public String getSystemUrl() {
  254. return defaultDatabase;
  255. }
  256. /**
  257. * Sets the URL of the default database, i.e. the one to which a DBA would connect to drop or create databases and
  258. * users.
  259. *
  260. * @param jdbcUrl the JDBC URL of the default database
  261. */
  262. public void setSystemUrl(final String jdbcUrl) {
  263. this.defaultDatabase = jdbcUrl;
  264. }
  265. public String getSystemUsername() {
  266. return systemUsername;
  267. }
  268. public void setSystemUsername(String systemUsername) {
  269. this.systemUsername = systemUsername;
  270. }
  271. public String getSystemPassword() {
  272. return systemPassword;
  273. }
  274. public void setSystemPassword(String systemPassword) {
  275. this.systemPassword = systemPassword;
  276. }
  277. public String getDumpFilePath() {
  278. return dumpFilePath;
  279. }
  280. public void setDumpFilePath(String dumpFilePath) {
  281. this.dumpFilePath = dumpFilePath;
  282. }
  283. public String getImportMethod() {
  284. return importMethod;
  285. }
  286. public void setImportMethod(String importMethod) {
  287. this.importMethod = importMethod;
  288. }
  289. @Override
  290. public String toString() {
  291. // Used in error messages, etc.
  292. return new ReflectionToStringBuilder(this, SHORT_PREFIX_STYLE)
  293. .setExcludeFieldNames(FIELDS_TO_EXCLUDE_FROM_TO_STRING)
  294. .toString();
  295. }
  296. /**
  297. * Returns the JDBC data source for this instance, connecting as the configured
  298. * system user and applying any configured driver properties.
  299. *
  300. * @return see above
  301. */
  302. public javax.sql.DataSource getJdbcDataSource() {
  303. final DriverManagerDataSource dataSource =
  304. new DriverManagerDataSource(defaultDatabase, systemUsername, systemPassword);
  305. dataSource.setConnectionProperties(parse(properties, PROPERTY_KEY_VALUE_DELIMITER, PROPERTY_DELIMITER));
  306. return dataSource;
  307. }
  308. /**
  309. * Queries this data source for its JDBC metadata and applies the given callback.
  310. *
  311. * @param callback the callback to apply
  312. * @return the non-null return value of the callback, or none if null or there was an error
  313. */
  314. @Nonnull
  315. public <T> Optional<T> getJdbcMetaData(@Nonnull final DatabaseMetaDataCallback callback) {
  316. try {
  317. @SuppressWarnings("unchecked") final T metaData = (T) JdbcUtils.extractDatabaseMetaData(getJdbcDataSource(), callback);
  318. return Optional.ofNullable(metaData);
  319. } catch (final ClassCastException | MetaDataAccessException e) {
  320. return Optional.empty();
  321. }
  322. }
  323. /**
  324. * Adds the given JDBC driver property.
  325. *
  326. * @param name the property name
  327. * @param value the property value
  328. */
  329. public void addProperty(final String name, final String value) {
  330. final String newProperty = name + PROPERTY_KEY_VALUE_DELIMITER + value;
  331. if (isBlank(properties)) {
  332. properties = newProperty;
  333. } else {
  334. properties += PROPERTY_DELIMITER + newProperty;
  335. }
  336. }
  337. /**
  338. * Returns the JDBC driver properties in the <a href="http://www.mojohaus.org/sql-maven-plugin/execute-mojo.html#driverProperties">
  339. * format required by the <code>sql-maven-plugin</code></a>.
  340. *
  341. * @return see above
  342. */
  343. public String getSqlPluginJdbcDriverProperties() {
  344. return trimToEmpty(properties).replace(PROPERTY_DELIMITER, ',');
  345. }
  346. /**
  347. * Returns the SQL query that validates the database connection. Not all products use this.
  348. *
  349. * @return an SQL-92 query, or {@code null} if none is provided
  350. * @since 8.3
  351. */
  352. @Nullable
  353. public String getValidationQuery() {
  354. return validationQuery;
  355. }
  356. /**
  357. * Sets the SQL query that validates the database connection. Not all products use this.
  358. *
  359. * @param validationQuery the SQL-92 query to set
  360. * @since 8.3
  361. */
  362. public void setValidationQuery(final String validationQuery) {
  363. this.validationQuery = validationQuery;
  364. }
  365. }