View Javadoc
1   package com.atlassian.activeobjects.jira;
2   
3   import com.atlassian.activeobjects.spi.AbstractTenantAwareDataSourceProvider;
4   import com.atlassian.activeobjects.spi.DatabaseType;
5   import com.atlassian.jira.ofbiz.OfBizConnectionFactory;
6   import com.atlassian.tenancy.api.Tenant;
7   import com.google.common.base.Supplier;
8   import com.google.common.collect.ImmutableMap;
9   import org.ofbiz.core.entity.jdbc.dbtype.DatabaseTypeFactory;
10  
11  import javax.annotation.Nonnull;
12  import javax.sql.DataSource;
13  import java.io.PrintWriter;
14  import java.sql.Connection;
15  import java.sql.SQLException;
16  import java.sql.SQLFeatureNotSupportedException;
17  import java.util.Map;
18  import java.util.logging.Logger;
19  
20  import static com.google.common.base.Preconditions.checkNotNull;
21  import static com.google.common.base.Suppliers.memoize;
22  
23  public final class JiraTenantAwareDataSourceProvider extends AbstractTenantAwareDataSourceProvider {
24      private static final Map<org.ofbiz.core.entity.jdbc.dbtype.DatabaseType, DatabaseType> DB_TYPE_TO_DB_TYPE = ImmutableMap.<org.ofbiz.core.entity.jdbc.dbtype.DatabaseType, DatabaseType>builder()
25              .put(DatabaseTypeFactory.DB2, DatabaseType.DB2)
26              .put(DatabaseTypeFactory.HSQL, DatabaseType.HSQL)
27              .put(DatabaseTypeFactory.MSSQL, DatabaseType.MS_SQL)
28              .put(DatabaseTypeFactory.MYSQL, DatabaseType.MYSQL)
29              .put(DatabaseTypeFactory.ORACLE_10G, DatabaseType.ORACLE)
30              .put(DatabaseTypeFactory.ORACLE_8I, DatabaseType.ORACLE)
31              .put(DatabaseTypeFactory.POSTGRES, DatabaseType.POSTGRESQL)
32              .put(DatabaseTypeFactory.POSTGRES_7_2, DatabaseType.POSTGRESQL)
33              .put(DatabaseTypeFactory.POSTGRES_7_3, DatabaseType.POSTGRESQL)
34              .build();
35  
36      private final OfBizConnectionFactory connectionFactory;
37      private final JiraDatabaseTypeExtractor databaseTypeExtractor;
38      private final DataSource ds;
39  
40      public JiraTenantAwareDataSourceProvider(OfBizConnectionFactory connectionFactory, JiraDatabaseTypeExtractor databaseTypeExtractor) {
41          this.connectionFactory = checkNotNull(connectionFactory);
42          this.databaseTypeExtractor = checkNotNull(databaseTypeExtractor);
43          this.ds = new OfBizDataSource(connectionFactory);
44      }
45  
46      @Nonnull
47      @Override
48      public DataSource getDataSource(@Nonnull final Tenant tenant) {
49          return ds;
50      }
51  
52      @Nonnull
53      @Override
54      public DatabaseType getDatabaseType(@Nonnull final Tenant tenant) {
55          return memoize(new Supplier<DatabaseType>() {
56              @Override
57              public DatabaseType get() {
58                  Connection connection = null;
59                  try {
60                      connection = ds.getConnection();
61                      final DatabaseType type = DB_TYPE_TO_DB_TYPE.get(databaseTypeExtractor.getDatabaseType(connection));
62                      return type != null ? type : DatabaseType.UNKNOWN;
63                  } catch (SQLException e) {
64                      throw new IllegalStateException("Could not get database type", e);
65                  } finally {
66                      closeQuietly(connection);
67                  }
68              }
69          }).get();
70      }
71  
72      @Override
73      public String getSchema(@Nonnull final Tenant tenant) {
74          return connectionFactory.getDatasourceInfo().getSchemaName();
75      }
76  
77      private static void closeQuietly(Connection connection) {
78          if (connection != null) {
79              try {
80                  connection.close();
81              } catch (SQLException e) {
82                  throw new IllegalStateException("There was an exception closing a database connection", e);
83              }
84          }
85      }
86  
87      private static class OfBizDataSource extends AbstractDataSource {
88          private final OfBizConnectionFactory connectionFactory;
89  
90          public OfBizDataSource(OfBizConnectionFactory connectionFactory) {
91              this.connectionFactory = checkNotNull(connectionFactory);
92          }
93  
94          public Connection getConnection() throws SQLException {
95              return connectionFactory.getConnection();
96          }
97  
98          public Connection getConnection(String username, String password) throws SQLException {
99              throw new IllegalStateException("Not allowed to get a connection for non default username/password");
100         }
101     }
102 
103     private static abstract class AbstractDataSource implements DataSource {
104         /**
105          * Returns 0, indicating to use the default system timeout.
106          */
107         @Override
108         public int getLoginTimeout() throws SQLException {
109             return 0;
110         }
111 
112         /**
113          * Setting a login timeout is not supported.
114          */
115         @Override
116         public void setLoginTimeout(int timeout) throws SQLException {
117             throw new UnsupportedOperationException("setLoginTimeout");
118         }
119 
120         /**
121          * LogWriter methods are not supported.
122          */
123         @Override
124         public PrintWriter getLogWriter() {
125             throw new UnsupportedOperationException("getLogWriter");
126         }
127 
128         /**
129          * LogWriter methods are not supported.
130          */
131         @Override
132         public void setLogWriter(PrintWriter pw) throws SQLException {
133             throw new UnsupportedOperationException("setLogWriter");
134         }
135 
136         @Override
137         public <T> T unwrap(Class<T> tClass) throws SQLException {
138             throw new UnsupportedOperationException("unwrap");
139         }
140 
141         @Override
142         public boolean isWrapperFor(Class<?> aClass) throws SQLException {
143             throw new UnsupportedOperationException("isWrapperFor");
144         }
145 
146         // @Override Java 7 only
147         public Logger getParentLogger() throws SQLFeatureNotSupportedException {
148             throw new SQLFeatureNotSupportedException();
149         }
150     }
151 }