fix #6535 change CdmMetaData.propertyName from int to string
[cdmlib.git] / cdmlib-persistence / src / main / java / eu / etaxonomy / cdm / database / WrappedCdmDataSource.java
1 /**
2 *
3 */
4 package eu.etaxonomy.cdm.database;
5
6 import java.io.PrintWriter;
7 import java.net.URISyntaxException;
8 import java.sql.Connection;
9 import java.sql.DatabaseMetaData;
10 import java.sql.PreparedStatement;
11 import java.sql.ResultSet;
12 import java.sql.SQLException;
13 import java.sql.SQLFeatureNotSupportedException;
14 import java.util.Map;
15
16 import javax.sql.DataSource;
17
18 import org.apache.log4j.Logger;
19 import org.hibernate.cache.spi.RegionFactory;
20 import org.springframework.beans.factory.config.BeanDefinition;
21
22 import com.mchange.v2.c3p0.ComboPooledDataSource;
23
24 import eu.etaxonomy.cdm.config.CdmSourceException;
25 import eu.etaxonomy.cdm.model.metadata.CdmMetaDataPropertyName;
26
27 /**
28 * This class is a wrapper class to wrap an {@link javax.sql.DataSource} to an
29 * {@link ICdmDataSource}. As the former is a very limited interface it is not possible
30 * to implement all methods of {@link ICdmDataSource}. However, the aim is
31 * to implement all those methods which are usually needed to work with a datasource
32 * which represents a connection to a database such as transaction handling and
33 * sending queries.
34 * Those methods which are not supported by this wrapper class will throw an xxx
35 * exception.
36 *
37 *
38 * @author a.mueller
39 */
40
41 //FIXME this class replicates lots of code in CdmDataSourceBase, we may want to merge it
42 //in a common helper class to avoid redundant code
43 public class WrappedCdmDataSource implements ICdmDataSource {
44 private static final Logger logger = Logger.getLogger(WrappedCdmDataSource.class);
45
46
47 private final DataSource datasource;
48
49 private Connection connection;
50
51
52 public WrappedCdmDataSource(DataSource datasource) {
53 if (datasource == null){
54 throw new NullPointerException("datasource must not be null for WrappedCdmDataSource");
55 }
56 this.datasource = datasource;
57 }
58
59 @Override
60 public Connection getConnection() throws SQLException {
61 Connection existingConnection = getExistingConnection();
62 if (existingConnection != null){
63 return existingConnection;
64 }else{
65 return datasource.getConnection();
66 }
67 }
68
69 public Connection getExistingConnection(){
70 return this.connection;
71 }
72
73
74 @Override
75 public Connection getConnection(String username, String password) throws SQLException {
76 Connection existingConnection = getExistingConnection();
77 if (existingConnection != null){
78 return existingConnection;
79 }else{
80 return datasource.getConnection(username, password);
81 }
82 }
83
84 @Override
85 public PrintWriter getLogWriter() throws SQLException {
86 return datasource.getLogWriter();
87 }
88
89 @Override
90 public void setLogWriter(PrintWriter out) throws SQLException {
91 datasource.setLogWriter(out);
92 }
93
94 @Override
95 public void setLoginTimeout(int seconds) throws SQLException {
96 datasource.setLoginTimeout(seconds);
97 }
98
99 @Override
100 public int getLoginTimeout() throws SQLException {
101 return datasource.getLoginTimeout();
102 }
103
104 @Override
105 public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException {
106 return datasource.getParentLogger();
107 }
108
109 @Override
110 public <T> T unwrap(Class<T> iface) throws SQLException {
111 return datasource.unwrap(iface);
112 }
113
114 @Override
115 public boolean isWrapperFor(Class<?> iface) throws SQLException {
116 return datasource.isWrapperFor(iface);
117 }
118
119 @Override
120 public String getName() {
121 throw new UnsupportedOperationException("getName() not supported by WrappedCdmDataSource");
122 }
123
124 @Override
125 public void setName(String name) {
126 throw new UnsupportedOperationException("setName(String) not supported by WrappedCdmDataSource");
127 }
128
129 @Override
130 public String getServer() {
131 //TODO we may want to use client info from connection here
132 throw new UnsupportedOperationException("getServer() not supported by WrappedCdmDataSource");
133 }
134
135 @Override
136 public void setServer(String server) {
137 throw new UnsupportedOperationException("setServer() not supported by WrappedCdmDataSource");
138 }
139
140 @Override
141 public int getPort() {
142 //TODO we may want to use client info from connection here
143 throw new UnsupportedOperationException("getPort() not supported by WrappedCdmDataSource");
144 }
145
146 @Override
147 public void setPort(int port) {
148 throw new UnsupportedOperationException("setPort(int) not supported by WrappedCdmDataSource");
149 }
150
151 @Override
152 public String getDbSchemaVersion() throws CdmSourceException {
153 try {
154 return (String)getSingleValue(CdmMetaDataPropertyName.DB_SCHEMA_VERSION.getSqlQuery());
155 } catch (SQLException e) {
156 throw new CdmSourceException(e.getMessage());
157 }
158 }
159
160
161 @Override
162 public boolean isDbEmpty() throws CdmSourceException {
163 // Any CDM DB should have a schema version
164 String dbSchemaVersion = getDbSchemaVersion();
165 return (dbSchemaVersion == null || dbSchemaVersion.equals(""));
166 }
167
168 @Override
169 public boolean checkConnection() throws CdmSourceException {
170 try {
171 return testConnection();
172 } catch (ClassNotFoundException e) {
173 throw new CdmSourceException(e.getMessage());
174 } catch (SQLException e) {
175 throw new CdmSourceException(e.getMessage());
176 }
177 }
178
179 @Override
180 public String getConnectionMessage() {
181 try {
182 Connection connection = getConnection();
183 String message = "Connecting to datasource " + connection.getSchema() + ".";
184 return message;
185 } catch (SQLException e) {
186 throw new RuntimeException(e);
187 }
188 }
189
190 @Override
191 public void closeOpenConnections() {
192 try {
193 if(connection != null && !connection.isClosed()){
194 connection.close();
195 connection = null;
196 }
197 } catch (SQLException e) {
198 logger.error("Error closing the connection");
199 }
200 }
201
202 @Override
203 public Map<CdmMetaDataPropertyName, String> getMetaDataMap() throws CdmSourceException {
204 //TODO is it possible/required to build a meta data map here?
205 throw new UnsupportedOperationException("getMetaDataMap() not supported by WrappedCdmDataSource");
206 }
207
208 @Override
209 public BeanDefinition getDatasourceBean() {
210 //TODO is it possible/required to build a datasource bean here?
211 throw new UnsupportedOperationException("getDatasourceBean() not supported by WrappedCdmDataSource");
212 }
213
214 @Override
215 public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll) {
216 //TODO is it possible/required to build a properties bean here?
217 throw new UnsupportedOperationException("getHibernatePropertiesBean() not supported by WrappedCdmDataSource");
218 }
219
220 @Override
221 public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll,
222 Boolean showSql, Boolean formatSql, Boolean registerSearchListener,
223 Class<? extends RegionFactory> cacheProviderClass) {
224 //TODO is it possible/required to build a properties bean here?
225 throw new UnsupportedOperationException("getHibernatePropertiesBean() not supported by WrappedCdmDataSource");
226 }
227
228 @Override
229 public String getFilePath() {
230 throw new UnsupportedOperationException("getFilePath() not supported by WrappedCdmDataSource");
231 }
232
233 @Override
234 public H2Mode getMode() {
235 throw new UnsupportedOperationException("getMode() not supported by WrappedCdmDataSource");
236 }
237
238 @Override
239 public String getUsername() {
240 //TODO maybe this can be implemented by connection meta data
241 throw new UnsupportedOperationException("getUsername() not supported by WrappedCdmDataSource");
242 }
243
244 @Override
245 public String getPassword() {
246 throw new UnsupportedOperationException("getPassword() not supported by WrappedCdmDataSource");
247 }
248
249 @Override
250 public String getDatabase() {
251 if(datasource instanceof ComboPooledDataSource) {
252 String jdbcUrl = ((ComboPooledDataSource)datasource).getJdbcUrl();
253 try {
254 return getDatabaseFrom(jdbcUrl);
255 } catch (URISyntaxException e) {
256 throw new RuntimeException(e);
257 }
258 } else {
259 throw new UnsupportedOperationException("getDatabase() not implemented for " + datasource.getClass() + " in WrappedCdmDataSource");
260 }
261 }
262
263 /**
264 * @param dbType
265 * @param jdbcUrl
266 * @return
267 * @throws URISyntaxException
268 */
269 private String getDatabaseFrom(String jdbcUrl) throws URISyntaxException {
270 DatabaseTypeEnum type = DatabaseTypeEnum.byConnectionString(jdbcUrl);
271 if (type == null){
272 return null;
273 }else{
274 String dbName = type.getDatabaseType().getDatabaseNameByConnectionString(jdbcUrl);
275 return dbName;
276 }
277 }
278
279 @Override
280 public void setMode(H2Mode h2Mode) {
281 throw new UnsupportedOperationException("setMode(H2Mode) not supported by WrappedCdmDataSource");
282 }
283
284 @Override
285 public void setUsername(String username) {
286 throw new UnsupportedOperationException("setUsername(String) not supported by WrappedCdmDataSource");
287 }
288
289 @Override
290 public void setPassword(String password) {
291 throw new UnsupportedOperationException("setPassword(String) not supported by WrappedCdmDataSource");
292 }
293
294 @Override
295 public void setDatabase(String database) {
296 throw new UnsupportedOperationException("setDatabase(String) not supported by WrappedCdmDataSource");
297 }
298
299 @Override
300 public DatabaseTypeEnum getDatabaseType() {
301 if (this.datasource instanceof ICdmDataSource){
302 return ((ICdmDataSource)this.datasource).getDatabaseType();
303 }
304
305 try {
306 getConnection();
307 } catch (SQLException e1) {
308 throw new RuntimeException("SQL Exception while trying to establish connection to datasource");
309 }
310
311 String driverName = null;
312 if (connection != null){
313 DatabaseMetaData metaData = null;
314 try {
315 metaData = connection.getMetaData();
316 } catch (SQLException e) {
317 throw new RuntimeException("SQL Exception while trying to read datasource metadata");
318 }
319
320 try {
321 driverName = metaData != null ? metaData.getDriverName() : null;
322 } catch (SQLException e) {
323 //throw exception at end
324 }
325 if (metaData != null){
326 DatabaseTypeEnum type = DatabaseTypeEnum.byDatabaseMetaData(metaData);
327 if (type != null){
328 return type;
329 }
330 }
331 throw new IllegalStateException("datasource type (MySQL, SQL Server, ...) could not be retrieved from generic datasource");
332
333 }
334 throw new IllegalStateException("datasource type (MySQL, SQL Server, ...) could not be retrieved from generic datasource");
335 }
336
337 @Override
338 public boolean testConnection() throws ClassNotFoundException, SQLException {
339 return getConnection() != null;
340 }
341
342 @Override
343 public ResultSet executeQuery(String query) throws SQLException {
344 PreparedStatement a = getConnection().prepareStatement(query);
345 return a.executeQuery();
346 }
347
348 @Override
349 public int executeUpdate(String sqlUpdate) throws SQLException {
350 PreparedStatement a = getConnection().prepareStatement(sqlUpdate);
351 return a.executeUpdate();
352 }
353
354 @Override
355 public void startTransaction() {
356 try {
357 Connection connection = getConnection();
358 this.connection = connection;
359 connection.setAutoCommit(false);
360 } catch (SQLException e) {
361 throw new RuntimeException(e);
362 }
363 }
364
365 @Override
366 public void commitTransaction() throws SQLException {
367 getConnection().commit();
368 }
369
370 @Override
371 public void rollback() throws SQLException {
372 getConnection().rollback();
373 }
374
375 @Override
376 public Object getSingleValue(String query) throws SQLException {
377 ResultSet rs = this.executeQuery(query);
378 if (rs.next()){
379 int count = rs.getMetaData().getColumnCount();
380 if (count > 0){
381 return rs.getObject(1);
382 }
383 }
384 return null;
385 }
386
387 @Override
388 public DatabaseMetaData getMetaData() {
389 try {
390 return getConnection().getMetaData();
391 } catch (SQLException e) {
392 throw new RuntimeException(e);
393 }
394 }
395 }