Project

General

Profile

Download (12.1 KB) Statistics
| Branch: | Tag: | Revision:
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
import eu.etaxonomy.cdm.persistence.hibernate.HibernateConfiguration;
27

    
28
/**
29
 * This class is a wrapper class to wrap an {@link javax.sql.DataSource} to an
30
 * {@link ICdmDataSource}. As the former is a very limited interface it is not possible
31
 * to implement all methods of {@link ICdmDataSource}. However, the aim is
32
 * to implement all those methods which are usually needed to work with a datasource
33
 * which represents a connection to a database such as transaction handling and
34
 * sending queries.
35
 * Those methods which are not supported by this wrapper class will throw an xxx
36
 * exception.
37
 *
38
 *
39
 * @author a.mueller
40
 */
41

    
42
//FIXME this class replicates lots of code in CdmDataSourceBase, we may want to merge it
43
//in a common helper class to avoid redundant code
44
public class WrappedCdmDataSource implements ICdmDataSource {
45
	private static final Logger logger = Logger.getLogger(WrappedCdmDataSource.class);
46

    
47

    
48
	private final DataSource datasource;
49

    
50
	private Connection connection;
51

    
52

    
53
	public WrappedCdmDataSource(DataSource datasource) {
54
		if (datasource == null){
55
			throw new NullPointerException("datasource must not be null for WrappedCdmDataSource");
56
		}
57
		this.datasource = datasource;
58
	}
59

    
60
	@Override
61
	public Connection getConnection() throws SQLException {
62
		Connection existingConnection = getExistingConnection();
63
		if (existingConnection != null){
64
			return existingConnection;
65
		}else{
66
			return datasource.getConnection();
67
		}
68
	}
69

    
70
	public Connection getExistingConnection(){
71
		return this.connection;
72
	}
73

    
74

    
75
	@Override
76
	public Connection getConnection(String username, String password) throws SQLException {
77
		Connection existingConnection = getExistingConnection();
78
		if (existingConnection != null){
79
			return existingConnection;
80
		}else{
81
			return datasource.getConnection(username, password);
82
		}
83
	}
84

    
85
	@Override
86
	public PrintWriter getLogWriter() throws SQLException {
87
		return datasource.getLogWriter();
88
	}
89

    
90
	@Override
91
	public void setLogWriter(PrintWriter out) throws SQLException {
92
		datasource.setLogWriter(out);
93
	}
94

    
95
	@Override
96
	public void setLoginTimeout(int seconds) throws SQLException {
97
		datasource.setLoginTimeout(seconds);
98
	}
99

    
100
	@Override
101
	public int getLoginTimeout() throws SQLException {
102
		return datasource.getLoginTimeout();
103
	}
104

    
105
	@Override
106
	public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException {
107
		return datasource.getParentLogger();
108
	}
109

    
110
	@Override
111
	public <T> T unwrap(Class<T> iface) throws SQLException {
112
		return datasource.unwrap(iface);
113
	}
114

    
115
	@Override
116
	public boolean isWrapperFor(Class<?> iface) throws SQLException {
117
		return datasource.isWrapperFor(iface);
118
	}
119

    
120
	@Override
121
	public String getName() {
122
		throw new UnsupportedOperationException("getName() not supported by WrappedCdmDataSource");
123
	}
124

    
125
	@Override
126
	public void setName(String name) {
127
		throw new UnsupportedOperationException("setName(String) not supported by WrappedCdmDataSource");
128
	}
129

    
130
	@Override
131
	public String getServer() {
132
		//TODO we may want to use client info from connection here
133
		throw new UnsupportedOperationException("getServer() not supported by WrappedCdmDataSource");
134
	}
135

    
136
	@Override
137
	public void setServer(String server) {
138
		throw new UnsupportedOperationException("setServer() not supported by WrappedCdmDataSource");
139
	}
140

    
141
	@Override
142
	public int getPort() {
143
		//TODO we may want to use client info from connection here
144
		throw new UnsupportedOperationException("getPort() not supported by WrappedCdmDataSource");
145
	}
146

    
147
	@Override
148
	public void setPort(int port) {
149
		throw new UnsupportedOperationException("setPort(int) not supported by WrappedCdmDataSource");
150
	}
151

    
152
	@Override
153
	public String getDbSchemaVersion() throws CdmSourceException {
154
		try {
155
			return (String)getSingleValue(CdmMetaDataPropertyName.DB_SCHEMA_VERSION.getSqlQuery());
156
		} catch (SQLException e1) {
157
		    try {
158
	            return (String)getSingleValue(CdmMetaDataPropertyName.DB_SCHEMA_VERSION.getSqlQueryOld());
159
	        } catch (SQLException e) {
160
	            throw new CdmSourceException(e.getMessage());
161
	        }
162
		}
163
	}
164

    
165

    
166
	@Override
167
	public boolean isDbEmpty() throws CdmSourceException {
168
		// Any CDM DB should have a schema version
169
		String dbSchemaVersion = getDbSchemaVersion();
170
		return (dbSchemaVersion == null || dbSchemaVersion.equals(""));
171
	}
172

    
173
	@Override
174
	public boolean checkConnection() throws CdmSourceException {
175
		try {
176
			return testConnection();
177
		} catch (ClassNotFoundException e) {
178
			throw new CdmSourceException(e.getMessage());
179
		} catch (SQLException e) {
180
			throw new CdmSourceException(e.getMessage());
181
		}
182
	}
183

    
184
	@Override
185
	public String getConnectionMessage() {
186
		try {
187
			Connection connection = getConnection();
188
			String message = "Connecting to datasource " + connection.getSchema() + ".";
189
			return message;
190
		} catch (SQLException e) {
191
			throw new RuntimeException(e);
192
		}
193
	}
194

    
195
	@Override
196
	public void closeOpenConnections() {
197
	    try {
198
	    	if(connection != null && !connection.isClosed()){
199
                connection.close();
200
                connection = null;
201
            }
202
        } catch (SQLException e) {
203
        	logger.error("Error closing the connection");
204
        }
205
	}
206

    
207
	@Override
208
	public Map<CdmMetaDataPropertyName, String> getMetaDataMap() throws CdmSourceException {
209
		//TODO is it possible/required to build a meta data map here?
210
		throw new UnsupportedOperationException("getMetaDataMap() not supported by WrappedCdmDataSource");
211
	}
212

    
213
	@Override
214
	public BeanDefinition getDatasourceBean() {
215
		//TODO is it possible/required to build a datasource bean here?
216
		throw new UnsupportedOperationException("getDatasourceBean() not supported by WrappedCdmDataSource");
217
	}
218

    
219
	@Override
220
	public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll) {
221
		//TODO is it possible/required to build a properties bean here?
222
		throw new UnsupportedOperationException("getHibernatePropertiesBean() not supported by WrappedCdmDataSource");
223
	}
