Project

General

Profile

Download (12 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
	/**
61
	 * {@inheritDoc}
62
	 */
63
	@Override
64
	public Connection getConnection() throws SQLException {
65
		if (this.connection == null){
66
		    this.connection = datasource.getConnection();
67
		}
68
		return this.connection;
69
	}
70

    
71
	@Override
72
	public Connection getConnection(String username, String password) throws SQLException {
73
		if (this.connection == null){
74
            this.connection = datasource.getConnection(username, password);
75
        }
76
		return connection;
77
	}
78

    
79
	@Override
80
	public PrintWriter getLogWriter() throws SQLException {
81
		return datasource.getLogWriter();
82
	}
83

    
84
	@Override
85
	public void setLogWriter(PrintWriter out) throws SQLException {
86
		datasource.setLogWriter(out);
87
	}
88

    
89
	@Override
90
	public void setLoginTimeout(int seconds) throws SQLException {
91
		datasource.setLoginTimeout(seconds);
92
	}
93

    
94
	@Override
95
	public int getLoginTimeout() throws SQLException {
96
		return datasource.getLoginTimeout();
97
	}
98

    
99
	@Override
100
	public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException {
101
		return datasource.getParentLogger();
102
	}
103

    
104
	@Override
105
	public <T> T unwrap(Class<T> iface) throws SQLException {
106
		return datasource.unwrap(iface);
107
	}
108

    
109
	@Override
110
	public boolean isWrapperFor(Class<?> iface) throws SQLException {
111
		return datasource.isWrapperFor(iface);
112
	}
113

    
114
	@Override
115
	public String getName() {
116
		throw new UnsupportedOperationException("getName() not supported by WrappedCdmDataSource");
117
	}
118

    
119
	@Override
120
	public void setName(String name) {
121
		throw new UnsupportedOperationException("setName(String) not supported by WrappedCdmDataSource");
122
	}
123

    
124
	@Override
125
	public String getServer() {
126
		//TODO we may want to use client info from connection here
127
		throw new UnsupportedOperationException("getServer() not supported by WrappedCdmDataSource");
128
	}
129

    
130
	@Override
131
	public void setServer(String server) {
132
		throw new UnsupportedOperationException("setServer() not supported by WrappedCdmDataSource");
133
	}
134

    
135
	@Override
136
	public int getPort() {
137
		//TODO we may want to use client info from connection here
138
		throw new UnsupportedOperationException("getPort() not supported by WrappedCdmDataSource");
139
	}
140

    
141
	@Override
142
	public void setPort(int port) {
143
		throw new UnsupportedOperationException("setPort(int) not supported by WrappedCdmDataSource");
144
	}
145

    
146
	@Override
147
	public String getDbSchemaVersion() throws CdmSourceException {
148
		try {
149
			return (String)getSingleValue(CdmMetaDataPropertyName.DB_SCHEMA_VERSION.getSqlQuery());
150
		} catch (SQLException e1) {
151
		    try {
152
	            return (String)getSingleValue(CdmMetaDataPropertyName.DB_SCHEMA_VERSION.getSqlQueryOld());
153
	        } catch (SQLException e) {
154
	            throw new CdmSourceException(e.getMessage());
155
	        }
156
		}
157
	}
158

    
159

    
160
	@Override
161
	public boolean isDbEmpty() throws CdmSourceException {
162
		// Any CDM DB should have a schema version
163
		String dbSchemaVersion = getDbSchemaVersion();
164
		return (dbSchemaVersion == null || dbSchemaVersion.equals(""));
165
	}
166

    
167
	@Override
168
	public boolean checkConnection() throws CdmSourceException {
169
		try {
170
			return testConnection();
171
		} catch (ClassNotFoundException e) {
172
			throw new CdmSourceException(e.getMessage());
173
		} catch (SQLException e) {
174
			throw new CdmSourceException(e.getMessage());
175
		}
176
	}
177

    
178
	@Override
179
	public String getConnectionMessage() {
180
		try {
181
			Connection connection = getConnection();
182
			String message = "Connecting to datasource " + connection.getSchema() + ".";
183
			return message;
184
		} catch (SQLException e) {
185
			throw new RuntimeException(e);
186
		}
187
	}
188

    
189
	@Override
190
	public void closeOpenConnections() {
191
	    try {
192
	    	if(connection != null && !connection.isClosed()){
193
                connection.close();
194
                connection = null;
195
            }
196
        } catch (SQLException e) {
197
        	logger.error("Error closing the connection");
198
        }
199
	}
200

    
201
	@Override
202
	public Map<CdmMetaDataPropertyName, String> getMetaDataMap() throws CdmSourceException {
203
		//TODO is it possible/required to build a meta data map here?
204
		throw new UnsupportedOperationException("getMetaDataMap() not supported by WrappedCdmDataSource");
205
	}
206

    
207
	@Override
208
	public BeanDefinition getDatasourceBean() {
209
		//TODO is it possible/required to build a datasource bean here?
210
		throw new UnsupportedOperationException("getDatasourceBean() not supported by WrappedCdmDataSource");
211
	}
212

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

    
219
	@Override
220
	@Deprecated
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
    /**
229
     * {@inheritDoc}
230
     */
231
    @Override
232
    public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll,
233
            HibernateConfiguration hibernateConfig) {
234
        //TODO is it possible/required to build a properties bean here?
235
        throw new UnsupportedOperationException("getHibernatePropertiesBean() not supported by WrappedCdmDataSource");
236
    }
