Coverage Report - liquibase.sqlgenerator.SqlGeneratorFactory
 
Classes in this File Line Coverage Branch Coverage Complexity
SqlGeneratorFactory
71%
55/77
65%
34/52
2.882
 
 1  
 package liquibase.sqlgenerator;
 2  
 
 3  
 import java.lang.reflect.ParameterizedType;
 4  
 import java.lang.reflect.Type;
 5  
 import java.lang.reflect.TypeVariable;
 6  
 import java.util.ArrayList;
 7  
 import java.util.Collection;
 8  
 import java.util.HashSet;
 9  
 import java.util.List;
 10  
 import java.util.Set;
 11  
 import java.util.SortedSet;
 12  
 import java.util.TreeSet;
 13  
 
 14  
 import liquibase.database.Database;
 15  
 import liquibase.database.structure.DatabaseObject;
 16  
 import liquibase.exception.ValidationErrors;
 17  
 import liquibase.exception.Warnings;
 18  
 import liquibase.servicelocator.ServiceLocator;
 19  
 import liquibase.sql.Sql;
 20  
 import liquibase.statement.SqlStatement;
 21  
 
 22  
 /**
 23  
  * SqlGeneratorFactory is a singleton registry of SqlGenerators. Use the register(SqlGenerator) method to add custom
 24  
  * SqlGenerators, and the getBestGenerator() method to retrieve the SqlGenerator that should be used for a given
 25  
  * SqlStatement.
 26  
  */
 27  
 public class SqlGeneratorFactory {
 28  
 
 29  
     private static SqlGeneratorFactory instance;
 30  
 
 31  10
     private List<SqlGenerator> generators = new ArrayList<SqlGenerator>();
 32  
 
 33  10
     private SqlGeneratorFactory() {
 34  
         Class[] classes;
 35  
         try {
 36  10
             classes = ServiceLocator.getInstance().findClasses(SqlGenerator.class);
 37  
 
 38  1010
             for (Class clazz : classes) {
 39  1000
                 register((SqlGenerator) clazz.getConstructor().newInstance());
 40  
             }
 41  
 
 42  0
         } catch (Exception e) {
 43  0
             throw new RuntimeException(e);
 44  10
         }
 45  
 
 46  10
     }
 47  
 
 48  
     /**
 49  
      * Return singleton SqlGeneratorFactory
 50  
      */
 51  
     public static SqlGeneratorFactory getInstance() {
 52  1834
         if (instance == null) {
 53  1
             instance = new SqlGeneratorFactory();
 54  
         }
 55  1834
         return instance;
 56  
     }
 57  
 
 58  
     public static void reset() {
 59  9
         instance = new SqlGeneratorFactory();
 60  9
     }
 61  
 
 62  
     public void register(SqlGenerator generator) {
 63  1010
         generators.add(generator);
 64  1010
     }
 65  
 
 66  
     public void unregister(SqlGenerator generator) {
 67  3
         generators.remove(generator);
 68  3
     }
 69  
 
 70  
     public void unregister(Class generatorClass) {
 71  2
         SqlGenerator toRemove = null;
 72  2
         for (SqlGenerator existingGenerator : generators) {
 73  6
             if (existingGenerator.getClass().equals(generatorClass)) {
 74  1
                 toRemove = existingGenerator;
 75  
             }
 76  
         }
 77  
 
 78  2
         unregister(toRemove);
 79  2
     }
 80  
 
 81  
     protected Collection<SqlGenerator> getGenerators() {
 82  1837
         return generators;
 83  
     }
 84  
 
 85  
     protected SortedSet<SqlGenerator> getGenerators(SqlStatement statement, Database database) {
 86  1820
         SortedSet<SqlGenerator> validGenerators = new TreeSet<SqlGenerator>(new SqlGeneratorComparator());
 87  
 
 88  1820
         for (SqlGenerator generator : getGenerators()) {
 89  182000
             Class clazz = generator.getClass();
 90  182000
             Type classType = null;
 91  791700
             while (clazz != null) {
 92  609700
                 if (classType instanceof ParameterizedType) {
 93  182000
                     checkType(classType, statement, generator, database, validGenerators);
 94  
                 }
 95  
 
 96  855400
                 for (Type type : clazz.getGenericInterfaces()) {
 97  245700
                     if (type instanceof ParameterizedType) {
 98  182000
                         checkType(type, statement, generator, database, validGenerators);
 99  63700
                     } else if (isTypeEqual(type, SqlGenerator.class)) {
 100  
                         // noinspection unchecked
 101  0
                         if (generator.supports(statement, database)) {
 102  0
                             validGenerators.add(generator);
 103  
                         }
 104  
                     }
 105  
                 }
 106  609700
                 classType = clazz.getGenericSuperclass();
 107  609700
                 clazz = clazz.getSuperclass();
 108  
             }
 109  182000
         }
 110  1820
         return validGenerators;
 111  
     }
 112  
 
 113  
     private boolean isTypeEqual(Type aType, Class aClass) {
 114  427700
         if (aType instanceof Class) {
 115  427700
             return ((Class) aType).getName().equals(aClass.getName());
 116  
         }
 117  0
         return aType.equals(aClass);
 118  
     }
 119  
 
 120  
     private void checkType(Type type, SqlStatement statement, SqlGenerator generator, Database database,
 121  
             SortedSet<SqlGenerator> validGenerators) {
 122  546000
         for (Type typeClass : ((ParameterizedType) type).getActualTypeArguments()) {
 123  364000
             if (typeClass instanceof TypeVariable) {
 124  182000
                 typeClass = ((TypeVariable) typeClass).getBounds()[0];
 125  
             }
 126  
 
 127  364000
             if (isTypeEqual(typeClass, SqlStatement.class)) {
 128  182000
                 return;
 129  
             }
 130  
 
 131  182000
             if (((Class) typeClass).isAssignableFrom(statement.getClass())) {
 132  2834
                 if (generator.supports(statement, database)) {
 133  1784
                     validGenerators.add(generator);
 134  
                 }
 135  
             }
 136  
         }
 137  
 
 138  182000
     }
 139  
 
 140  
     private SqlGeneratorChain createGeneratorChain(SqlStatement statement, Database database) {
 141  427
         SortedSet<SqlGenerator> sqlGenerators = getGenerators(statement, database);
 142  427
         if (sqlGenerators == null || sqlGenerators.size() == 0) {
 143  0
             return null;
 144  
         }
 145  
         // noinspection unchecked
 146  427
         return new SqlGeneratorChain(sqlGenerators);
 147  
     }
 148  
 
 149  
     public Sql[] generateSql(SqlStatement statement, Database database) {
 150  0
         SqlGeneratorChain generatorChain = createGeneratorChain(statement, database);
 151  0
         if (generatorChain == null) {
 152  0
             throw new IllegalStateException("Cannot find generators for database " + database.getClass()
 153  
                     + ", statement: " + statement);
 154  
         }
 155  0
         return generatorChain.generateSql(statement, database);
 156  
     }
 157  
 
 158  
     public boolean requiresCurrentDatabaseMetadata(SqlStatement statement, Database database) {
 159  0
         for (SqlGenerator generator : getGenerators(statement, database)) {
 160  0
             if (generator.requiresUpdatedDatabaseMetadata(database)) {
 161  0
                 return true;
 162  
             }
 163  
         }
 164  0
         return false;
 165  
     }
 166  
 
 167  
     public boolean supports(SqlStatement statement, Database database) {
 168  1392
         return getGenerators(statement, database).size() > 0;
 169  
     }
 170  
 
 171  
     public ValidationErrors validate(SqlStatement statement, Database database) {
 172  
         // noinspection unchecked
 173  423
         return createGeneratorChain(statement, database).validate(statement, database);
 174  
     }
 175  
 
 176  
     public Warnings warn(SqlStatement statement, Database database) {
 177  
         // noinspection unchecked
 178  4
         return createGeneratorChain(statement, database).warn(statement, database);
 179  
     }
 180  
 
 181  
     public Set<DatabaseObject> getAffectedDatabaseObjects(SqlStatement statement, Database database) {
 182  0
         Set<DatabaseObject> affectedObjects = new HashSet<DatabaseObject>();
 183  
 
 184  0
         SqlGeneratorChain sqlGeneratorChain = createGeneratorChain(statement, database);
 185  0
         if (sqlGeneratorChain != null) {
 186  
             // noinspection unchecked
 187  0
             Sql[] sqls = sqlGeneratorChain.generateSql(statement, database);
 188  0
             if (sqls != null) {
 189  0
                 for (Sql sql : sqls) {
 190  0
                     affectedObjects.addAll(sql.getAffectedDatabaseObjects());
 191  
                 }
 192  
             }
 193  
         }
 194  
 
 195  0
         return affectedObjects;
 196  
 
 197  
     }
 198  
 
 199  
 }