HHH-6931 - Provide local database hook

This commit is contained in:
Steve Ebersole 2012-01-03 20:43:15 -06:00
parent ccc087b975
commit ab94a18c33
30 changed files with 1092 additions and 1570 deletions

View File

@ -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_

View File

@ -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)
}
}

View File

@ -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"));
}
}

View File

@ -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;
}
}

View 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,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();
}

View File

@ -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;
}
}

View File

@ -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 );
}
}

View 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,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;
}
}

View File

@ -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 );
}
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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
*/

View File

@ -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;

View File

@ -22,7 +22,7 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.gradle.util;
package org.hibernate.build.gradle.util;
/**
* TODO : javadoc

View File

@ -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;

View 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();
}

View File

@ -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 ];
}
}

View 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,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
}
}

View File

@ -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 );
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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 ) );
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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
View 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

View File

@ -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 )

View File

@ -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 {

View File

@ -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' ) )