237

    
238
	@Override
239
	public String getFilePath() {
240
		throw new UnsupportedOperationException("getFilePath() not supported by WrappedCdmDataSource");
241
	}
242

    
243
	@Override
244
	public H2Mode getMode() {
245
		throw new UnsupportedOperationException("getMode() not supported by WrappedCdmDataSource");
246
	}
247

    
248
	@Override
249
	public String getUsername() {
250
		//TODO maybe this can be implemented by connection meta data
251
		throw new UnsupportedOperationException("getUsername() not supported by WrappedCdmDataSource");
252
	}
253

    
254
	@Override
255
	public String getPassword() {
256
		throw new UnsupportedOperationException("getPassword() not supported by WrappedCdmDataSource");
257
	}
258

    
259
	@Override
260
	public String getDatabase() {
261
	    if(datasource instanceof ComboPooledDataSource) {
262
	      String jdbcUrl = ((ComboPooledDataSource)datasource).getJdbcUrl();
263
	        try {
264
                return getDatabaseFrom(jdbcUrl);
265
            } catch (URISyntaxException e) {
266
                throw new RuntimeException(e);
267
            }
268
	    } else {
269
	        throw new UnsupportedOperationException("getDatabase() not implemented for " + datasource.getClass() + " in WrappedCdmDataSource");
270
	    }
271
	}
272

    
273
    /**
274
     * @param dbType
275
     * @param jdbcUrl
276
     * @return
277
     * @throws URISyntaxException
278
     */
279
    private String getDatabaseFrom(String jdbcUrl) throws URISyntaxException {
280
        DatabaseTypeEnum type = DatabaseTypeEnum.byConnectionString(jdbcUrl);
281
        if (type == null){
282
            return null;
283
        }else{
284
            String dbName = type.getDatabaseType().getDatabaseNameByConnectionString(jdbcUrl);
285
            return dbName;
286
        }
287
    }
288

    
289
	@Override
290
	public void setMode(H2Mode h2Mode) {
291
		throw new UnsupportedOperationException("setMode(H2Mode) not supported by WrappedCdmDataSource");
292
	}
293

    
294
	@Override
295
	public void setUsername(String username) {
296
		throw new UnsupportedOperationException("setUsername(String) not supported by WrappedCdmDataSource");
297
	}
298

    
299
	@Override
300
	public void setPassword(String password) {
301
		throw new UnsupportedOperationException("setPassword(String) not supported by WrappedCdmDataSource");
302
	}
303

    
304
	@Override
305
	public void setDatabase(String database) {
306
		throw new UnsupportedOperationException("setDatabase(String) not supported by WrappedCdmDataSource");
307
	}
308

    
309
	@Override
310
	public DatabaseTypeEnum getDatabaseType() {
311
	    if (this.datasource instanceof ICdmDataSource){
312
	        return ((ICdmDataSource)this.datasource).getDatabaseType();
313
	    }
314

    
315
	    try {
316
            getConnection();
317
        } catch (SQLException e1) {
318
            throw new RuntimeException("SQL Exception while trying to establish connection to datasource");
319
        }
320

    
321
	    String driverName = null;
322
        if (connection != null){
323
            DatabaseMetaData metaData = null;
324
            try {
325
                metaData = connection.getMetaData();
326
            } catch (SQLException e) {
327
                throw new RuntimeException("SQL Exception while trying to read datasource metadata");
328
            }
329

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

    
343
        }
344
		throw new IllegalStateException("datasource type (MySQL, SQL Server, ...) could not be retrieved from generic datasource");
345
	}
346

    
347
	@Override
348
	public boolean testConnection() throws ClassNotFoundException, SQLException {
349
		return getConnection() != null;
350
	}
351

    
352
	@Override
353
	public ResultSet executeQuery(String query) throws SQLException {
354
		PreparedStatement a = getConnection().prepareStatement(query);
355
		return a.executeQuery();
356
	}
357

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

    
364
	@Override
365
	public void startTransaction() {
366
		try {
367
            Connection connection = getConnection();
368
            this.connection = connection;
369
            connection.setAutoCommit(false);
370
		} catch (SQLException e) {
371
			throw new RuntimeException(e);
372
		}
373
	}
374

    
375
	@Override
376
	public void commitTransaction() throws SQLException {
377
		getConnection().commit();
378
	}
379

    
380
	@Override
381
	public void rollback() throws SQLException {
382
		getConnection().rollback();
383
	}
384

    
385
	@Override
386
	public Object getSingleValue(String query) throws SQLException {
387
		ResultSet rs = this.executeQuery(query);
388
		if (rs.next()){
389
			int count = rs.getMetaData().getColumnCount();
390
			if (count > 0){
391
				return rs.getObject(1);
392
			}
393
		}
394
		return null;
395
	}
396

    
397
	@Override
398
	public DatabaseMetaData getMetaData() {
399
		try {
400
			return getConnection().getMetaData();
401
		} catch (SQLException e) {
402
			throw new RuntimeException(e);
403
		}
404
	}
405

    
406
}
(20-20/20)