mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-22 02:58:05 +00:00
HHH-6931 - Provide local database hook
This commit is contained in:
parent
ccc087b975
commit
ab94a18c33
@ -1,61 +1,152 @@
|
||||
##Hibernate Matrix Testing
|
||||
|
||||
#### Goal
|
||||
### Goal
|
||||
|
||||
Run hibernate-core _functional_ tests on other DBs besides default H2 easily.
|
||||
The idea of matrix testing is to allow testing in a varied set of configurations. Specifically for Hibernate, this
|
||||
correlates to running the same set of tests against against multiple databases. This goal is achieved through
|
||||
2 Gradle plugins.
|
||||
|
||||
Well, although [Functional Testing](http://en.wikipedia.org/wiki/Functional_testing) and [Unit Testing](http://en.wikipedia.org/wiki/Unit_testing) are already well known in the developer world, but we ( hibernate team ) use a little different definition:
|
||||
Note that the second plugin (org.hibernate.build.gradle.testing.matrix.MatrixTestingPlugin) applies the first
|
||||
one (org.hibernate.build.gradle.testing.database.DatabaseProfilePlugin) automatically, so generally scripts would
|
||||
not even reference it. The reason for the split is historical and these 2 may get merged later...
|
||||
|
||||
###### Unit Test
|
||||
|
||||
Test doesn't need DB involved or only the default DB (currently is [H2](http://www.h2database.com/)) is fine, then we call it is a _unit test_.
|
||||
### org.hibernate.build.gradle.testing.database.DatabaseProfilePlugin
|
||||
|
||||
###### Functional Test
|
||||
This plugin is responsible for determining which databases are available for testing in the given environment. It
|
||||
does this by performing a directory search. Well actually it can perform up to 2 directory searches:
|
||||
* The standard profile directory is named _databases_ at the base directory of the root project
|
||||
* A custom profile directory, which can be named by setting a system property named _hibernate-matrix-databases_
|
||||
|
||||
Test which is used to verify a hibernate function and needs to make sure this function works fine on all DBs.
|
||||
These directories are searched recursively. We leverage this in Hibernate to allow the standard _databases_ directory
|
||||
to hold local profiles too. That is achieved by a _.gitignore_ which says to ignore any directory named
|
||||
_local_ under the directory _databases_. So one option to provide custom profiles is to drop them in there. That
|
||||
has the benefit of not having to specify _hibernate-matrix-databases_
|
||||
|
||||
Just to be clear, in hibernate codebase, most tests we have are _functional tests_ by this definition.
|
||||
Within these directories, the plugin looks for sub-directories which either:
|
||||
* contain a file named _matrix.gradle_. _matrix.gradle_ is a limited DSL Gradle file which currently understands
|
||||
just a specialized org.gradle.api.artifacts.Configuration reference named _jdbcDependency_. All that is a fancy
|
||||
way to say that _matrix.gradle_ allows you to specify some dependencies this database profile needs (JDBC drivers,
|
||||
etc). For example:
|
||||
jdbcDependency {
|
||||
"mysql:mysql-connector-java:5.1.17"
|
||||
}
|
||||
|
||||
And all hibernate _functional tests_ are also _unit tests_, since they are also supposed to pass on the default DB (H2).
|
||||
Any dependency artifacts named here get resolved using whatever resolvers (Maven, etc) are associated with the build.
|
||||
* contain a directory named _jdbc_ which is assumed to hold jar file(s) needed for the profile.
|
||||
|
||||
#### MatrixTestingPlugin
|
||||
Such directories become the basis of a database profile made available to the build. The name of the profile
|
||||
(which becomes important when we discuss the next plugin) is taken from the directory name. Database profiles can
|
||||
also contain a _resources_ directory.
|
||||
|
||||
Since Hibernate Core has moved to [Gradle](http://www.gradle.org/) from [Maven](http://maven.apache.org/), so we created a gradle plugin, called _MatrixTestingPlugin_, to run hibernate functional tests on the DB matrix (this is why it is called _MatrixTestingPlugin_ :).
|
||||
An example layout using _matrix.gradle_ might be
|
||||
├── mysql50
|
||||
│ ├── jdbc
|
||||
│ │ └── mysql-connector-java-5.1.9.jar
|
||||
│ └── resources
|
||||
│ └── hibernate.properties
|
||||
|
||||
The source of this plugin is [here](https://github.com/hibernate/hibernate-core/tree/master/buildSrc), this is used by Hibernate Core only right now, so this post is specific to hibernate core project only, hope one day we could denote it to the gradle community.
|
||||
Or
|
||||
├── mysql50
|
||||
│ ├── matrix.gradle
|
||||
│ └── resources
|
||||
│ └── hibernate.properties
|
||||
|
||||
#### How to use this plugin
|
||||
|
||||
1. apply this plugin in your gradle build script (of course!)
|
||||
Either would result in a database profile name mysql50_
|
||||
|
||||
In [hibernate-core/hibernate-core.gradle](https://github.com/hibernate/hibernate-core/blob/master/hibernate-core/hibernate-core.gradle) we have this line:
|
||||
|
||||
`apply plugin: org.hibernate.gradle.testing.matrix.MatrixTestingPlugin`
|
||||
Profiles can be ignored using the _hibernate-matrix-ignore_ setting which accepts either
|
||||
* a comma-separated list of the database profile names to be skipped
|
||||
* the magic value **all** which indicates to ignore all profiles
|
||||
|
||||
2. SourceSet separation
|
||||
|
||||
Although it is possible to define a logical separation in Gradle (see [this](http://gradle.org/current/docs/javadoc/org/gradle/api/tasks/SourceSet.html)), I would like physical separation of unit tests and functional tests, so, we have this project structure:
|
||||
|
||||
localhost:hibernate-core stliu$ tree -L 3
|
||||
├── hibernate-core.gradle
|
||||
├── src
|
||||
├── main
|
||||
│ ├── antlr
|
||||
│ ├── java
|
||||
│ ├── javadoc
|
||||
│ ├── resources
|
||||
│ └── xjb
|
||||
├── matrix
|
||||
│ └── java
|
||||
└── test
|
||||
├── java
|
||||
└── resources
|
||||
### org.hibernate.build.gradle.testing.matrix.MatrixTestingPlugin
|
||||
|
||||
The MatrixTestingPlugin essentially generates a bunch of Gradle tasks dynamically and adds them to your build. It does
|
||||
this based on all the database profiles found. Running `gradle tasks --all` will list all tasks available to the build
|
||||
including these generated ones.
|
||||
|
||||
For each database profile the plugin will generate a task named _matrix_{profile}_ that executes the tests against
|
||||
that particular database profile. It also generates a task named _matrix_ that groups together all the
|
||||
profile-specific tasks so that running `gradle matrix` will run all the profiles.
|
||||
|
||||
|
||||
*see section below discussing SourceSet separation
|
||||
|
||||
|
||||
### Database Allocator (JBoss internally, VPN required)
|
||||
|
||||
For developers on the Red Hat VPN, one option is to use the databases in the JBoss QA lab for testing. Note that
|
||||
this tends to result in **very** slow builds but the obvious trade off is not having to install and manage these
|
||||
databases locally.
|
||||
|
||||
The JBoss QA team developed a servlet to allow management of "database allocations" including requesting an
|
||||
allocation be set up. The MatrixTestingPlugin is able to play with that feature allowing you to ask the build
|
||||
to allocate the database for you. This feature is disabled by default, to enable it, you need this system property
|
||||
named _hibernate-matrix-dballcoation_ which accepts either
|
||||
* a comma-separate list of profile names
|
||||
* the magic value **all** which indicates to allocate for all **supported** databases (see
|
||||
org.hibernate.build.qalab.DatabaseAllocator.SUPPORTED_DB_NAMES for details)
|
||||
|
||||
For example, if you want to run matrix test on PostgreSQL 8.4, knowing that the database name for that is
|
||||
_postgresql84_, you can use this command:
|
||||
gradle matrix_postgresql84 -Dhibernate-matrix-dballocation=postgresql84
|
||||
|
||||
which would
|
||||
1. talk to the database allocator service and make a database instance available
|
||||
2. use the information returned from the allocator service to properly set up the connection information
|
||||
Hibernate would need to connect to that instance.
|
||||
3. run the tests against the postgresql84 profile
|
||||
|
||||
For some databases we need adjust the connection url with some options after get it from the database allocator. In
|
||||
these cases we can use the system property _hibernate-matrix-dballocation-url-postfix-${dbname}_. For example
|
||||
`-Dhibernate-matrix-dballocation-url-postfix-sybase155="?SQLINITSTRING=set quoted_identifier on&DYNAMIC_PREPARE=true"`
|
||||
|
||||
A useful parameter to the allocator service when allocating a database is the _requester_ which is basically just a
|
||||
string meant to identify who is making the request. By default the Hibernate build uses _hibernate_. But you can
|
||||
specify an alternate requester using the system property _hibernate-matrix-dballocation-requestee_
|
||||
|
||||
|
||||
### Testing SourceSets
|
||||
|
||||
If you are not familiar with Gradle's notion of
|
||||
[SourceSet](http://gradle.org/current/docs/javadoc/org/gradle/api/tasks/SourceSet.html), you should be :)
|
||||
|
||||
The Hibernate build defines 2 different testing related SourceSets in a number of modules (currently hibernate-core,
|
||||
hibernate-entitymanager and hibernate-envers):
|
||||
* _test_ - tests that **should not** be run against the profiles from the MatrixTestingPlugin
|
||||
* _matrix_ - tests that **should** be run against the profiles from the MatrixTestingPlugin
|
||||
|
||||
Tests in _test_ include unit tests as well as a few functional tests which use a database but where the particular
|
||||
database should not at all affect the outcome. Tests in _matrix_ are functional tests where the outcome of the tests
|
||||
are highly dependent on the database being used (how pessimistic locks are acquired, etc).
|
||||
|
||||
As always, Wikipedia is a great source of information
|
||||
* [Functional Testing](http://en.wikipedia.org/wiki/Functional_testing)
|
||||
* [Unit Testing](http://en.wikipedia.org/wiki/Unit_testing)
|
||||
|
||||
hibernate-core directory layout (for discussion):
|
||||
hibernate-core
|
||||
├── hibernate-core.gradle
|
||||
├── src
|
||||
├── main
|
||||
│ ├── antlr
|
||||
│ ├── java
|
||||
│ ├── javadoc
|
||||
│ ├── resources
|
||||
│ └── xjb
|
||||
├── matrix
|
||||
│ └── java
|
||||
└── test
|
||||
├── java
|
||||
└── resources
|
||||
|
||||
The directories of interest include
|
||||
* matrix/java
|
||||
|
||||
|
||||
all functional tests go into this directory
|
||||
|
||||
* test/java
|
||||
* test/java
|
||||
|
||||
all unit tests go into this directory
|
||||
|
||||
@ -63,117 +154,24 @@ The source of this plugin is [here](https://github.com/hibernate/hibernate-core/
|
||||
|
||||
all resources for ***functional tests and unit tests***, yes, resource files in this directory are shared for both, so you don't need to copy one file to both place, for example, log4j.properties.
|
||||
|
||||
To make _idea plugin_ (and _eclipse plugin_) works, we also have this defined in hibernate-core.gradle:
|
||||
|
||||
sourceSets {
|
||||
matrix {
|
||||
java {
|
||||
srcDir 'src/matrix/java'
|
||||
}
|
||||
resources {
|
||||
srcDir 'src/matrix/resources'
|
||||
}
|
||||
|
||||
To make _idea plugin_ (similar entries for _eclipse plugin_) works, we also have this defined in hibernate-core.gradle:
|
||||
|
||||
sourceSets {
|
||||
matrix {
|
||||
java {
|
||||
srcDir 'src/matrix/java'
|
||||
}
|
||||
resources {
|
||||
srcDir 'src/matrix/resources'
|
||||
}
|
||||
}
|
||||
|
||||
ideaModule {
|
||||
sourceDirs += file( '$buildDir/generated-src/antlr/main' )
|
||||
testSourceDirs += file( 'src/matrix/java')
|
||||
testSourceDirs += file( 'src/matrix/resources')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
3. DB profile
|
||||
|
||||
A DB profile defines the JDBC driver and DB connection info ( and hibernate properties for this DB ) that hibernate should use to run _functional tests_ on this DB.
|
||||
|
||||
A DB profile looks like this:
|
||||
|
||||
├── mysql50
|
||||
│ ├── jdbc
|
||||
│ │ └── mysql-connector-java-5.1.9.jar
|
||||
│ ├── matrix.gradle
|
||||
│ └── resources
|
||||
│ └── hibernate.properties
|
||||
|
||||
There are two ways to define JDBC driver, as showed above, put the driver jar file into `jdbc` directory, or use `matrix.gradle` file, below is something you should put into your `matrix.gradle` file:
|
||||
|
||||
jdbcDependency "mysql:mysql-connector-java:5.1.17"
|
||||
|
||||
As you can see, just add the driver's GAV into `jdbcDependency` configuration, then MatrixTestingPlugin will look it up from maven repository defined in the `build.gradle` and add it to the `testCompile` scope.
|
||||
|
||||
For DB connection info, you should add it into `resources/hibernate.properties` (if you have Redhat VPN access, you can use the DB maintained by JBoss QA and get the DB connection automatically through DB Allocator, see below).
|
||||
|
||||
NOTE: this `hibernate.properties` will overrides the one in `hibernate-core/test/resources/hibernate.properties` if same property name defined in both place.
|
||||
|
||||
And, the DB profile name is the directory name, in this example, it is _mysql50_.
|
||||
|
||||
The default DB profile location is in `hibernate-core/databases` directory, but you can also reallocate it to another place by using system property `hibernate-matrix-databases`, see below for more details.
|
||||
|
||||
#### Matrix Tasks
|
||||
|
||||
Once you have DB profiles defined, you could run `gradle tasks --all`, this will list all tasks you can use.
|
||||
|
||||
For example, there will be a `matrix` task, which depends on all of other `matrix_${profile_name}` tasks, each DB profile has a `matrix_${profile_name}` task, so if you want to run hibernate functional tests on all DB profiles, then just call `gradle matrix` or if you want to run them on mysql only, then `gradle mysql50`.
|
||||
|
||||
In this case ( run `gradle matrix` or its sub-task `gradle matrix_${profile_name}` ), only tests in `src/matrix/java` will be ran, and `hibernate.properties` come from your `db profile/resources/hibernate.properties` (and `test/resources/hibernate.properties`).
|
||||
|
||||
Matrix test results are in `target/matrix/${profile_name}/test-results`.
|
||||
|
||||
But, there is also a `test` task, this task runs ***all*** tests, both `src/matrix/java` and `src/test/java`, with `src/test/resources` on default DB (as above said, all _functional tests_ are also _unit tests_).
|
||||
|
||||
Unit test results are in `target/test-results`, so if you run `test` task, all test results are in here, instead of `target/matrix/${profile_name}/test-results`, just as normal.
|
||||
|
||||
#### Configuration Properties
|
||||
|
||||
There are two way to pass a system property to gradle build:
|
||||
|
||||
1. The original java way, -Dxxx=yyy
|
||||
2. Add it to ${user.home}/.gradle/gradle.properties with a 'systemProp' prefix, like 'systemProp.xxx=yyy'
|
||||
|
||||
* hibernate-matrix-databases
|
||||
|
||||
This property is used to define the location of DB profile container.
|
||||
Accept value: absolute path of DB profile container directory.
|
||||
|
||||
* hibernate-matrix-ignore
|
||||
|
||||
This property is used to ignore some DB profiles (or all of them), so if you run `matrix`, the ignored profile matrix task won't be run.
|
||||
|
||||
Accept value : _all_ or _${profile name1},${profile name2},${profile name3}_
|
||||
ideaModule {
|
||||
sourceDirs += file( '$buildDir/generated-src/antlr/main' )
|
||||
testSourceDirs += file( 'src/matrix/java')
|
||||
testSourceDirs += file( 'src/matrix/resources')
|
||||
}
|
||||
|
||||
|
||||
#### DB Allocator (JBoss internally, VPN required)
|
||||
|
||||
For users who has access to JBoss QA lab (need Redhat VPN), here is a better way to run matrix tests, you don't need to have a DB instance on your side, but you can use DB instance in JBoss QA Lab.
|
||||
|
||||
And the connection info can be queried from DB Allocator automatically.
|
||||
|
||||
This feature is disabled by default, to enable it, you need this system property
|
||||
|
||||
* hibernate-matrix-dballcoation
|
||||
|
||||
Accept value: _all_ or _${profile name1},${profile name2},${profile name3}_
|
||||
|
||||
For example, if you want to run matrix test on postgresql84, you can use this command
|
||||
|
||||
./gradlew clean test matrix_postgresql84 -Dhibernate-matrix-dballocation=postgresql84
|
||||
|
||||
what does this command do actually?
|
||||
1. test
|
||||
run 'src/test/java' on default H2, test results in 'target/test-results'
|
||||
run 'src/matrix/java' on default H2, test results in 'target/test-results'
|
||||
|
||||
2. query postgresql 84 db instance connection info
|
||||
3. run 'src/matrix/java' on postgresql 84 with 'databases/postgresql84/matrix.gradle' defined jdbc driver and 'databases/postgresql84/resources/hibernate.properties' and postgresql84 db instance connection info (this info will override those defined in hibernate.properties), test results in 'target/matrix/postgresql84/results'
|
||||
|
||||
Some DBs need we tweak url with some configurations after get it from DB allocator, so, we can use this system property:
|
||||
|
||||
* hibernate-matrix-dballocation-url-postfix-${dbname}
|
||||
|
||||
for example:
|
||||
|
||||
`-Dhibernate-matrix-dballocation-url-postfix-sybase155="?SQLINITSTRING=set quoted_identifier on&DYNAMIC_PREPARE=true"`
|
||||
|
||||
* hibernate-matrix-dballocation-requestee
|
||||
This property is used to define the DB Allocator requester name, default is _hibernate_
|
||||
|
@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package hudson.util
|
||||
|
||||
/**
|
||||
*
|
||||
* @author mvecera
|
||||
*/
|
||||
class DBAllocation {
|
||||
private final static String DB_ALLOCATOR_URL = "http://dballocator.mw.lab.eng.bos.redhat.com:8080/Allocator/AllocatorServlet";
|
||||
private dbinstallPath = "dbinstall"
|
||||
private retries = 30
|
||||
private UUID = ""
|
||||
private ant
|
||||
private File dbConfigFile;
|
||||
private File tmpFile;
|
||||
private String requestee;
|
||||
|
||||
def DBAllocation(dbinstallPath) {
|
||||
this(new AntBuilder(), dbinstallPath)
|
||||
}
|
||||
|
||||
def DBAllocation(ant, dbinstallPath, outPropsFileName = "allocated.db.properties") {
|
||||
this.ant = ant;
|
||||
this.dbinstallPath = dbinstallPath;
|
||||
this.dbConfigFile = new File(dbinstallPath, outPropsFileName);
|
||||
this.tmpFile = new File(dbinstallPath, "tmpfile")
|
||||
if ( System.properties.containsKey("hibernate-matrix-dballocation-requestee") )
|
||||
requestee = System.properties["hibernate-matrix-dballocation-requestee"]
|
||||
else
|
||||
requestee = "hibernate"
|
||||
}
|
||||
|
||||
def getProperties() {
|
||||
def props = new Properties();
|
||||
props.load(new FileInputStream(dbConfigFile));
|
||||
return props;
|
||||
}
|
||||
|
||||
def allocate(label, expiry) {
|
||||
if ( dbConfigFile.exists() ) {
|
||||
dbConfigFile.delete()
|
||||
}
|
||||
def i = 0
|
||||
while ( !(dbConfigFile.exists() && dbConfigFile.length() > 0) ) {
|
||||
if ( i >= retries ) {
|
||||
throw new Exception('Database unavailable')
|
||||
}
|
||||
if ( i > 0 ) {
|
||||
println "Waiting before trying to allocate DB again."
|
||||
Thread.sleep(60000)
|
||||
}
|
||||
println "Allocating DB..."
|
||||
def allocatorUrl = DB_ALLOCATOR_URL + "?operation=alloc&label=$label&requestee=${requestee}&expiry=$expiry"
|
||||
ant.get(src: allocatorUrl, dest: dbConfigFile.absolutePath, ignoreerrors: 'true')
|
||||
i++
|
||||
}
|
||||
def dbProps = getProperties();
|
||||
this.UUID = dbProps['uuid']
|
||||
return this.UUID
|
||||
}
|
||||
|
||||
def release() {
|
||||
release(this.UUID)
|
||||
}
|
||||
|
||||
def release(UUID) {
|
||||
println 'De-allocating DB...'
|
||||
def allocatorUrl = DB_ALLOCATOR_URL + "?operation=dealloc&uuid=$UUID"
|
||||
ant.get(src: allocatorUrl, dest: tmpFile.absolutePath)
|
||||
}
|
||||
|
||||
def clean() {
|
||||
clean(this.UUID);
|
||||
}
|
||||
|
||||
def clean(UUID) {
|
||||
println 'Cleaning DB...'
|
||||
def allocatorUrl = DB_ALLOCATOR_URL + "?operation=erase&uuid=$UUID"
|
||||
ant.get(src: allocatorUrl, dest: tmpFile.absolutePath)
|
||||
}
|
||||
|
||||
def reallocate(newExpiry) {
|
||||
reallocate(this.UUID, newExpiry)
|
||||
}
|
||||
|
||||
def reallocate(UUID, newExpiry) {
|
||||
println 'Re-allocating DB...'
|
||||
def allocatorUrl = DB_ALLOCATOR_URL + "?operation=realloc&uuid=$UUID&expiry=$newExpiry"
|
||||
ant.get(src: allocatorUrl, dest: tmpFile.absolutePath)
|
||||
}
|
||||
}
|
||||
|
@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package hudson.util
|
||||
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.api.logging.Logging
|
||||
import org.hibernate.gradle.testing.matrix.MatrixNode
|
||||
import org.hibernate.gradle.util.FileUtil
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Strong Liu
|
||||
*/
|
||||
public class DBAllocationHelper {
|
||||
private static final Logger log = Logging.getLogger(DBAllocationHelper.class);
|
||||
|
||||
private static final String DRIVER_PROP = "hibernate.connection.driver_class";
|
||||
private static final String URL_PROP = "hibernate.connection.url";
|
||||
private static final String USERNAME_PROP = "hibernate.connection.username";
|
||||
private static final String PASSWORD_PROP = "hibernate.connection.password";
|
||||
private static final String DB_ALLOCATION_URL_POSTFIX = "hibernate-matrix-dballocation-url-postfix";
|
||||
//DBAllocator supports the following DBs
|
||||
private static def supportedDB = ["oracle9i", "oracle10g", "oracle11gR1", "oracle11gR2",
|
||||
"oracle11gR2RAC", "oracle11gR1RAC",
|
||||
"postgresql82", "postgresql83", "postgresql84", "postgresql91", "mysql50", "mysql51","mysql55",
|
||||
"db2-91", "db2-97", "mssql2005", "mssql2008R1", "mssql2008R2", "sybase155"];
|
||||
private static final Map<MatrixNode, Map<String, String>> cache = new HashMap<MatrixNode, Map<String, String>>();
|
||||
|
||||
public static Map<String, String> getProperties(MatrixNode node) {
|
||||
if ( !cache.containsKey(node) ) {
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
cache.put(node, map);
|
||||
if ( FileUtil.isFile(node.hibernatePropertyFile) ) {
|
||||
Properties hibernateProperties = new Properties();
|
||||
hibernateProperties.load(new FileInputStream(node.hibernatePropertyFile));
|
||||
map.putAll(hibernateProperties);
|
||||
}
|
||||
if ( isDBAllocationEnabled(node.name) ) {
|
||||
log.lifecycle("using DBAllocator to get DB[${node.name}] connection info");
|
||||
try {
|
||||
DBAllocation db = node.DBAllocation
|
||||
db.allocate(node.name, 300);
|
||||
Properties prop = db.properties
|
||||
log.lifecycle("DBAllocating finished for DB[${node.name}], uuid is [${prop['uuid']}]")
|
||||
map[DRIVER_PROP] = prop["db.jdbc_class"]
|
||||
map[URL_PROP] = prop["db.jdbc_url"] + getURLPostfix(node.name)
|
||||
map[USERNAME_PROP] = prop["db.username"]
|
||||
map[PASSWORD_PROP] = prop["db.password"]
|
||||
map["uuid"] = prop["uuid"];
|
||||
db.clean();
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
log.debug("DBAllocating error, ignore", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return cache.get(node);
|
||||
}
|
||||
|
||||
private static String getURLPostfix(String dbName) {
|
||||
for ( String key: System.properties.keySet() ) {
|
||||
if ( key.startsWith(DB_ALLOCATION_URL_POSTFIX) ) {
|
||||
String db = key.substring(DB_ALLOCATION_URL_POSTFIX.length() + 1, key.length())
|
||||
if ( db.equalsIgnoreCase(dbName) ) {
|
||||
String postfix = System.properties[key];
|
||||
log.debug("found URL postfix[%s] for DB[%s]", postfix, db );
|
||||
return postfix;
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
/**
|
||||
* use -Dhibernate-matrix-dballocation=all to enable DBAllocation for all matrix node
|
||||
* or
|
||||
* add systemProp.hibernate-matrix-dballocation=all to ${user.home}/.gradle/gradle.properties
|
||||
*/
|
||||
public static boolean isDBAllocationEnabled(String name) {
|
||||
if ( !supportedDB.contains(name) ) return false;
|
||||
String value = System.properties["hibernate-matrix-dballocation"]
|
||||
return value != null && (value.contains(name) || value.equals("all"));
|
||||
}
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.build.gradle.testing.database;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.logging.Logging;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
/**
|
||||
* Basic support for {@link DatabaseProfile} implementations
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Strong Liu
|
||||
*/
|
||||
public abstract class AbstractDatabaseProfileImpl implements DatabaseProfile {
|
||||
private static final Logger log = Logging.getLogger( AbstractDatabaseProfileImpl.class );
|
||||
|
||||
private final String name;
|
||||
private final File profileDirectory;
|
||||
private final Project project;
|
||||
private final Map<String,String> hibernateProperties;
|
||||
|
||||
@SuppressWarnings( {"unchecked"})
|
||||
protected AbstractDatabaseProfileImpl(File profileDirectory, Project project) {
|
||||
this.profileDirectory = profileDirectory;
|
||||
this.name = profileDirectory.getName();
|
||||
this.project = project;
|
||||
|
||||
this.hibernateProperties = new HashMap<String, String>();
|
||||
final File hibernatePropertiesFile = new File(
|
||||
new File( profileDirectory, "resources" ),
|
||||
"hibernate.properties"
|
||||
);
|
||||
if ( hibernatePropertiesFile.exists() ) {
|
||||
Properties props = new Properties();
|
||||
try {
|
||||
FileInputStream stream = new FileInputStream( hibernatePropertiesFile );
|
||||
try {
|
||||
props.load( stream );
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
stream.close();
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.warn( "Unable to read Hibernate properties for database profile [" + name + "]", e );
|
||||
}
|
||||
for ( String propName : props.stringPropertyNames() ) {
|
||||
hibernateProperties.put( propName, props.getProperty( propName ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDirectory() {
|
||||
return profileDirectory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getHibernateProperties() {
|
||||
return hibernateProperties;
|
||||
}
|
||||
|
||||
protected Configuration prepareConfiguration(String name) {
|
||||
Configuration configuration = getOrCreateConfiguration( name );
|
||||
configuration.setDescription( "The JDBC dependency configuration for the [" + name + "] profile" );
|
||||
return configuration;
|
||||
}
|
||||
|
||||
protected Configuration getOrCreateConfiguration(String name) {
|
||||
Configuration configuration = project.getConfigurations().findByName( name );
|
||||
if ( configuration == null ) {
|
||||
configuration = project.getConfigurations().add( name );
|
||||
}
|
||||
return configuration;
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
@ -21,17 +21,22 @@
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.build.gradle.testing.database;
|
||||
|
||||
package org.hibernate.gradle.testing.database;
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
|
||||
/**
|
||||
* Contract for database "profiles".
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Strong Liu
|
||||
*/
|
||||
public interface DependencyResolver {
|
||||
Project getProject();
|
||||
Configuration resolve();
|
||||
|
||||
public interface DatabaseProfile {
|
||||
public String getName();
|
||||
public File getDirectory();
|
||||
public Map<String,String> getHibernateProperties();
|
||||
public Configuration getTestingRuntimeConfiguration();
|
||||
}
|
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package org.hibernate.build.gradle.testing.database;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.logging.Logger;
|
||||
import org.gradle.api.logging.Logging;
|
||||
|
||||
/**
|
||||
* Plugin used to apply notion of database profiles, which are consumed by the matrix testing plugin.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Strong Liu
|
||||
*/
|
||||
public class DatabaseProfilePlugin implements Plugin<Project> {
|
||||
/**
|
||||
* The directory containing standard database profiles.
|
||||
*/
|
||||
public static final String STANDARD_DATABASES_DIRECTORY = "databases";
|
||||
/**
|
||||
* Names a system setting key that can be set to point to a directory containing additional, custom
|
||||
* database profiles.
|
||||
*/
|
||||
public static final String CUSTOM_DATABASES_DIRECTORY_KEY = "hibernate-matrix-databases";
|
||||
public static final String HIBERNATE_MATRIX_IGNORE = "hibernate-matrix-ignore";
|
||||
|
||||
private static final String MATRIX_BUILD_FILE = "matrix.gradle";
|
||||
private static final String JDBC_DIR = "jdbc";
|
||||
|
||||
private static final Logger log = Logging.getLogger( DatabaseProfilePlugin.class );
|
||||
|
||||
private Project project;
|
||||
private List<DatabaseProfile> profiles;
|
||||
|
||||
public void apply(Project project) {
|
||||
this.project = project;
|
||||
|
||||
final LinkedHashMap<String, DatabaseProfile> profileMap = new LinkedHashMap<String, DatabaseProfile>();
|
||||
processStandardProfiles( profileMap );
|
||||
processCustomProfiles( profileMap );
|
||||
this.profiles = new ArrayList<DatabaseProfile>();
|
||||
this.profiles.addAll( profileMap.values() );
|
||||
}
|
||||
|
||||
private void processStandardProfiles(Map<String, DatabaseProfile> profileMap) {
|
||||
final File standardDatabasesDirectory = getRootProject( project ).file( STANDARD_DATABASES_DIRECTORY );
|
||||
if ( standardDatabasesDirectory == null || ! standardDatabasesDirectory.exists() ) {
|
||||
log.debug( "Standard databases directory [{}] did not exist", STANDARD_DATABASES_DIRECTORY );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! standardDatabasesDirectory.isDirectory() ) {
|
||||
log.warn( "Located standard databases directory [{}] was not a directory", STANDARD_DATABASES_DIRECTORY );
|
||||
return;
|
||||
}
|
||||
|
||||
processProfiles( standardDatabasesDirectory, profileMap );
|
||||
}
|
||||
|
||||
private Project getRootProject(Project project) {
|
||||
return project.getParent() != null ? getRootProject( project.getParent() ) : project;
|
||||
}
|
||||
|
||||
private void processProfiles(File directory, Map<String, DatabaseProfile> profileMap) {
|
||||
// the directory itself is a "database directory" if it contains either:
|
||||
// 1) a file named 'matrix.gradle'
|
||||
// 2) a directory named 'jdbc'
|
||||
DatabaseProfile databaseProfile = null;
|
||||
final File matrixDotGradleFile = new File( directory, MATRIX_BUILD_FILE );
|
||||
if ( matrixDotGradleFile.exists() && matrixDotGradleFile.isFile() ) {
|
||||
log.debug( "Found matrix.gradle file : " + matrixDotGradleFile );
|
||||
databaseProfile = new MatrixDotGradleProfile( matrixDotGradleFile, project );
|
||||
}
|
||||
final File jdbcDirectory = new File( directory, JDBC_DIR );
|
||||
if ( jdbcDirectory.exists() && jdbcDirectory.isDirectory() ) {
|
||||
databaseProfile = new JdbcDirectoryProfile( jdbcDirectory, project );
|
||||
}
|
||||
|
||||
if ( databaseProfile == null ) {
|
||||
// we determined this directory is not a database directory, check its sub-directories
|
||||
for ( File subDirectory : directory.listFiles() ) {
|
||||
if ( subDirectory.isDirectory() ) {
|
||||
processProfiles( subDirectory, profileMap );
|
||||
}
|
||||
}
|
||||
return; // EARLY EXIT!!!
|
||||
}
|
||||
|
||||
final String profileName = databaseProfile.getName();
|
||||
if ( ignored().contains( profileName ) ) {
|
||||
log.debug( "Skipping ignored database profile [{}]", profileName );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( profileMap.containsKey( databaseProfile.getName() ) ) {
|
||||
throw new DuplicateDatabaseProfileException( "There is already a profile named " + profileName );
|
||||
}
|
||||
|
||||
profileMap.put( profileName, databaseProfile );
|
||||
}
|
||||
|
||||
private Set<String> ignored;
|
||||
|
||||
private Set<String> ignored() {
|
||||
if ( ignored == null ) {
|
||||
final String values = System.getProperty( HIBERNATE_MATRIX_IGNORE );
|
||||
if ( values == null || values.length() == 0 ) {
|
||||
ignored = Collections.emptySet();
|
||||
}
|
||||
else {
|
||||
ignored = new HashSet<String>();
|
||||
Collections.addAll( ignored, values.split( "," ) );
|
||||
}
|
||||
}
|
||||
return ignored;
|
||||
}
|
||||
|
||||
private void processCustomProfiles(Map<String, DatabaseProfile> profileMap) {
|
||||
final String customDatabaseDirectoryPath = System.getProperty( CUSTOM_DATABASES_DIRECTORY_KEY );
|
||||
if ( customDatabaseDirectoryPath != null && customDatabaseDirectoryPath.length() > 0 ) {
|
||||
final File customDatabaseDirectory = new File( customDatabaseDirectoryPath );
|
||||
if ( customDatabaseDirectory.exists() && customDatabaseDirectory.isDirectory() ) {
|
||||
processProfiles( customDatabaseDirectory, profileMap );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Iterable<DatabaseProfile> getDatabaseProfiles() {
|
||||
return profiles;
|
||||
}
|
||||
}
|
@ -22,17 +22,18 @@
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package org.hibernate.gradle.util;
|
||||
package org.hibernate.build.gradle.testing.database;
|
||||
|
||||
import org.hibernate.build.gradle.util.BuildException;
|
||||
|
||||
/**
|
||||
* Indicates that we found multiple database profiles having the same name.
|
||||
*
|
||||
* @author Strong Liu
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class DuplicatedDBConfigException extends RuntimeException {
|
||||
public DuplicatedDBConfigException(String message) {
|
||||
public class DuplicateDatabaseProfileException extends BuildException {
|
||||
public DuplicateDatabaseProfileException(String message) {
|
||||
super( message );
|
||||
}
|
||||
|
||||
public DuplicatedDBConfigException(String message, Throwable cause) {
|
||||
super( message, cause );
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
@ -21,41 +21,33 @@
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package org.hibernate.gradle.testing.matrix;
|
||||
package org.hibernate.build.gradle.testing.database;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
import hudson.util.DBAllocation;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
|
||||
import org.hibernate.gradle.testing.database.DependencyResolver;
|
||||
import org.hibernate.gradle.util.Jdk;
|
||||
import org.gradle.api.internal.artifacts.dependencies.DefaultSelfResolvingDependency;
|
||||
|
||||
/**
|
||||
* Describes the various pieces of information being contributed to the matrix by a given node.
|
||||
* Database profile as defined by a directory named {@code jdbc} containing JDBC drivers.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Strong Liu
|
||||
*/
|
||||
public interface MatrixNode {
|
||||
/**
|
||||
* Get the name of this node.
|
||||
*
|
||||
* @return The node.
|
||||
*/
|
||||
String getName();
|
||||
public class JdbcDirectoryProfile extends AbstractDatabaseProfileImpl {
|
||||
private final Configuration jdbcDependencies;
|
||||
|
||||
Configuration getTestingRuntimeConfiguration();
|
||||
public JdbcDirectoryProfile(File jdbcDirectory, Project project) {
|
||||
super( jdbcDirectory.getParentFile(), project );
|
||||
jdbcDependencies = prepareConfiguration( getName() );
|
||||
DefaultSelfResolvingDependency dependency =
|
||||
new DefaultSelfResolvingDependency( project.files( jdbcDirectory.listFiles() ) );
|
||||
jdbcDependencies.addDependency( dependency );
|
||||
}
|
||||
|
||||
Jdk getTestingRuntimeJdk();
|
||||
|
||||
DependencyResolver getDependencyResolver();
|
||||
File getBaseOutputDirectory();
|
||||
DBAllocation getDBAllocation();
|
||||
Map<String,String> getProperties();
|
||||
File getHibernatePropertyFile();
|
||||
void setHibernatePropertyFile(File file);
|
||||
void release();
|
||||
@Override
|
||||
public Configuration getTestingRuntimeConfiguration() {
|
||||
return jdbcDependencies;
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.build.gradle.testing.database;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
|
||||
import groovy.lang.Closure;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
|
||||
/**
|
||||
* Database profile as defined by a {@code matrix.gradle} file
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Strong Liu
|
||||
*/
|
||||
public class MatrixDotGradleProfile extends AbstractDatabaseProfileImpl {
|
||||
private static final String MATRIX_NODE_CONVENTION_KEY = "matrixNode";
|
||||
|
||||
private final Configuration jdbcDependencies;
|
||||
|
||||
protected MatrixDotGradleProfile(File matrixDotGradleFile, Project project) {
|
||||
super( matrixDotGradleFile.getParentFile(), project );
|
||||
jdbcDependencies = prepareConfiguration( getName() );
|
||||
final ConventionImpl convention = new ConventionImpl( jdbcDependencies, project );
|
||||
project.getConvention().getPlugins().put( MATRIX_NODE_CONVENTION_KEY, convention );
|
||||
try {
|
||||
project.apply( Collections.singletonMap( "from", matrixDotGradleFile ) );
|
||||
}
|
||||
finally {
|
||||
project.getConvention().getPlugins().remove( MATRIX_NODE_CONVENTION_KEY );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration getTestingRuntimeConfiguration() {
|
||||
return jdbcDependencies;
|
||||
}
|
||||
|
||||
private class ConventionImpl {
|
||||
private final Configuration jdbcDependencies;
|
||||
private final Project project;
|
||||
|
||||
private ConventionImpl(Configuration jdbcDependencies, Project project) {
|
||||
this.jdbcDependencies = jdbcDependencies;
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
@SuppressWarnings( {"UnusedDeclaration"})
|
||||
public void jdbcDependency(Object dependencyNotation, Closure closure) {
|
||||
project.getDependencies().add( jdbcDependencies.getName(), dependencyNotation, closure );
|
||||
}
|
||||
|
||||
@SuppressWarnings( {"UnusedDeclaration"})
|
||||
public void jdbcDependency(Object dependencyNotation) {
|
||||
project.getDependencies().add( jdbcDependencies.getName(), dependencyNotation );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.build.gradle.testing.matrix;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.gradle.BuildAdapter;
|
||||
import org.gradle.BuildResult;
|
||||
|
||||
import org.hibernate.build.qalab.DatabaseAllocation;
|
||||
|
||||
/**
|
||||
* A Gradle {@link org.gradle.BuildListener} used to release all databases allocated when the build is finished.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class DatabaseAllocationCleanUp extends BuildAdapter {
|
||||
private Set<DatabaseAllocation> databaseAllocations = new HashSet<DatabaseAllocation>();
|
||||
|
||||
public void addDatabaseAllocation(DatabaseAllocation databaseAllocation) {
|
||||
databaseAllocations.add( databaseAllocation );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildFinished(BuildResult result) {
|
||||
super.buildFinished( result );
|
||||
for ( DatabaseAllocation databaseAllocation : databaseAllocations ) {
|
||||
databaseAllocation.release();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.build.gradle.testing.matrix;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import org.hibernate.build.gradle.testing.database.DatabaseProfile;
|
||||
import org.hibernate.build.gradle.util.Jdk;
|
||||
import org.hibernate.build.qalab.*;
|
||||
import org.hibernate.build.qalab.DatabaseAllocation;
|
||||
|
||||
/**
|
||||
* A testing matrix node combines a database profile and a jdk (eventually) along with managing "db allocation"
|
||||
* information.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Strong Liu
|
||||
*/
|
||||
public class MatrixNode {
|
||||
private final DatabaseProfile databaseProfile;
|
||||
private final Jdk jdk;
|
||||
private final File baseOutputDirectory;
|
||||
|
||||
private final DatabaseAllocation databaseAllocation;
|
||||
|
||||
@SuppressWarnings( {"ResultOfMethodCallIgnored"})
|
||||
public MatrixNode(Project project, DatabaseProfile databaseProfile, Jdk jdk) {
|
||||
this.databaseProfile = databaseProfile;
|
||||
this.jdk = jdk;
|
||||
|
||||
baseOutputDirectory = new File( new File( project.getBuildDir(), "matrix" ), databaseProfile.getName() );
|
||||
baseOutputDirectory.mkdirs();
|
||||
|
||||
this.databaseAllocation = DatabaseAllocator.locate( project ).getAllocation( databaseProfile );
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return databaseProfile.getName();
|
||||
}
|
||||
|
||||
public DatabaseProfile getDatabaseProfile() {
|
||||
return databaseProfile;
|
||||
}
|
||||
|
||||
public Jdk getJdk() {
|
||||
return jdk;
|
||||
}
|
||||
|
||||
public File getBaseOutputDirectory() {
|
||||
return baseOutputDirectory;
|
||||
}
|
||||
|
||||
public DatabaseAllocation getDatabaseAllocation() {
|
||||
return databaseAllocation;
|
||||
}
|
||||
}
|
@ -21,9 +21,7 @@
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package org.hibernate.gradle.testing.matrix;
|
||||
|
||||
package org.hibernate.build.gradle.testing.matrix;
|
||||
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
@ -35,11 +33,15 @@ import org.gradle.api.plugins.JavaPluginConvention
|
||||
import org.gradle.api.tasks.SourceSet
|
||||
import org.gradle.api.tasks.SourceSetContainer
|
||||
import org.gradle.api.tasks.testing.Test
|
||||
import org.hibernate.gradle.testing.database.DatabaseMatrixPlugin
|
||||
import org.hibernate.build.gradle.testing.database.DatabaseProfile
|
||||
import org.hibernate.build.gradle.testing.database.DatabaseProfilePlugin
|
||||
import org.hibernate.build.gradle.util.Jdk
|
||||
import static org.gradle.api.plugins.JavaPlugin.COMPILE_CONFIGURATION_NAME
|
||||
import static org.gradle.api.plugins.JavaPlugin.RUNTIME_CONFIGURATION_NAME
|
||||
import static org.gradle.api.plugins.JavaPlugin.TEST_COMPILE_CONFIGURATION_NAME
|
||||
import static org.gradle.api.plugins.JavaPlugin.TEST_RUNTIME_CONFIGURATION_NAME
|
||||
import org.gradle.BuildAdapter
|
||||
import org.gradle.BuildResult
|
||||
|
||||
/**
|
||||
* TODO : 1) add a base configuration of common attribute across all matrix node tasks (convention)
|
||||
@ -56,28 +58,143 @@ public class MatrixTestingPlugin implements Plugin<Project> {
|
||||
public static final String MATRIX_TASK_NAME = "matrix";
|
||||
public static final String MATRIX_SOURCE_SET_NAME = "matrix";
|
||||
public static final String SKIP_UNIT_TEST = "hibernate-matrix-skip-unittest";
|
||||
|
||||
private Project project;
|
||||
private Configuration matrixCompileConfig;
|
||||
private Configuration matrixRuntimeConfig;
|
||||
private Task matrixTask;
|
||||
private SourceSet matrixSourceSet;
|
||||
private List<MatrixNode> matrixNodes;
|
||||
|
||||
// currently, only the build jdk is supported
|
||||
private Jdk theJdk = new Jdk();
|
||||
|
||||
public void apply(Project project) {
|
||||
this.project = project;
|
||||
project.plugins.apply(DatabaseMatrixPlugin);
|
||||
matrixNodes = locateMatrixNodes(project);
|
||||
if ( matrixNodes == null || matrixNodes.isEmpty() ) return; //no db matrix defined.
|
||||
|
||||
project.plugins.apply( DatabaseProfilePlugin );
|
||||
List<MatrixNode> matrixNodes = locateMatrixNodes();
|
||||
if ( matrixNodes == null || matrixNodes.isEmpty() ) {
|
||||
// no db profiles defined
|
||||
return;
|
||||
}
|
||||
|
||||
matrixCompileConfig = prepareCompileConfiguration();
|
||||
matrixRuntimeConfig = prepareRuntimeConfiguration();
|
||||
matrixSourceSet = prepareSourceSet();
|
||||
// create a "grouping task" for all the matrix nodes
|
||||
matrixTask = project.tasks.add(MATRIX_TASK_NAME);
|
||||
|
||||
matrixTask = prepareGroupingTask();
|
||||
DatabaseAllocationCleanUp listener = new DatabaseAllocationCleanUp();
|
||||
project.rootProject.gradle.addBuildListener( listener );
|
||||
for ( MatrixNode matrixNode: matrixNodes ) {
|
||||
Task matrixNodeTask = prepareNodeTask( matrixNode );
|
||||
matrixTask.dependsOn( matrixNodeTask );
|
||||
listener.addDatabaseAllocation( matrixNode.databaseAllocation );
|
||||
}
|
||||
|
||||
if ( !System.properties[SKIP_UNIT_TEST].equals('true') ) {
|
||||
createTestTaskForMatrixSourceSet();
|
||||
}
|
||||
}
|
||||
|
||||
private List<MatrixNode> locateMatrixNodes() {
|
||||
return locateMatrixNodes( this.project );
|
||||
}
|
||||
|
||||
private List<MatrixNode> locateMatrixNodes(Project project) {
|
||||
if ( project == null ) {
|
||||
return null; // EARLY EXIT!!!
|
||||
}
|
||||
|
||||
if ( ! project.plugins.hasPlugin(DatabaseProfilePlugin) ) {
|
||||
return locateMatrixNodes( project.parent ); // EARLY EXIT!!!
|
||||
}
|
||||
|
||||
List<MatrixNode> matrixNodes = new ArrayList<MatrixNode>();
|
||||
Iterable<DatabaseProfile> profiles = project.plugins[DatabaseProfilePlugin].databaseProfiles;
|
||||
if ( profiles != null ) {
|
||||
for ( DatabaseProfile profile : profiles ) {
|
||||
matrixNodes.add( new MatrixNode( project, profile, theJdk ) );
|
||||
}
|
||||
}
|
||||
return matrixNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare compile configuration for matrix source set.
|
||||
*/
|
||||
private Configuration prepareCompileConfiguration() {
|
||||
return project.configurations.add( MATRIX_COMPILE_CONFIG_NAME )
|
||||
.setDescription( "Dependencies used to compile the matrix tests" )
|
||||
.extendsFrom( project.configurations.getByName( COMPILE_CONFIGURATION_NAME ) )
|
||||
.extendsFrom( project.configurations.getByName( TEST_COMPILE_CONFIGURATION_NAME ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare runtime configuration for matrix source set.
|
||||
*/
|
||||
private Configuration prepareRuntimeConfiguration() {
|
||||
return project.configurations.add( MATRIX_RUNTIME_CONFIG_NAME )
|
||||
.setDescription( "Dependencies (baseline) used to run the matrix tests" )
|
||||
.extendsFrom( matrixCompileConfig )
|
||||
.extendsFrom( project.configurations.getByName( RUNTIME_CONFIGURATION_NAME ) )
|
||||
.extendsFrom( project.configurations.getByName( TEST_RUNTIME_CONFIGURATION_NAME ) );
|
||||
}
|
||||
|
||||
|
||||
private SourceSet prepareSourceSet() {
|
||||
final SourceSetContainer sourceSets = project.convention.getPlugin( JavaPluginConvention ).sourceSets;
|
||||
SourceSet sourceSet = sourceSets.findByName( MATRIX_SOURCE_SET_NAME );
|
||||
if ( sourceSet == null ) {
|
||||
sourceSet = sourceSets.add( MATRIX_SOURCE_SET_NAME );
|
||||
}
|
||||
final SourceSet mainSourceSet = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME); //sourceSets.main
|
||||
final SourceSet unitTestSourceSet = sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME); //sourceSets.test
|
||||
sourceSet.compileClasspath = mainSourceSet.classes + unitTestSourceSet.classes + matrixCompileConfig
|
||||
sourceSet.runtimeClasspath = sourceSet.classes + mainSourceSet.classes + unitTestSourceSet.classes + matrixRuntimeConfig
|
||||
sourceSet.classesDir = new File(unitTestSourceSet.classesDir.parentFile, "matrix")
|
||||
sourceSet.resources {
|
||||
setSrcDirs(['src/matrix/java', 'src/matrix/resources'])
|
||||
}
|
||||
return sourceSet;
|
||||
}
|
||||
|
||||
private Task prepareGroupingTask() {
|
||||
Task matrixTask = project.tasks.add( MATRIX_TASK_NAME );
|
||||
matrixTask.group = "Verification"
|
||||
matrixTask.description = "Runs the unit tests on Database Matrix"
|
||||
generateNodes();
|
||||
if(!System.properties[SKIP_UNIT_TEST].equals('true'))
|
||||
createTestTaskForMatrixSourceSet();
|
||||
return matrixTask;
|
||||
}
|
||||
|
||||
private void generateNodeTasks(List<MatrixNode> matrixNodes) {
|
||||
// For now we just hard code this to locate the databases processed by
|
||||
// org.hibernate.build.gradle.testing.database.DatabaseProfilePlugin. But long term would be much better to
|
||||
// abstract this idea via the MatrixNode/MatrixNodeProvider interfaces; this would allow the jvm variance
|
||||
// needed for jdbc3/jdbc4 testing for example. Not to mention its much more generally applicable
|
||||
//
|
||||
// Also the notion that the plugin as a MatrixNodeProducer might not be appropriate. probably a split there
|
||||
// is in order too (config producer and jvm producer and somehow they get wired into a matrix).
|
||||
//
|
||||
// but again this is just a start.
|
||||
}
|
||||
|
||||
private Task prepareNodeTask(MatrixNode node) {
|
||||
String taskName = MATRIX_TASK_NAME + '_' + node.name
|
||||
log.debug( "Adding Matrix Testing task $taskName" );
|
||||
final Test nodeTask = project.tasks.add( taskName, Test );
|
||||
nodeTask.description = "Runs the matrix against ${node.name}"
|
||||
nodeTask.classpath = node.databaseProfile.testingRuntimeConfiguration + matrixSourceSet.runtimeClasspath
|
||||
nodeTask.testClassesDir = matrixSourceSet.classesDir
|
||||
nodeTask.ignoreFailures = true
|
||||
nodeTask.workingDir = node.baseOutputDirectory
|
||||
nodeTask.testReportDir = new File(node.baseOutputDirectory, "reports")
|
||||
nodeTask.testResultsDir = new File(node.baseOutputDirectory, "results")
|
||||
|
||||
nodeTask.dependsOn( project.tasks.getByName( matrixSourceSet.classesTaskName ) );
|
||||
nodeTask.systemProperties = node.databaseAllocation.properties
|
||||
nodeTask.systemProperties['hibernate.test.validatefailureexpected'] = true
|
||||
nodeTask.jvmArgs = ['-Xms1024M', '-Xmx1024M']//, '-XX:MaxPermSize=512M', '-Xss4096k', '-Xverify:none', '-XX:+UseFastAccessorMethods', '-XX:+DisableExplicitGC']
|
||||
nodeTask.maxHeapSize = "1024M"
|
||||
return nodeTask;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -121,85 +238,4 @@ public class MatrixTestingPlugin implements Plugin<Project> {
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare compile configuration for matrix source set.
|
||||
*/
|
||||
private Configuration prepareCompileConfiguration() {
|
||||
return project.configurations.add(MATRIX_COMPILE_CONFIG_NAME).setDescription("Dependencies used to compile the matrix tests").extendsFrom(project.configurations.getByName(COMPILE_CONFIGURATION_NAME)).extendsFrom(project.configurations.getByName(TEST_COMPILE_CONFIGURATION_NAME));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare runtime configuration for matrix source set.
|
||||
*/
|
||||
private Configuration prepareRuntimeConfiguration() {
|
||||
return project.configurations.add(MATRIX_RUNTIME_CONFIG_NAME).setDescription("Dependencies (baseline) used to run the matrix tests").extendsFrom(matrixCompileConfig).extendsFrom(project.configurations.getByName(RUNTIME_CONFIGURATION_NAME)).extendsFrom(project.configurations.getByName(TEST_RUNTIME_CONFIGURATION_NAME));
|
||||
}
|
||||
|
||||
private SourceSet prepareSourceSet() {
|
||||
final SourceSetContainer sourceSets = project.convention.getPlugin(JavaPluginConvention).sourceSets;
|
||||
SourceSet sourceSet = sourceSets.findByName(MATRIX_SOURCE_SET_NAME);
|
||||
if ( sourceSet == null ) {
|
||||
sourceSet = sourceSets.add(MATRIX_SOURCE_SET_NAME);
|
||||
}
|
||||
final SourceSet mainSourceSet = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME); //sourceSets.main
|
||||
final SourceSet unitTestSourceSet = sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME); //sourceSets.test
|
||||
sourceSet.compileClasspath = mainSourceSet.classes + unitTestSourceSet.classes + matrixCompileConfig
|
||||
sourceSet.runtimeClasspath = sourceSet.classes + mainSourceSet.classes + unitTestSourceSet.classes + matrixRuntimeConfig
|
||||
sourceSet.classesDir = new File(unitTestSourceSet.classesDir.parentFile, "matrix")
|
||||
sourceSet.resources {
|
||||
setSrcDirs(['src/matrix/java', 'src/matrix/resources'])
|
||||
}
|
||||
return sourceSet;
|
||||
}
|
||||
|
||||
private void generateNodes() {
|
||||
// For now we just hard code this to locate the databases processed by
|
||||
// org.hibernate.gradle.testing.database.DatabaseMatrixPlugin. But long term would be much better to
|
||||
// abstract this idea via the MatrixNode/MatrixNodeProvider interfaces; this would allow the jvm variance
|
||||
// needed for jdbc3/jdbc4 testing for example. Not to mention its much more generally applicable
|
||||
//
|
||||
// Also the notion that the plugin as a MatrixNodeProducer might not be appropriate. probably a split there
|
||||
// is in order too (config producer and jvm producer and somehow they get wired into a matrix).
|
||||
//
|
||||
// but again this is just a start.
|
||||
|
||||
for ( MatrixNode node: matrixNodes ) {
|
||||
Task nodeTask = prepareNodeTask(node);
|
||||
matrixTask.dependsOn(nodeTask);
|
||||
}
|
||||
}
|
||||
|
||||
private List<MatrixNode> locateMatrixNodes(Project project) {
|
||||
if ( project == null ) return null;
|
||||
if ( project.plugins.hasPlugin(DatabaseMatrixPlugin) ) {
|
||||
return project.plugins[DatabaseMatrixPlugin].matrixNodes;
|
||||
}
|
||||
else {
|
||||
locateMatrixNodes(project.parent)
|
||||
}
|
||||
}
|
||||
|
||||
private Task prepareNodeTask(MatrixNode node) {
|
||||
String taskName = MATRIX_TASK_NAME + '_' + node.name
|
||||
log.debug("Adding Matrix Testing task $taskName");
|
||||
final Test nodeTask = project.tasks.add(taskName, Test);
|
||||
nodeTask.description = "Runs the matrix against ${node.name}"
|
||||
nodeTask.classpath = node.testingRuntimeConfiguration + matrixSourceSet.runtimeClasspath
|
||||
nodeTask.testClassesDir = matrixSourceSet.classesDir
|
||||
nodeTask.ignoreFailures = true
|
||||
nodeTask.workingDir = node.baseOutputDirectory
|
||||
nodeTask.testReportDir = new File(node.baseOutputDirectory, "reports")
|
||||
nodeTask.testResultsDir = new File(node.baseOutputDirectory, "results")
|
||||
|
||||
nodeTask.dependsOn(project.tasks.getByName(matrixSourceSet.classesTaskName));
|
||||
nodeTask.systemProperties = node.properties
|
||||
nodeTask.systemProperties['hibernate.test.validatefailureexpected'] = true
|
||||
nodeTask.jvmArgs = ['-Xms1024M', '-Xmx1024M' ]//, '-XX:MaxPermSize=512M', '-Xss4096k', '-Xverify:none', '-XX:+UseFastAccessorMethods', '-XX:+DisableExplicitGC']
|
||||
nodeTask.maxHeapSize = "1024M"
|
||||
nodeTask.doLast {
|
||||
node.release()
|
||||
}
|
||||
return nodeTask;
|
||||
}
|
||||
}
|
@ -22,10 +22,10 @@
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package org.hibernate.gradle.util;
|
||||
package org.hibernate.build.gradle.util;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
* And exception intended to fail the build.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
@ -22,7 +22,7 @@
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package org.hibernate.gradle.util;
|
||||
package org.hibernate.build.gradle.util;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@ -37,14 +37,6 @@ public static boolean isFile(File file) {
|
||||
return file != null && file.exists() && file.isFile();
|
||||
}
|
||||
|
||||
public static boolean isDirectory(File file) {
|
||||
return file != null && file.exists() && file.isDirectory();
|
||||
}
|
||||
|
||||
public static boolean hasChildren(File file) {
|
||||
return isDirectory( file ) && file.listFiles() != null && file.listFiles().length > 0;
|
||||
}
|
||||
|
||||
public static void mkdir(File file) {
|
||||
if ( file == null || file.exists() ) {
|
||||
return;
|
@ -22,7 +22,7 @@
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package org.hibernate.gradle.util;
|
||||
package org.hibernate.build.gradle.util;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
@ -22,7 +22,7 @@
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package org.hibernate.gradle.util;
|
||||
package org.hibernate.build.gradle.util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
@ -21,16 +21,19 @@
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.build.qalab;
|
||||
|
||||
package org.hibernate.gradle.testing.matrix;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
*
|
||||
* Represents a database instances allocated in the JBoss/Red Hat Qe Lab via {@link DatabaseAllocator}
|
||||
*
|
||||
* @author mvecera
|
||||
* @author Strong Liu
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface MatrixNodeProvider {
|
||||
public List<MatrixNode> getMatrixNodes();
|
||||
public interface DatabaseAllocation {
|
||||
public Map<String,String> getProperties();
|
||||
|
||||
public void release();
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.build.qalab
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.api.logging.Logging
|
||||
import org.hibernate.build.gradle.testing.database.DatabaseProfile
|
||||
|
||||
/**
|
||||
* Helper for dealing with the "DB Allocator" service set up in the JBoss/Red Hat QE lab.
|
||||
*
|
||||
* Use the <code>hibernate-matrix-dballocation</code> setting to control db allocation. By default,
|
||||
* no allocations are performed. <code>hibernate-matrix-dballocation</code> could be either:<ul>
|
||||
* <li><b>all</b> - allocate all non-ignored databases</li>
|
||||
* <li><b>profile1{,profile2,...}</b> - allocate only the named profiles, provided the name is also one of the supported names</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author mvecera
|
||||
* @author Strong Liu
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
class DatabaseAllocator {
|
||||
private static final Logger log = Logging.getLogger( DatabaseAllocator.class );
|
||||
|
||||
public static final String ALLOCATION_ENABLED = "hibernate-matrix-dballocation";
|
||||
public static final String REQUESTEE = "hibernate-matrix-dballocation-requestee";
|
||||
|
||||
public static final String DB_ALLOCATOR_KEY = "dbAllocator";
|
||||
|
||||
public static def SUPPORTED_DB_NAMES = [
|
||||
"oracle9i", "oracle10g", "oracle11gR1", "oracle11gR2", "oracle11gR2RAC", "oracle11gR1RAC",
|
||||
"postgresql82", "postgresql83", "postgresql84", "postgresql91",
|
||||
"mysql50", "mysql51","mysql55",
|
||||
"db2-91", "db2-97",
|
||||
"mssql2005", "mssql2008R1", "mssql2008R2",
|
||||
"sybase155"
|
||||
];
|
||||
|
||||
private Map<String,DatabaseAllocation> databaseAllocationMap = new HashMap<String, DatabaseAllocation>();
|
||||
private final Project rootProject;
|
||||
|
||||
DatabaseAllocator(Project rootProject) {
|
||||
this.rootProject = rootProject
|
||||
}
|
||||
|
||||
public DatabaseAllocation getAllocation(DatabaseProfile profile) {
|
||||
DatabaseAllocation databaseAllocation = databaseAllocationMap.get( profile.name );
|
||||
if ( databaseAllocation == null ) {
|
||||
databaseAllocation = createAllocation( profile );
|
||||
databaseAllocationMap.put( profile.name, databaseAllocation );
|
||||
}
|
||||
return databaseAllocation;
|
||||
}
|
||||
|
||||
private DatabaseAllocation createAllocation(DatabaseProfile profile) {
|
||||
if ( isAllocationEnabled( profile.name ) ) {
|
||||
log.lifecycle( "using Allocator to get database [${profile.name}] connection info" );
|
||||
final File outputDirectory = new File( new File( rootProject.getBuildDir(), "matrix" ), profile.getName() )
|
||||
return new EnabledDatabaseAllocation( rootProject.getAnt(), profile, outputDirectory );
|
||||
}
|
||||
return new DisabledDatabaseAllocation( profile );
|
||||
}
|
||||
|
||||
private boolean isAllocationEnabled(String name) {
|
||||
if ( !SUPPORTED_DB_NAMES.contains(name) ) {
|
||||
return false
|
||||
};
|
||||
String value = System.properties[ALLOCATION_ENABLED]
|
||||
return value != null && (value.contains(name) || value.equals("all"));
|
||||
}
|
||||
|
||||
public static DatabaseAllocator locate(Project project) {
|
||||
if ( ! project.rootProject.hasProperty( DB_ALLOCATOR_KEY ) ) {
|
||||
project.rootProject.setProperty( DB_ALLOCATOR_KEY, new DatabaseAllocator( project.rootProject ) );
|
||||
}
|
||||
return (DatabaseAllocator) project.rootProject.properties[ DB_ALLOCATOR_KEY ];
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
@ -21,31 +21,27 @@
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.build.qalab
|
||||
|
||||
package org.hibernate.gradle.util;
|
||||
|
||||
import java.util.List;
|
||||
import org.hibernate.build.gradle.testing.database.DatabaseProfile
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ResolutionException extends BuildException {
|
||||
private final String moduleDescriptor;
|
||||
private final List<String> problemMessages;
|
||||
class DisabledDatabaseAllocation implements DatabaseAllocation {
|
||||
private final DatabaseProfile databaseProfile;
|
||||
|
||||
public ResolutionException(String moduleDescriptor, List<String> problemMessages) {
|
||||
super( "Problem performing resolution of module [" + moduleDescriptor + "]" );
|
||||
this.moduleDescriptor = moduleDescriptor;
|
||||
this.problemMessages = problemMessages;
|
||||
}
|
||||
DisabledDatabaseAllocation(DatabaseProfile databaseProfile) {
|
||||
this.databaseProfile = databaseProfile;
|
||||
}
|
||||
|
||||
public String getModuleDescriptor() {
|
||||
return moduleDescriptor;
|
||||
}
|
||||
@Override
|
||||
Map<String, String> getProperties() {
|
||||
return databaseProfile.hibernateProperties;
|
||||
}
|
||||
|
||||
public List<String> getProblemMessages() {
|
||||
return problemMessages;
|
||||
}
|
||||
@Override
|
||||
void release() {
|
||||
// nothing to do
|
||||
}
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.build.qalab
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.hibernate.build.gradle.testing.database.DatabaseProfile
|
||||
import org.hibernate.build.gradle.util.BuildException
|
||||
import org.gradle.api.logging.Logging
|
||||
import org.gradle.api.logging.Logger
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
class EnabledDatabaseAllocation implements DatabaseAllocation {
|
||||
private static final Logger log = Logging.getLogger( DatabaseAllocator.class );
|
||||
|
||||
private static final String DB_ALLOCATOR_URL = "http://dballocator.mw.lab.eng.bos.redhat.com:8080/Allocator/AllocatorServlet";
|
||||
private static final String ALLOCATOR_OUTPUT_FILE_NAME = "allocated-db.properties";
|
||||
private static final String DB_ALLOCATION_URL_POSTFIX = "hibernate-matrix-dballocation-url-postfix";
|
||||
|
||||
private static final String DRIVER_PROP = "hibernate.connection.driver_class";
|
||||
private static final String URL_PROP = "hibernate.connection.url";
|
||||
private static final String USERNAME_PROP = "hibernate.connection.username";
|
||||
private static final String PASSWORD_PROP = "hibernate.connection.password";
|
||||
|
||||
private static final int RETRIES = 30
|
||||
private static final int EXPIRY = 300;
|
||||
|
||||
private final DatabaseProfile databaseProfile
|
||||
private final AntBuilder ant;
|
||||
|
||||
private final File allocatorOutputFile;
|
||||
private final String requester;
|
||||
private final String uuid;
|
||||
|
||||
private final File tmpFile;
|
||||
|
||||
private final Map<String,String> properties;
|
||||
|
||||
EnabledDatabaseAllocation(AntBuilder ant, DatabaseProfile databaseProfile, File outputDirectory) {
|
||||
this.ant = ant;
|
||||
this.databaseProfile = databaseProfile;
|
||||
|
||||
outputDirectory.mkdirs()
|
||||
|
||||
this.allocatorOutputFile = new File( outputDirectory, ALLOCATOR_OUTPUT_FILE_NAME );
|
||||
this.tmpFile = new File( outputDirectory, "tmpfile" );
|
||||
|
||||
if ( System.properties.containsKey("hibernate-matrix-dballocation-requestee") ) {
|
||||
requester = System.properties["hibernate-matrix-dballocation-requestee"]
|
||||
}
|
||||
else {
|
||||
requester = "hibernate"
|
||||
}
|
||||
|
||||
if ( allocatorOutputFile.exists() ) {
|
||||
allocatorOutputFile.delete()
|
||||
}
|
||||
|
||||
int attempts = 0;
|
||||
while ( !(allocatorOutputFile.exists() && allocatorOutputFile.length() > 0) ) {
|
||||
if ( attempts >= RETRIES ) {
|
||||
throw new BuildException( 'Database unavailable' );
|
||||
}
|
||||
if ( attempts > 0 ) {
|
||||
log.lifecycle( "Trouble accessing Allocator servlet; waiting before trying again" );
|
||||
Thread.sleep( 60000 );
|
||||
}
|
||||
def allocatorUrl = DB_ALLOCATOR_URL +
|
||||
"?operation=alloc&label=${databaseProfile.name}&requestee=${requester}&expiry=${EXPIRY}"
|
||||
ant.get(
|
||||
src: allocatorUrl,
|
||||
dest: allocatorOutputFile.absolutePath,
|
||||
ignoreerrors: 'true'
|
||||
);
|
||||
attempts++
|
||||
}
|
||||
|
||||
def allocatorProps = new Properties();
|
||||
allocatorProps.load( new FileInputStream( allocatorOutputFile ) );
|
||||
|
||||
this.uuid = allocatorProps['uuid']
|
||||
log.lifecycle( "Finished allocating for DB instance [${databaseProfile.name}], uuid is [${uuid}]" );
|
||||
|
||||
properties = new HashMap<String, String>();
|
||||
properties.putAll( databaseProfile.hibernateProperties );
|
||||
properties[DRIVER_PROP] = allocatorProps["db.jdbc_class"]
|
||||
properties[URL_PROP] = allocatorProps["db.jdbc_url"] + getURLPostfix(databaseProfile.name)
|
||||
properties[USERNAME_PROP] = allocatorProps["db.username"]
|
||||
properties[PASSWORD_PROP] = allocatorProps["db.password"]
|
||||
properties["uuid"] = allocatorProps["uuid"];
|
||||
|
||||
clean();
|
||||
}
|
||||
|
||||
private String getURLPostfix(String dbName) {
|
||||
for ( String key: System.properties.keySet() ) {
|
||||
if ( key.startsWith(DB_ALLOCATION_URL_POSTFIX) ) {
|
||||
String db = key.substring(DB_ALLOCATION_URL_POSTFIX.length() + 1, key.length())
|
||||
if ( db.equalsIgnoreCase(dbName) ) {
|
||||
String postfix = System.properties[key];
|
||||
log.debug("found URL postfix[%s] for DB[%s]", postfix, db );
|
||||
return postfix;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
void clean() {
|
||||
log.lifecycle( "Cleaning DB [${databaseProfile.name}]..." );
|
||||
final String allocatorUrl = DB_ALLOCATOR_URL + "?operation=erase&uuid=${uuid}";
|
||||
ant.get( src: allocatorUrl, dest: tmpFile.absolutePath );
|
||||
}
|
||||
|
||||
@Override
|
||||
Map<String, String> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
void release() {
|
||||
log.lifecycle( "De-allocating DB [${databaseProfile.name}]..." );
|
||||
final String allocatorUrl = DB_ALLOCATOR_URL + "?operation=dealloc&uuid=${uuid}";
|
||||
ant.get( src: allocatorUrl, dest: tmpFile.absolutePath );
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,277 +0,0 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package org.hibernate.gradle.testing.database;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import groovy.lang.Closure;
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.logging.Logger;
|
||||
import org.gradle.api.logging.Logging;
|
||||
|
||||
import org.hibernate.gradle.testing.matrix.AbstractMatrixNode;
|
||||
import org.hibernate.gradle.testing.matrix.MatrixNode;
|
||||
import org.hibernate.gradle.testing.matrix.MatrixNodeProvider;
|
||||
import org.hibernate.gradle.util.DuplicatedDBConfigException;
|
||||
import org.hibernate.gradle.util.FileUtil;
|
||||
import org.hibernate.gradle.util.Jdk;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Strong Liu
|
||||
*/
|
||||
public class DatabaseMatrixPlugin implements Plugin<Project>, MatrixNodeProvider {
|
||||
private static final Logger log = Logging.getLogger( DatabaseMatrixPlugin.class );
|
||||
public static final String DEFAULT_DATABASE_DIRECTORY = "databases";
|
||||
public static final String MATRIX_DATABASES_LOCATION = "hibernate-matrix-databases";
|
||||
public static final String HIBERNATE_MATRIX_IGNORE = "hibernate-matrix-ignore";
|
||||
private static final String MATRIX_NODE_CONVENTION_KEY = "matrixNode";
|
||||
private static final String MATRIX_BUILD_FILE = "matrix.gradle";
|
||||
|
||||
private Project project;
|
||||
private Map<String, MatrixNode> matrixNodeMap = new HashMap();
|
||||
|
||||
public void apply(Project project) {
|
||||
this.project = project;
|
||||
applyDatabaseDirectories( getRootProject( project ).file( DEFAULT_DATABASE_DIRECTORY ) , true);
|
||||
String databasesDirPath = System.getProperty( MATRIX_DATABASES_LOCATION );
|
||||
if ( databasesDirPath != null ) {
|
||||
File databaseDir = new File( databasesDirPath );
|
||||
applyDatabaseDirectories( databaseDir, false );
|
||||
}
|
||||
}
|
||||
|
||||
private Project getRootProject(Project project) {
|
||||
return project.getParent() != null ? getRootProject( project.getParent() ) : project;
|
||||
}
|
||||
|
||||
|
||||
private void applyDatabaseDirectories(File databasesBaseDirObject, boolean isDefault) {
|
||||
if ( !FileUtil.isDirectory( databasesBaseDirObject ) ) {
|
||||
log.warn( "Giving DB profile location [" + databasesBaseDirObject + "] is not a valid directory, ignored." );
|
||||
return;
|
||||
}
|
||||
log.debug( "Applying database directory: " + databasesBaseDirObject );
|
||||
for ( File entry : databasesBaseDirObject.listFiles() ) {
|
||||
if ( FileUtil.isDirectory(entry) ) {
|
||||
applyPossibleDatabaseDirectory( entry, isDefault );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean ignoreDefault(String databaseName) {
|
||||
String value = System.getProperty( HIBERNATE_MATRIX_IGNORE );
|
||||
return ( value != null && ( value.equals( "all" ) || value.contains( databaseName ) ) );
|
||||
}
|
||||
|
||||
private void applyPossibleDatabaseDirectory(final File databaseDir, final boolean isDefault) {
|
||||
final String databaseName = databaseDir.getName();
|
||||
if ( isDefault && ignoreDefault( databaseName ) ) {
|
||||
log.debug( "Ignore default DB profile [{}]", databaseName );
|
||||
return;
|
||||
}
|
||||
log.debug( "Checking potential database directory : {}", databaseName );
|
||||
|
||||
MatrixNode node = null;
|
||||
|
||||
// 3 types of support here:
|
||||
// 1) directory contains a file named 'matrix.gradle'
|
||||
// 2) directory contains a file named 'ivy.xml' (we prefer matrix.gradle --stliu)
|
||||
// 3) directory contains a sub-directory named 'jdbc' containing the driver artifacts
|
||||
|
||||
final File matrixFile = new File( databaseDir, MATRIX_BUILD_FILE );
|
||||
if ( FileUtil.isFile( matrixFile ) ) {
|
||||
|
||||
// (1) we found the 'matrix.gradle' file
|
||||
node = prepareFromGradleFile( matrixFile );
|
||||
}
|
||||
else {
|
||||
// final File ivyXmlFile = new File( databaseDir, IVY_XML_FILE );
|
||||
// if ( FileUtil.isFile( ivyXmlFile ) ) {
|
||||
// // (2) we found the 'ivy.xml' file
|
||||
// node = prepareFromIvyXmlFile( ivyXmlFile );
|
||||
// }
|
||||
// else {
|
||||
final File jdbcDir = new File( databaseDir, "jdbc" );
|
||||
if ( FileUtil.isDirectory( jdbcDir ) ) {
|
||||
node = prepareFromJdbcDir( jdbcDir );
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
if ( node == null ) {
|
||||
log.info( "Doesn't found valid Matrix database configuration file in directory : {}", databaseDir );
|
||||
return;
|
||||
}
|
||||
|
||||
final File propertiesFile = new File( new File( databaseDir, "resources" ), "hibernate.properties" );
|
||||
if ( FileUtil.isFile( propertiesFile ) ) {
|
||||
node.setHibernatePropertyFile( propertiesFile );
|
||||
}
|
||||
else {
|
||||
log.warn( "No 'hibernate.properties' found in {}/resources", databaseDir );
|
||||
}
|
||||
log.debug( "Adding node[{}] " + node.getName() );
|
||||
if ( matrixNodeMap.containsKey( node.getName() ) ) {
|
||||
throw new DuplicatedDBConfigException( "There is already a Matrix node named " + node.getName() );
|
||||
}
|
||||
else {
|
||||
matrixNodeMap.put( node.getName(), node );
|
||||
}
|
||||
}
|
||||
|
||||
private MatrixNode prepareFromGradleFile(File matrixFile) {
|
||||
log.debug( "Found matrix file : " + matrixFile );
|
||||
MatrixDotGradleMatrixNodeImpl matrixNode = new MatrixDotGradleMatrixNodeImpl(
|
||||
matrixFile.getParentFile()
|
||||
.getName()
|
||||
);
|
||||
MatrixDotGradleMatrixNodeConvention convention = new MatrixDotGradleMatrixNodeConvention( matrixNode );
|
||||
project.getConvention().getPlugins().put( MATRIX_NODE_CONVENTION_KEY, convention );
|
||||
try {
|
||||
project.apply( Collections.singletonMap( "from", matrixFile ) );
|
||||
}
|
||||
finally {
|
||||
project.getConvention().getPlugins().remove( MATRIX_NODE_CONVENTION_KEY );
|
||||
}
|
||||
return matrixNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link MatrixNode} implementation for handling 'matrix.gradle' files
|
||||
*/
|
||||
private class MatrixDotGradleMatrixNodeImpl extends AbstractMatrixNode {
|
||||
private final Configuration jdbcDependencies;
|
||||
private Jdk jdk;
|
||||
|
||||
public MatrixDotGradleMatrixNodeImpl(String name) {
|
||||
super( project, name );
|
||||
this.jdbcDependencies = prepareConfiguration( name );
|
||||
this.jdk = getDefaultJdk();
|
||||
}
|
||||
|
||||
public Jdk getTestingRuntimeJdk() {
|
||||
return jdk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DependencyResolver getDependencyResolver() {
|
||||
return new DependencyResolver() {
|
||||
@Override
|
||||
public Project getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration resolve() {
|
||||
return jdbcDependencies;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides simplified convention object to the database-specific script for convenient configuration.
|
||||
*/
|
||||
private class MatrixDotGradleMatrixNodeConvention {
|
||||
private final MatrixDotGradleMatrixNodeImpl matrixNode;
|
||||
|
||||
private MatrixDotGradleMatrixNodeConvention(MatrixDotGradleMatrixNodeImpl matrixNode) {
|
||||
this.matrixNode = matrixNode;
|
||||
}
|
||||
|
||||
public void jdbcDependency(Object dependencyNotation, Closure closure) {
|
||||
project.getDependencies().add( matrixNode.jdbcDependencies.getName(), dependencyNotation, closure );
|
||||
}
|
||||
|
||||
public void jdbcDependency(Object dependencyNotation) {
|
||||
log.debug(
|
||||
"Adding JDBC dependency[{}] resolved from matrix.gradle",
|
||||
matrixNode.jdbcDependencies.getName()
|
||||
);
|
||||
project.getDependencies().add( matrixNode.jdbcDependencies.getName(), dependencyNotation );
|
||||
}
|
||||
|
||||
public void jdk(Jdk jdk) {
|
||||
matrixNode.jdk = jdk;
|
||||
}
|
||||
}
|
||||
|
||||
private MatrixNode prepareFromJdbcDir(File jdbcDir) {
|
||||
log.debug( "Found local jdbc dir : " + jdbcDir );
|
||||
return new LocalMatrixNode( jdbcDir );
|
||||
}
|
||||
|
||||
private class LocalMatrixNode extends AbstractMatrixNode {
|
||||
private final Jdk jdk = getDefaultJdk();
|
||||
private final LocalJdbcDependencyResolver resolver;
|
||||
|
||||
private LocalMatrixNode(File jdbcDir) {
|
||||
super( project, jdbcDir.getParentFile().getName() );
|
||||
resolver = new LocalJdbcDependencyResolver( project, jdbcDir.getParentFile() );
|
||||
}
|
||||
|
||||
public Jdk getTestingRuntimeJdk() {
|
||||
return jdk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DependencyResolver getDependencyResolver() {
|
||||
return resolver;
|
||||
}
|
||||
}
|
||||
|
||||
public List<MatrixNode> getMatrixNodes() {
|
||||
return Collections.unmodifiableList( new ArrayList<MatrixNode>( matrixNodeMap.values() ) );
|
||||
}
|
||||
|
||||
private Configuration prepareConfiguration(String name) {
|
||||
Configuration configuration = getOrCreateConfiguration( name );
|
||||
configuration.setDescription( "The [" + name + "] JDBC dependency configuration" );
|
||||
return configuration;
|
||||
}
|
||||
|
||||
private Configuration getOrCreateConfiguration(String configurationName) {
|
||||
Configuration configuration = project.getConfigurations().findByName( configurationName );
|
||||
if ( configuration == null ) {
|
||||
configuration = project.getConfigurations().add( configurationName );
|
||||
}
|
||||
return configuration;
|
||||
}
|
||||
|
||||
private Jdk getDefaultJdk() {
|
||||
return new Jdk();
|
||||
}
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package org.hibernate.gradle.testing.database;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.logging.Logger;
|
||||
import org.gradle.api.logging.Logging;
|
||||
|
||||
import org.hibernate.gradle.util.FileUtil;
|
||||
import org.hibernate.gradle.util.IvyResolutionHelper;
|
||||
import org.hibernate.gradle.util.ResolutionException;
|
||||
|
||||
/**
|
||||
* @author Strong Liu
|
||||
*/
|
||||
public class IvyDependencyResolver implements DependencyResolver {
|
||||
private static final Logger log = Logging.getLogger( IvyDependencyResolver.class );
|
||||
|
||||
private final File ivyXml;
|
||||
private final Project project;
|
||||
private final IvyResolutionHelper ivyResolutionHelper;
|
||||
private Configuration configuration;
|
||||
|
||||
public IvyDependencyResolver(File ivyXml, Project project) {
|
||||
this.ivyXml = ivyXml;
|
||||
this.project = project;
|
||||
this.ivyResolutionHelper = new IvyResolutionHelper( project );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Project getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration resolve() {
|
||||
if ( configuration == null ) {
|
||||
if ( FileUtil.isFile( ivyXml ) ) {
|
||||
String databaseName = ivyXml.getParentFile().getName();
|
||||
try {
|
||||
log.debug(
|
||||
"Using IvyDependencyResolver to resolve {} dependencies with file {} ",
|
||||
databaseName,
|
||||
ivyXml
|
||||
);
|
||||
configuration = ivyResolutionHelper.resolve( ivyXml, databaseName );
|
||||
}
|
||||
catch ( ResolutionException e ) {
|
||||
log.warn( "Skipping database '{}' due to problems resolving dependencies", databaseName );
|
||||
}
|
||||
|
||||
if ( configuration != null ) {
|
||||
configuration.setVisible( true );
|
||||
configuration.setDescription(
|
||||
"The [" + ivyXml.getParentFile()
|
||||
.getName() + "] JDBC dependency configuration"
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return configuration;
|
||||
}
|
||||
}
|
@ -1,218 +0,0 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package org.hibernate.gradle.testing.database;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.ivy.Ivy;
|
||||
import org.apache.ivy.core.cache.DefaultRepositoryCacheManager;
|
||||
import org.apache.ivy.core.cache.RepositoryCacheManager;
|
||||
import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
|
||||
import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
|
||||
import org.apache.ivy.core.module.id.ModuleRevisionId;
|
||||
import org.apache.ivy.core.report.ResolveReport;
|
||||
import org.apache.ivy.core.settings.IvySettings;
|
||||
import org.apache.ivy.plugins.resolver.DependencyResolver;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.internal.artifacts.IvyService;
|
||||
import org.gradle.api.internal.artifacts.configurations.DefaultConfigurationContainer;
|
||||
import org.gradle.api.internal.artifacts.configurations.ResolverProvider;
|
||||
import org.gradle.api.internal.artifacts.dependencies.DefaultSelfResolvingDependency;
|
||||
import org.gradle.api.internal.artifacts.ivyservice.DefaultIvyService;
|
||||
import org.gradle.api.internal.artifacts.ivyservice.ErrorHandlingIvyService;
|
||||
import org.gradle.api.internal.artifacts.ivyservice.IvyFactory;
|
||||
import org.gradle.api.internal.artifacts.ivyservice.SettingsConverter;
|
||||
import org.gradle.api.internal.artifacts.ivyservice.ShortcircuitEmptyConfigsIvyService;
|
||||
import org.gradle.api.internal.artifacts.repositories.InternalRepository;
|
||||
import org.gradle.api.internal.file.AbstractFileCollection;
|
||||
import org.gradle.invocation.DefaultGradle;
|
||||
|
||||
import org.hibernate.gradle.util.BuildException;
|
||||
import org.hibernate.gradle.util.ResolutionException;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class IvyXmlDependency extends DefaultSelfResolvingDependency {
|
||||
private final String name;
|
||||
|
||||
public IvyXmlDependency(Project project, File ivyXmlFile) {
|
||||
super( new IvyXmlDependencyFileCollection( project, ivyXmlFile ) );
|
||||
this.name = ivyXmlFile.getParentFile().getName() + '/' + ivyXmlFile.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IvyXmlDependencyFileCollection getSource() {
|
||||
return (IvyXmlDependencyFileCollection) super.getSource();
|
||||
}
|
||||
|
||||
private static class IvyXmlDependencyFileCollection extends AbstractFileCollection {
|
||||
private final Project project;
|
||||
private final File ivyXmlFile;
|
||||
private Set<File> resolvedDependencyFiles;
|
||||
|
||||
private IvyXmlDependencyFileCollection(Project project, File ivyXmlFile) {
|
||||
this.project = project;
|
||||
this.ivyXmlFile = ivyXmlFile;
|
||||
}
|
||||
|
||||
public File getIvyXmlFile() {
|
||||
return ivyXmlFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return ivyXmlFile.getAbsolutePath();
|
||||
}
|
||||
|
||||
public Set<File> getFiles() {
|
||||
if ( resolvedDependencyFiles == null ) {
|
||||
resolvedDependencyFiles = resolveDependencyFiles();
|
||||
}
|
||||
return resolvedDependencyFiles;
|
||||
}
|
||||
|
||||
private Set<File> resolveDependencyFiles() {
|
||||
DefaultIvyService ivyService = unwrap(
|
||||
( (DefaultConfigurationContainer) project.getConfigurations() ).getIvyService()
|
||||
);
|
||||
|
||||
final ModuleDescriptor moduleDescriptor = resolveIvyXml( ivyService );
|
||||
|
||||
DefaultRepositoryCacheManager repositoryCacheManager = null;
|
||||
final ResolverProvider resolverProvider = ivyService.getResolverProvider();
|
||||
for ( DependencyResolver resolver : resolverProvider.getResolvers() ) {
|
||||
RepositoryCacheManager potentialRepositoryCacheManager = resolver.getRepositoryCacheManager();
|
||||
if ( DefaultRepositoryCacheManager.class.isInstance( potentialRepositoryCacheManager ) ) {
|
||||
repositoryCacheManager = (DefaultRepositoryCacheManager) potentialRepositoryCacheManager;
|
||||
}
|
||||
}
|
||||
if ( repositoryCacheManager == null ) {
|
||||
throw buildResolutionException( moduleDescriptor.getModuleRevisionId(), "Unable to locate proper dependency cache manager" );
|
||||
}
|
||||
|
||||
HashSet<File> dependencyFiles = new HashSet<File>();
|
||||
for ( DependencyDescriptor dependencyDescriptor : moduleDescriptor.getDependencies() ) {
|
||||
final ModuleRevisionId info = dependencyDescriptor.getDynamicConstraintDependencyRevisionId();
|
||||
|
||||
dependencyFiles.add( repositoryCacheManager.getIvyFileInCache( info ) );
|
||||
}
|
||||
|
||||
return dependencyFiles;
|
||||
}
|
||||
|
||||
private DefaultIvyService unwrap(IvyService ivyService) {
|
||||
if ( DefaultIvyService.class.isInstance( ivyService ) ) {
|
||||
return (DefaultIvyService) ivyService;
|
||||
}
|
||||
|
||||
if ( ErrorHandlingIvyService.class.isInstance( ivyService ) ) {
|
||||
return unwrap( ( (ErrorHandlingIvyService) ivyService ).getIvyService() );
|
||||
}
|
||||
|
||||
if ( ShortcircuitEmptyConfigsIvyService.class.isInstance( ivyService ) ) {
|
||||
return unwrap( ( (ShortcircuitEmptyConfigsIvyService) ivyService ).getIvyService() );
|
||||
}
|
||||
|
||||
throw new BuildException( "Do not know how to extract needed ivy config from ivy service of type " + ivyService.getClass().getName() );
|
||||
}
|
||||
|
||||
private ModuleDescriptor resolveIvyXml(DefaultIvyService ivyService) {
|
||||
Ivy ivy = locateIvyService( ivyService );
|
||||
ResolveReport resolveReport = performResolve( ivy, ivyXmlFile );
|
||||
return resolveReport.getModuleDescriptor();
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
private ResolveReport performResolve(Ivy ivy, File ivyXmlFile) {
|
||||
try {
|
||||
ResolveReport resolveReport = ivy.resolve( ivyXmlFile );
|
||||
if ( resolveReport.hasError() ) {
|
||||
throw buildResolutionException(
|
||||
resolveReport.getModuleDescriptor().getModuleRevisionId(),
|
||||
resolveReport.getAllProblemMessages()
|
||||
);
|
||||
}
|
||||
return resolveReport;
|
||||
}
|
||||
catch ( ParseException e ) {
|
||||
throw new BuildException( "Malformed ivy dependency file [" + ivyXmlFile.getName() + "]", e );
|
||||
}
|
||||
catch ( IOException e ) {
|
||||
throw new BuildException( "Problem reading ivy dependency file [" + ivyXmlFile.getName() + "]", e );
|
||||
}
|
||||
}
|
||||
|
||||
private Ivy locateIvyService(DefaultIvyService ivyService) {
|
||||
final IvyFactory ivyFactory = ivyService.getIvyFactory();
|
||||
final SettingsConverter settingsConverter = ivyService.getSettingsConverter();
|
||||
final ResolverProvider resolverProvider = ivyService.getResolverProvider();
|
||||
|
||||
// Ugh, can absolutely find no way to access this other than a bunch of recursive reflection calls to
|
||||
// locate the build's org.gradle.api.internal.project.TopLevelBuildServiceRegistry and access its
|
||||
// private org.gradle.api.internal.project.TopLevelBuildServiceRegistry.clientModuleRegistry field.
|
||||
//
|
||||
// Not sure if it is critical to reuse that map instance or not. seems to work without, but i have no
|
||||
// idea about the ramifications.
|
||||
Map<String, ModuleDescriptor> clientModuleRegistry = new HashMap<String, ModuleDescriptor>();
|
||||
|
||||
// this part is mainly DefaultIvyService#ivyForResolve
|
||||
IvySettings ivySettings = settingsConverter.convertForResolve(
|
||||
resolverProvider.getResolvers(),
|
||||
project.getGradle().getGradleUserHomeDir(),
|
||||
getGradeService( InternalRepository.class ),
|
||||
clientModuleRegistry
|
||||
);
|
||||
return ivyFactory.createIvy( ivySettings );
|
||||
}
|
||||
|
||||
protected <T> T getGradeService(Class<T> type) {
|
||||
return ( (DefaultGradle) project.getGradle() ).getServices().get( type );
|
||||
}
|
||||
}
|
||||
|
||||
private static ResolutionException buildResolutionException(ModuleRevisionId descriptor, List<String> messages) {
|
||||
return new ResolutionException( descriptor.toString(), messages );
|
||||
}
|
||||
|
||||
private static ResolutionException buildResolutionException(ModuleRevisionId descriptor, String... messages) {
|
||||
return buildResolutionException( descriptor, Arrays.asList( messages ) );
|
||||
}
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package org.hibernate.gradle.testing.database;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.internal.artifacts.dependencies.DefaultSelfResolvingDependency;
|
||||
import org.gradle.api.logging.Logger;
|
||||
import org.gradle.api.logging.Logging;
|
||||
|
||||
import org.hibernate.gradle.util.FileUtil;
|
||||
import org.hibernate.gradle.util.IvyResolutionHelper;
|
||||
|
||||
/**
|
||||
* @author Strong Liu
|
||||
*/
|
||||
@SuppressWarnings("cast")
|
||||
public class LocalJdbcDependencyResolver implements DependencyResolver {
|
||||
private static final Logger log = Logging.getLogger( LocalJdbcDependencyResolver.class );
|
||||
|
||||
private final File databaseDir;
|
||||
private final Project project;
|
||||
private final IvyResolutionHelper ivyResolutionHelper;
|
||||
private Configuration configuration;
|
||||
|
||||
public LocalJdbcDependencyResolver(Project project, File databaseDir) {
|
||||
this.databaseDir = databaseDir;
|
||||
this.project = project;
|
||||
this.ivyResolutionHelper = new IvyResolutionHelper( project );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Project getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration resolve() {
|
||||
if ( configuration == null ) {
|
||||
final File jdbcDir = new File( databaseDir, "jdbc" );
|
||||
if ( FileUtil.isDirectory( jdbcDir ) ) {
|
||||
configuration = createSelfContainedConfiguration( jdbcDir, databaseDir.getName() );
|
||||
}
|
||||
else {
|
||||
log.warn( "Found 'jdbc' directory, but no entries" );
|
||||
}
|
||||
if ( configuration != null ) {
|
||||
configuration.setVisible( true );
|
||||
configuration.setDescription( "The [" + databaseDir.getName() + "] JDBC dependency configuration" );
|
||||
|
||||
}
|
||||
}
|
||||
return configuration;
|
||||
}
|
||||
|
||||
private Configuration createSelfContainedConfiguration(File directory, String configurationName) {
|
||||
Configuration configuration = ivyResolutionHelper.getOrCreateConfiguration( configurationName );
|
||||
DefaultSelfResolvingDependency dependency =
|
||||
new DefaultSelfResolvingDependency( project.files( (File[]) directory.listFiles() ) );
|
||||
configuration.addDependency( dependency );
|
||||
return configuration;
|
||||
}
|
||||
|
||||
}
|
@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package org.hibernate.gradle.testing.matrix;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
import hudson.util.DBAllocation;
|
||||
import hudson.util.DBAllocationHelper;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.logging.Logger;
|
||||
import org.gradle.api.logging.Logging;
|
||||
|
||||
import org.hibernate.gradle.util.FileUtil;
|
||||
|
||||
/**
|
||||
* @author Strong Liu
|
||||
*/
|
||||
public abstract class AbstractMatrixNode implements MatrixNode {
|
||||
private static final Logger log = Logging.getLogger( AbstractMatrixNode.class );
|
||||
private final String name;
|
||||
private final File baseOutputDirectory;
|
||||
private final DBAllocation dbAllocation;
|
||||
private File propertyFile;
|
||||
private Map<String, String> properties;
|
||||
private String uuid;
|
||||
|
||||
protected AbstractMatrixNode(final Project project, final String name) {
|
||||
this.name = name;
|
||||
this.baseOutputDirectory = new File( new File( project.getBuildDir(), "matrix" ), getName() );
|
||||
FileUtil.mkdir( baseOutputDirectory );
|
||||
this.dbAllocation = new DBAllocation( baseOutputDirectory );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getBaseOutputDirectory() {
|
||||
return baseOutputDirectory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration getTestingRuntimeConfiguration() {
|
||||
return getDependencyResolver().resolve();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
if ( DBAllocationHelper.isDBAllocationEnabled( getName() ) ) {
|
||||
if ( uuid != null ) {
|
||||
try {
|
||||
dbAllocation.release( uuid );
|
||||
}
|
||||
catch ( RuntimeException e ) {
|
||||
log.warn( "DBAllocator failed to release db["+getName()+"]", e );
|
||||
}
|
||||
} else {
|
||||
log.warn( getName() + "is enabled to use DBAllocation, but the allocated uuid is null" );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBAllocation getDBAllocation() {
|
||||
return dbAllocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHibernatePropertyFile(File file) {
|
||||
this.propertyFile = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getHibernatePropertyFile() {
|
||||
return propertyFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getProperties() {
|
||||
if ( properties == null ) {
|
||||
properties = DBAllocationHelper.getProperties( this );
|
||||
uuid = properties.get( "uuid" );
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if ( this == o ) {
|
||||
return true;
|
||||
}
|
||||
if ( o == null || getClass() != o.getClass() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AbstractMatrixNode that = (AbstractMatrixNode) o;
|
||||
|
||||
if ( name != null ? !name.equals( that.name ) : that.name != null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name != null ? name.hashCode() : 0;
|
||||
}
|
||||
}
|
@ -1,215 +0,0 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package org.hibernate.gradle.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.ivy.Ivy;
|
||||
import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
|
||||
import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
|
||||
import org.apache.ivy.core.module.id.ModuleRevisionId;
|
||||
import org.apache.ivy.core.report.ResolveReport;
|
||||
import org.apache.ivy.core.settings.IvySettings;
|
||||
import org.apache.ivy.util.AbstractMessageLogger;
|
||||
import org.apache.ivy.util.Message;
|
||||
import org.apache.ivy.util.MessageLogger;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.artifacts.Dependency;
|
||||
import org.gradle.api.internal.artifacts.IvyService;
|
||||
import org.gradle.api.internal.artifacts.configurations.DefaultConfigurationContainer;
|
||||
import org.gradle.api.internal.artifacts.configurations.ResolverProvider;
|
||||
import org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency;
|
||||
import org.gradle.api.internal.artifacts.ivyservice.DefaultIvyService;
|
||||
import org.gradle.api.internal.artifacts.ivyservice.ErrorHandlingIvyService;
|
||||
import org.gradle.api.internal.artifacts.ivyservice.IvyFactory;
|
||||
import org.gradle.api.internal.artifacts.ivyservice.SettingsConverter;
|
||||
import org.gradle.api.internal.artifacts.ivyservice.ShortcircuitEmptyConfigsIvyService;
|
||||
import org.gradle.api.internal.artifacts.repositories.InternalRepository;
|
||||
import org.gradle.api.logging.Logger;
|
||||
import org.gradle.api.logging.Logging;
|
||||
import org.gradle.invocation.DefaultGradle;
|
||||
|
||||
/**
|
||||
* A helper for handling resolution of ivy.xml files through Ivy calls using the bits and pieces of Ivy config
|
||||
* from Gradle.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class IvyResolutionHelper {
|
||||
private static final Logger log = Logging.getLogger( IvyResolutionHelper.class );
|
||||
|
||||
private final Project project;
|
||||
|
||||
/**
|
||||
* Creates an Ivy resolution helper for the given project. The project will be the one on
|
||||
* which the requested configurations are created/used.
|
||||
*
|
||||
* @param project The project into which to inject the resolved dependencies.
|
||||
*/
|
||||
public IvyResolutionHelper(Project project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constitutes the main API. Resolve the dependencies named in the given ivy.xml file into the named
|
||||
* configuration.
|
||||
*
|
||||
* @param ivyXmlFile The ivy.xml file
|
||||
* @param configurationName The name of the configuration into which to place the resolved dependencies.
|
||||
*
|
||||
* @return The configuration. Returns null to indicate a problem doing the resolution.
|
||||
*/
|
||||
public Configuration resolve(File ivyXmlFile, String configurationName) {
|
||||
log.debug( "Resolving file[{}] by configuration[{}]", ivyXmlFile, configurationName );
|
||||
ResolveReport resolveReport = performResolve( getIvy(), ivyXmlFile );
|
||||
ModuleDescriptor moduleDescriptor = resolveReport.getModuleDescriptor();
|
||||
Configuration configuration = getOrCreateConfiguration( configurationName );
|
||||
for ( DependencyDescriptor dependencyDescriptor : moduleDescriptor.getDependencies() ) {
|
||||
final ModuleRevisionId info = dependencyDescriptor.getDynamicConstraintDependencyRevisionId();
|
||||
final Dependency dependency = new DefaultExternalModuleDependency(
|
||||
info.getOrganisation(),
|
||||
info.getName(),
|
||||
info.getRevision()
|
||||
);
|
||||
configuration.addDependency( dependency );
|
||||
log.debug( "Added dependency {} to configuration {}", dependency, configurationName );
|
||||
}
|
||||
|
||||
return configuration;
|
||||
}
|
||||
|
||||
public Configuration getOrCreateConfiguration(String configurationName) {
|
||||
Configuration configuration = project.getConfigurations().findByName( configurationName );
|
||||
if ( configuration == null ) {
|
||||
configuration = project.getConfigurations().add( configurationName );
|
||||
}
|
||||
return configuration;
|
||||
}
|
||||
|
||||
@SuppressWarnings( { "unchecked" })
|
||||
protected ResolveReport performResolve(Ivy ivy, File ivyXmlFile) {
|
||||
final MessageLogger originalMessageLogger = Message.getDefaultLogger();
|
||||
Message.setDefaultLogger( new NoOpMessageLogger() );
|
||||
try {
|
||||
ResolveReport resolveReport = ivy.resolve( ivyXmlFile );
|
||||
if ( resolveReport.hasError() ) {
|
||||
throw new ResolutionException(
|
||||
resolveReport.getModuleDescriptor().getModuleRevisionId().toString(),
|
||||
resolveReport.getAllProblemMessages()
|
||||
);
|
||||
}
|
||||
return resolveReport;
|
||||
}
|
||||
catch ( ParseException e ) {
|
||||
throw new BuildException( "Malformed ivy dependency file [" + ivyXmlFile.getName() + "]", e );
|
||||
}
|
||||
catch ( IOException e ) {
|
||||
throw new BuildException( "Problem reading ivy dependency file [" + ivyXmlFile.getName() + "]", e );
|
||||
}
|
||||
finally {
|
||||
Message.setDefaultLogger( originalMessageLogger );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link Ivy} instance based on the running Gradle instance.
|
||||
* <p/>
|
||||
* Much of this is copied from {@link org.gradle.api.internal.artifacts.ivyservice.DefaultIvyService} because it
|
||||
* unfortunately does not expose the needed information.
|
||||
*
|
||||
* @return The generated {@link Ivy} instance
|
||||
*/
|
||||
private Ivy getIvy() {
|
||||
DefaultIvyService ivyService = unwrap(
|
||||
( (DefaultConfigurationContainer) project.getConfigurations() ).getIvyService()
|
||||
);
|
||||
|
||||
final IvyFactory ivyFactory = ivyService.getIvyFactory();
|
||||
final SettingsConverter settingsConverter = ivyService.getSettingsConverter();
|
||||
final ResolverProvider resolverProvider = ivyService.getResolverProvider();
|
||||
|
||||
// Ugh, can absolutely find no way to access this other than a bunch of recursive reflection calls to
|
||||
// locate the build's org.gradle.api.internal.project.TopLevelBuildServiceRegistry and access its
|
||||
// private org.gradle.api.internal.project.TopLevelBuildServiceRegistry.clientModuleRegistry field.
|
||||
//
|
||||
// Not sure if it is critical to reuse that map instance or not. seems to work without, but i have no
|
||||
// idea about the ramifications.
|
||||
Map<String, ModuleDescriptor> clientModuleRegistry = new HashMap<String, ModuleDescriptor>();
|
||||
|
||||
// this part is mainly DefaultIvyService#ivyForResolve
|
||||
IvySettings ivySettings = settingsConverter.convertForResolve(
|
||||
resolverProvider.getResolvers(),
|
||||
project.getGradle().getGradleUserHomeDir(),
|
||||
getGradeService( InternalRepository.class ),
|
||||
clientModuleRegistry
|
||||
);
|
||||
return ivyFactory.createIvy( ivySettings );
|
||||
}
|
||||
|
||||
private DefaultIvyService unwrap(IvyService ivyService) {
|
||||
if ( DefaultIvyService.class.isInstance( ivyService ) ) {
|
||||
return (DefaultIvyService) ivyService;
|
||||
}
|
||||
|
||||
if ( ErrorHandlingIvyService.class.isInstance( ivyService ) ) {
|
||||
return unwrap( ( (ErrorHandlingIvyService) ivyService ).getIvyService() );
|
||||
}
|
||||
|
||||
if ( ShortcircuitEmptyConfigsIvyService.class.isInstance( ivyService ) ) {
|
||||
return unwrap( ( (ShortcircuitEmptyConfigsIvyService) ivyService ).getIvyService() );
|
||||
}
|
||||
|
||||
throw new BuildException(
|
||||
"Do not know how to extract needed ivy config from ivy service of type " + ivyService.getClass()
|
||||
.getName()
|
||||
);
|
||||
}
|
||||
|
||||
protected <T> T getGradeService(Class<T> type) {
|
||||
return ( (DefaultGradle) project.getGradle() ).getServices().get( type );
|
||||
}
|
||||
|
||||
private static class NoOpMessageLogger extends AbstractMessageLogger implements MessageLogger {
|
||||
public void log(String s, int i) {
|
||||
}
|
||||
|
||||
public void rawlog(String s, int i) {
|
||||
}
|
||||
|
||||
public void sumupProblems() {
|
||||
}
|
||||
|
||||
protected void doProgress() {
|
||||
}
|
||||
|
||||
protected void doEndProgress(String s) {
|
||||
}
|
||||
}
|
||||
}
|
3
databases/.gitignore
vendored
Normal file
3
databases/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
#Ignore any sub directory named 'local'. these are used to define custom database profiles local
|
||||
# to the developer's machine
|
||||
/local
|
@ -1,7 +1,7 @@
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'antlr'
|
||||
apply plugin: org.hibernate.build.gradle.inject.InjectionPlugin
|
||||
apply plugin: org.hibernate.gradle.testing.matrix.MatrixTestingPlugin
|
||||
apply plugin: org.hibernate.build.gradle.testing.matrix.MatrixTestingPlugin
|
||||
|
||||
dependencies {
|
||||
compile( libraries.commons_collections )
|
||||
|
@ -2,7 +2,7 @@ import org.apache.tools.ant.filters.ReplaceTokens
|
||||
|
||||
apply plugin: 'java'
|
||||
apply plugin: "jdocbook"
|
||||
apply plugin: org.hibernate.gradle.testing.matrix.MatrixTestingPlugin
|
||||
apply plugin: org.hibernate.build.gradle.testing.matrix.MatrixTestingPlugin
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
|
@ -1,5 +1,5 @@
|
||||
apply plugin: 'java'
|
||||
apply plugin: org.hibernate.gradle.testing.matrix.MatrixTestingPlugin
|
||||
apply plugin: org.hibernate.build.gradle.testing.matrix.MatrixTestingPlugin
|
||||
|
||||
dependencies {
|
||||
compile( project( ':hibernate-core' ) )
|
||||
|
Loading…
x
Reference in New Issue
Block a user