View Javadoc
1   package com.atlassian.activeobjects.internal;
2   
3   import com.atlassian.activeobjects.spi.DatabaseType;
4   import net.java.ao.DatabaseProvider;
5   import net.java.ao.Disposable;
6   import net.java.ao.DisposableDataSource;
7   import net.java.ao.builder.DelegatingDisposableDataSourceHandler;
8   import net.java.ao.db.ClientDerbyDatabaseProvider;
9   import net.java.ao.db.EmbeddedDerbyDatabaseProvider;
10  import net.java.ao.db.H2DatabaseProvider;
11  import net.java.ao.db.HSQLDatabaseProvider;
12  import net.java.ao.db.MsJdbcSQLServerDatabaseProvider;
13  import net.java.ao.db.MySQLDatabaseProvider;
14  import net.java.ao.db.NuoDBDatabaseProvider;
15  import net.java.ao.db.NuoDBDisposableDataSourceHandler;
16  import net.java.ao.db.OracleDatabaseProvider;
17  import net.java.ao.db.PostgreSQLDatabaseProvider;
18  import net.java.ao.db.SQLServerDatabaseProvider;
19  
20  import javax.sql.DataSource;
21  
22  import static com.atlassian.activeobjects.ao.ConverterUtils.toLowerCase;
23  import static com.google.common.base.Preconditions.checkNotNull;
24  
25  public final class JdbcDriverDatabaseProviderFactory implements DatabaseProviderFactory {
26      private final DriverNameExtractor driverNameExtractor;
27  
28      public JdbcDriverDatabaseProviderFactory(DriverNameExtractor driverNameExtractor) {
29          this.driverNameExtractor = checkNotNull(driverNameExtractor);
30      }
31  
32      public DatabaseProvider getDatabaseProvider(DataSource dataSource, DatabaseType databaseType, String schema) {
33          final String driverName = getDriverName(dataSource);
34          for (DatabaseProviderFactoryEnum dbProviderFactory : DatabaseProviderFactoryEnum.values()) {
35              if (dbProviderFactory.accept(databaseType, driverName)) {
36                  return dbProviderFactory.getDatabaseProvider(dataSource, schema);
37              }
38          }
39          throw new DatabaseProviderNotFoundException(driverName);
40      }
41  
42      private String getDriverName(DataSource dataSource) {
43          return driverNameExtractor.getDriverName(dataSource);
44      }
45  
46      /**
47       * TODO fix, this is actually not tested and needs to be. This is possibly quite fragile as well, as I don't know
48       * yet what happens to the driver name when using connection pooling, but I'd bet it changes to something that doesn't
49       * give much information
50       */
51      private static enum DatabaseProviderFactoryEnum {
52          MYSQL(DatabaseType.MYSQL, "mysql", false) {
53              @Override
54              public DatabaseProvider getDatabaseProvider(DataSource dataSource, String schema) {
55                  return new MySQLDatabaseProvider(getDisposableDataSource(dataSource));
56              }
57          },
58          DERBY_NETWORK(DatabaseType.DERBY_NETWORK, "derby", false) {
59              @Override
60              public DatabaseProvider getDatabaseProvider(DataSource dataSource, String schema) {
61                  return new ClientDerbyDatabaseProvider(getDisposableDataSource(dataSource));
62              }
63          },
64          DERBY_EMBEDDED(DatabaseType.DERBY_EMBEDDED, "derby", false) {
65              @Override
66              public DatabaseProvider getDatabaseProvider(DataSource dataSource, String schema) {
67                  return new EmbeddedDerbyDatabaseProvider(getDisposableDataSource(dataSource), "a-fake-uri"); // TODO handle the URI issue
68              }
69          },
70          ORACLE(DatabaseType.ORACLE, "oracle", false) {
71              @Override
72              public DatabaseProvider getDatabaseProvider(DataSource dataSource, String schema) {
73                  return new OracleDatabaseProvider(getDisposableDataSource(dataSource), schema);
74              }
75          },
76          POSTGRESQL(DatabaseType.POSTGRESQL, "postgres", false) {
77              @Override
78              public DatabaseProvider getDatabaseProvider(DataSource dataSource, String schema) {
79                  return new PostgreSQLDatabaseProvider(getDisposableDataSource(dataSource), schema);
80              }
81          },
82          MSSQL(DatabaseType.MS_SQL, "microsoft", true) {
83              @Override
84              public DatabaseProvider getDatabaseProvider(DataSource dataSource, String schema) {
85                  return new MsJdbcSQLServerDatabaseProvider(getDisposableDataSource(dataSource), schema);
86              }
87          },
88          MSSQL_JTDS(DatabaseType.MS_SQL, "jtds", true) {
89              @Override
90              public DatabaseProvider getDatabaseProvider(DataSource dataSource, String schema) {
91                  return new SQLServerDatabaseProvider(getDisposableDataSource(dataSource), schema);
92              }
93          },
94          HSQLDB(DatabaseType.HSQL, "hsql", false) {
95              @Override
96              public DatabaseProvider getDatabaseProvider(DataSource dataSource, String schema) {
97                  return new HSQLDatabaseProvider(getDisposableDataSource(dataSource), schema);
98              }
99          },
100         H2(DatabaseType.H2, "h2", false) {
101             @Override
102             public DatabaseProvider getDatabaseProvider(DataSource dataSource, String schema) {
103                 return new H2DatabaseProvider(getDisposableDataSource(dataSource), schema);
104             }
105         },
106         NUODB(DatabaseType.NUODB, "nuodb", false) {
107             @Override
108             public DatabaseProvider getDatabaseProvider(DataSource dataSource, String schema) {
109                 return new NuoDBDatabaseProvider(NuoDBDisposableDataSourceHandler.newInstance(dataSource), schema);
110             }
111         };
112 
113         private final DatabaseType databaseType;
114         private final String driverName;
115         private final boolean needsDatabaseTypeAndDriverName;
116 
117         DatabaseProviderFactoryEnum(DatabaseType databaseType, String driverName, boolean needsDatabaseTypeAndDriverName) {
118             this.databaseType = checkNotNull(databaseType);
119             this.driverName = checkNotNull(driverName);
120             this.needsDatabaseTypeAndDriverName = needsDatabaseTypeAndDriverName;
121         }
122 
123         boolean accept(DatabaseType otherDatabaseType, String otherDriverName) {
124             final boolean acceptDatabaseType = acceptDatabaseType(otherDatabaseType);
125             final boolean acceptDriverName = acceptDriverName(otherDriverName);
126             if (needsDatabaseTypeAndDriverName) {
127                 return acceptDatabaseType && acceptDriverName;
128             } else {
129                 return acceptDatabaseType || acceptDriverName;
130             }
131         }
132 
133         private boolean acceptDatabaseType(DatabaseType otherDatabaseType) {
134             return databaseType.equals(otherDatabaseType);
135         }
136 
137         private boolean acceptDriverName(String otherDriverName) {
138             return otherDriverName != null && toLowerCase(otherDriverName).contains(this.driverName);
139         }
140 
141         // apparently useless, I know, but the compiler complains if not there
142         public abstract DatabaseProvider getDatabaseProvider(DataSource dataSource, String schema);
143     }
144 
145     private static DisposableDataSource getDisposableDataSource(final DataSource dataSource) {
146         return DelegatingDisposableDataSourceHandler.newInstance(dataSource, new Disposable() {
147             @Override
148             public void dispose() {
149             }
150         });
151     }
152 }