224

    
225
	@Override
226
	@Deprecated
227
	public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll,
228
			Boolean showSql, Boolean formatSql, Boolean registerSearchListener,
229
			Class<? extends RegionFactory> cacheProviderClass) {
230
		//TODO is it possible/required to build a properties bean here?
231
		throw new UnsupportedOperationException("getHibernatePropertiesBean() not supported by WrappedCdmDataSource");
232
	}
233

    
234
    /**
235
     * {@inheritDoc}
236
     */
237
    @Override
238
    public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll,
239
            HibernateConfiguration hibernateConfig) {
240
        //TODO is it possible/required to build a properties bean here?
241
        throw new UnsupportedOperationException("getHibernatePropertiesBean() not supported by WrappedCdmDataSource");
242
    }
243

    
244
	@Override
245
	public String getFilePath() {
246
		throw new UnsupportedOperationException("getFilePath() not supported by WrappedCdmDataSource");
247
	}
248

    
249
	@Override
250
	public H2Mode getMode() {
251
		throw new UnsupportedOperationException("getMode() not supported by WrappedCdmDataSource");
252
	}
253

    
254
	@Override
255
	public String getUsername() {
256
		//TODO maybe this can be implemented by connection meta data
257
		throw new UnsupportedOperationException("getUsername() not supported by WrappedCdmDataSource");
258
	}
259

    
260
	@Override
261
	public String getPassword() {
262
		throw new UnsupportedOperationException("getPassword() not supported by WrappedCdmDataSource");
263
	}
264

    
265
	@Override
266
	public String getDatabase() {
267
	    if(datasource instanceof ComboPooledDataSource) {
268
	      String jdbcUrl = ((ComboPooledDataSource)datasource).getJdbcUrl();
269
	        try {
270
                return getDatabaseFrom(jdbcUrl);
271
            } catch (URISyntaxException e) {
272
                throw new RuntimeException(e);
273
            }
274
	    } else {
275
	        throw new UnsupportedOperationException("getDatabase() not implemented for " + datasource.getClass() + " in WrappedCdmDataSource");
276
	    }
277
	}
