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
106
107 @Override
108 public int getLoginTimeout() throws SQLException {
109 return 0;
110 }
111
112
113
114
115 @Override
116 public void setLoginTimeout(int timeout) throws SQLException {
117 throw new UnsupportedOperationException("setLoginTimeout");
118 }
119
120
121
122
123 @Override
124 public PrintWriter getLogWriter() {
125 throw new UnsupportedOperationException("getLogWriter");
126 }
127
128
129
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
147 public Logger getParentLogger() throws SQLFeatureNotSupportedException {
148 throw new SQLFeatureNotSupportedException();
149 }
150 }
151 }