278

    
279
    /**
280
     * @param dbType
281
     * @param jdbcUrl
282
     * @return
283
     * @throws URISyntaxException
284
     */
285
    private String getDatabaseFrom(String jdbcUrl) throws URISyntaxException {
286
        DatabaseTypeEnum type = DatabaseTypeEnum.byConnectionString(jdbcUrl);
287
        if (type == null){
288
            return null;
289
        }else{
290
            String dbName = type.getDatabaseType().getDatabaseNameByConnectionString(jdbcUrl);
291
            return dbName;
292
        }
293
    }
294

    
295
	@Override
296
	public void setMode(H2Mode h2Mode) {
297
		throw new UnsupportedOperationException("setMode(H2Mode) not supported by WrappedCdmDataSource");
298
	}
299

    
300
	@Override
301
	public void setUsername(String username) {
302
		throw new UnsupportedOperationException("setUsername(String) not supported by WrappedCdmDataSource");
303
	}
304

    
305
	@Override
306
	public void setPassword(String password) {
307
		throw new UnsupportedOperationException("setPassword(String) not supported by WrappedCdmDataSource");
308
	}
309

    
310
	@Override
311
	public void setDatabase(String database) {
312
		throw new UnsupportedOperationException("setDatabase(String) not supported by WrappedCdmDataSource");
313
	}
314

    
315
	@Override
316
	public DatabaseTypeEnum getDatabaseType() {
317
	    if (this.datasource instanceof ICdmDataSource){
318
	        return ((ICdmDataSource)this.datasource).getDatabaseType();
319
	    }
320

    
321
	    try {
322
            getConnection();
323
        } catch (SQLException e1) {
324
            throw new RuntimeException("SQL Exception while trying to establish connection to datasource");
325
        }
326

    
327
	    String driverName = null;
328
        if (connection != null){
329
            DatabaseMetaData metaData = null;
330
            try {
331
                metaData = connection.getMetaData();
332
            } catch (SQLException e) {
333
                throw new RuntimeException("SQL Exception while trying to read datasource metadata");
334
            }
335

    
336
            try {
337
                driverName = metaData != null ? metaData.getDriverName() : null;
338
            } catch (SQLException e) {
339
                //throw exception at end
340
            }
341
            if (metaData != null){
342
                DatabaseTypeEnum type = DatabaseTypeEnum.byDatabaseMetaData(metaData);
343
                if (type != null){
344
                    return type;
345
                }
346
            }
347
            throw new IllegalStateException("datasource type (MySQL, SQL Server, ...) could not be retrieved from generic datasource");
348

    
349
        }
350
		throw new IllegalStateException("datasource type (MySQL, SQL Server, ...) could not be retrieved from generic datasource");
351
	}
352

    
353
	@Override
354
	public boolean testConnection() throws ClassNotFoundException, SQLException {
355
		return getConnection() != null;
356
	}
357

    
358
	@Override
359
	public ResultSet executeQuery(String query) throws SQLException {
360
		PreparedStatement a = getConnection().prepareStatement(query);
361
		return a.executeQuery();
362
	}
363

    
364
	@Override
365
	public int executeUpdate(String sqlUpdate) throws SQLException {
366
		PreparedStatement a = getConnection().prepareStatement(sqlUpdate);
367
		return a.executeUpdate();
368
	}
369

    
370
	@Override
371
	public void startTransaction() {
372
		try {
373
            Connection connection = getConnection();
374
            this.connection = connection;
375
            connection.setAutoCommit(false);
376
		} catch (SQLException e) {
377
			throw new RuntimeException(e);
378
		}
379
	}
380

    
381
	@Override
382
	public void commitTransaction() throws SQLException {
383
		getConnection().commit();
384
	}
385

    
386
	@Override
387
	public void rollback() throws SQLException {
388
		getConnection().rollback();
389
	}
390

    
391
	@Override
392
	public Object getSingleValue(String query) throws SQLException {
393
		ResultSet rs = this.executeQuery(query);
394
		if (rs.next()){
395
			int count = rs.getMetaData().getColumnCount();
396
			if (count > 0){
397
				return rs.getObject(1);
398
			}
399
		}
400
		return null;
401
	}
402

    
403
	@Override
404
	public DatabaseMetaData getMetaData() {
405
		try {
406
			return getConnection().getMetaData();
407
		} catch (SQLException e) {
408
			throw new RuntimeException(e);
409
		}
410
	}
411

    
412
}
(20-20/20)