Project

General

Profile

Download (18.4 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2007 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9

    
10
package eu.etaxonomy.cdm.database;
11

    
12
import static eu.etaxonomy.cdm.common.XmlHelp.getBeansRoot;
13
import static eu.etaxonomy.cdm.common.XmlHelp.insertXmlBean;
14
import static eu.etaxonomy.cdm.common.XmlHelp.insertXmlValueProperty;
15
import static eu.etaxonomy.cdm.common.XmlHelp.saveToXml;
16

    
17
import java.util.ArrayList;
18
import java.util.Enumeration;
19
import java.util.Iterator;
20
import java.util.List;
21
import java.util.Properties;
22

    
23
import javax.sql.DataSource;
24

    
25
import org.apache.log4j.Logger;
26
import org.hibernate.cache.internal.NoCachingRegionFactory;
27
import org.hibernate.cache.spi.RegionFactory;
28
import org.jdom.Attribute;
29
import org.jdom.Element;
30
import org.springframework.beans.MutablePropertyValues;
31
import org.springframework.beans.factory.config.BeanDefinition;
32
import org.springframework.beans.factory.config.PropertiesFactoryBean;
33
import org.springframework.beans.factory.support.AbstractBeanDefinition;
34
import org.springframework.beans.factory.support.RootBeanDefinition;
35

    
36
import com.mchange.v2.c3p0.ComboPooledDataSource;
37

    
38
import eu.etaxonomy.cdm.common.XmlHelp;
39
import eu.etaxonomy.cdm.config.CdmPersistentSourceUtils;
40
import eu.etaxonomy.cdm.config.CdmPersistentXMLSource;
41
import eu.etaxonomy.cdm.config.CdmPersistentXMLSource.CdmSourceProperties;
42
import eu.etaxonomy.cdm.config.ICdmPersistentSource;
43
import eu.etaxonomy.cdm.database.types.IDatabaseType;
44

    
45

    
46
/**
47
 * class to access an CdmDataSource
48
 */
49
public class CdmPersistentDataSource extends CdmDataSourceBase implements ICdmPersistentSource {
50
	private static final Logger logger = Logger.getLogger(CdmPersistentDataSource.class);
51

    
52
	public static final String DATASOURCE_BEAN_POSTFIX = "DataSource";
53

    
54

    
55
	private String beanName;
56

    
57
	private String database;
58

    
59
	/**
60
	 * This is strictly a <String, String> list of properties
61
	 */
62
	private Properties cdmSourceProperties;
63

    
64
	private List<Attribute> cdmSourceAttributes;
65

    
66

    
67
	/**
68
	 * The Datasource class that Spring will use to set up the connection to the database
69
	 */
70
	private static String dataSourceClassName = ComboPooledDataSource.class.getName();
71

    
72

    
73
	/**
74
	 * Returns the default CdmDataSource
75
	 * @return the default CdmDataSource
76
	 * @throws DataSourceNotFoundException
77
	 */
78
	public final static CdmPersistentDataSource NewDefaultInstance() throws DataSourceNotFoundException {
79
		return NewInstance("default");
80
	}
81

    
82

    
83
	/**
84
	 * Returns the default CdmDataSource
85
	 * @return the default CdmDataSource
86
	 * @throws DataSourceNotFoundException
87
	 */
88
	public final static CdmPersistentDataSource NewLocalHsqlInstance() throws DataSourceNotFoundException{
89
		return NewInstance("localDefaultHsql");
90
	}
91

    
92
	/**
93
	 * Returns the CdmDataSource named by strDataSource
94
	 * @param strDataSource
95
	 * @return
96
	 */
97
	public final static CdmPersistentDataSource NewInstance(String dataSourceName) throws DataSourceNotFoundException{
98
		if (exists(dataSourceName)){
99
			return new CdmPersistentDataSource(dataSourceName);
100
		}else{
101
			throw new DataSourceNotFoundException("Datasource not found: " + dataSourceName);
102
		}
103
	}
104

    
105
	/**
106
	 * Private Constructor. Use NewXXX factory methods for creating a new instance of CdmDataSource!
107
	 * @param strDataSource
108
	 */
109
	private CdmPersistentDataSource(String strDataSource){
110
		setName(strDataSource);
111
		loadSource(strDataSource);
112
	}
113

    
114
	private void loadSource(String strDataSource) {
115
		CdmPersistentXMLSource cdmPersistentXMLSource = CdmPersistentXMLSource.NewInstance(strDataSource, DATASOURCE_BEAN_POSTFIX);
116
		if(cdmPersistentXMLSource.getElement() != null) {
117
			beanName = cdmPersistentXMLSource.getBeanName();
118
			// properties from the persistent xml file
119
			cdmSourceProperties = cdmPersistentXMLSource.getCdmSourceProperties();
120
			cdmSourceAttributes = cdmPersistentXMLSource.getCdmSourceAttributes();
121

    
122
			// added database specific properties if they are null
123
			String url = getCdmSourceProperty(CdmSourceProperties.URL);
124
			DatabaseTypeEnum dbTypeEnum = getDatabaseType();
125
			if (dbTypeEnum != null && url != null){
126
				IDatabaseType dbType = dbTypeEnum.getDatabaseType();
127
				if (getCdmSourceProperty(CdmSourceProperties.DATABASE) == null){
128
					String database = dbType.getDatabaseNameByConnectionString(url);
129
					if(database != null) {
130
						setDatabase(database);
131
					}
132
				}
133
				if(getCdmSourceProperty(CdmSourceProperties.SERVER) == null){
134
					String server = dbType.getServerNameByConnectionString(url);
135
					if(server != null) {
136
						setServer(server);
137
					}
138
				}
139
				if(getCdmSourceProperty(CdmSourceProperties.PORT) == null){
140
					int port = dbType.getPortByConnectionString(url);
141
						if(port > 0) {
142
							setPort(port);
143
						} else {
144
							setPort(NULL_PORT);
145
						}
146
				}
147
			}
148
		}
149
	}
150

    
151
	@Override
152
    public String getBeanName() {
153
		return beanName;
154
	}
155

    
156
	@Override
157
	public String getDatabase() {
158
		return database;
159
	}
160

    
161

    
162
	@Override
163
	public void setDatabase(String database) {
164
		this.database = database;
165
		//update url string
166
		cdmSourceProperties.put(CdmSourceProperties.URL.toString(), getDatabaseType().getConnectionString(this));
167

    
168
	}
169

    
170
	@Override
171
	public void setServer(String server) {
172
		super.setServer(server);
173
		//update url string
174
		cdmSourceProperties.put(CdmSourceProperties.URL.toString(), getDatabaseType().getConnectionString(this));
175
	}
176

    
177
	@Override
178
	public void setPort(int port) {
179
		super.setPort(port);
180
		if(port != NULL_PORT) {
181
			//update url string
182
			cdmSourceProperties.put(CdmSourceProperties.URL.toString(), getDatabaseType().getConnectionString(this));
183
		}
184
	}
185
	@Override
186
	public String getFilePath() {
187
		return getCdmSourceProperty(CdmSourceProperties.FILEPATH);
188
	}
189

    
190

    
191
	@Override
192
	public H2Mode getMode() {
193
		return H2Mode.fromString(getCdmSourceProperty(CdmSourceProperties.MODE));
194
	}
195

    
196
	@Override
197
	public void setMode(H2Mode h2Mode) {
198
		cdmSourceProperties.put(CdmSourceProperties.MODE.toString(), h2Mode.name());
199

    
200
	}
201

    
202
	@Override
203
	public String getUsername(){
204
		return getCdmSourceProperty(CdmSourceProperties.USERNAME);
205
	}
206

    
207
	@Override
208
	public void setUsername(String username) {
209
		cdmSourceProperties.put(CdmSourceProperties.USERNAME.toString(), username);
210

    
211
	}
212

    
213
	@Override
214
	public String getPassword(){
215
		return getCdmSourceProperty(CdmSourceProperties.PASSWORD);
216
	}
217

    
218
	@Override
219
	public void setPassword(String password) {
220
		cdmSourceProperties.put(CdmSourceProperties.PASSWORD.toString(), password);
221

    
222
	}
223

    
224
	@Override
225
	public DatabaseTypeEnum getDatabaseType(){
226
		String strDriverClass = getCdmSourceProperty(CdmSourceProperties.DRIVER_CLASS);
227
		DatabaseTypeEnum dbType = DatabaseTypeEnum.byDriverClass(strDriverClass);
228
		return dbType;
229
	}
230

    
231

    
232
	public String getCdmSourceProperty(CdmSourceProperties property){
233
		return cdmSourceProperties.getProperty(property.toString(),null);
234
	}
235

    
236
	/**
237
	 * Returns a BeanDefinition object of type DataSource that contains
238
	 * datsource properties (url, username, password, ...)
239
	 * @return
240
	 */
241
	@SuppressWarnings("unchecked")
242
	@Override
243
	public BeanDefinition getDatasourceBean(){
244
		DatabaseTypeEnum dbtype =
245
				DatabaseTypeEnum.byDriverClass(getCdmSourceProperty(CdmSourceProperties.DRIVER_CLASS));
246

    
247
		AbstractBeanDefinition bd = new RootBeanDefinition(dbtype.getDataSourceClass());
248
		//attributes
249
		Iterator<Attribute> iterator = cdmSourceAttributes.iterator();
250
		while(iterator.hasNext()){
251
			Attribute attribute = iterator.next();
252
			if (attribute.getName().equals("lazy-init")){
253
				bd.setLazyInit(Boolean.valueOf(attribute.getValue()));
254
			}
255
			if (attribute.getName().equals("init-method")){
256
				bd.setInitMethodName(attribute.getValue());
257
			}
258
			if (attribute.getName().equals("destroy-method")){
259
				bd.setDestroyMethodName(attribute.getValue());
260
			}
261
			//Attribute attribute = iterator.next();
262
			//bd.setAttribute(attribute.getName(), attribute.getValue());
263
		}
264

    
265
		//properties
266
		MutablePropertyValues props = new MutablePropertyValues();
267

    
268
		Enumeration<String> keys = (Enumeration)cdmSourceProperties.keys();
269
		while (keys.hasMoreElements()){
270
			String key = keys.nextElement();
271

    
272
			props.addPropertyValue(key, cdmSourceProperties.getProperty(key));
273
		}
274

    
275
		bd.setPropertyValues(props);
276
		return bd;
277
	}
278

    
279
	/**
280
	 * @param hbm2dll
281
	 * @param showSql
282
	 * @return
283
	 */
284
	@Override
285
	public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll){
286
		boolean showSql = false;
287
		boolean formatSql = false;
288
		boolean registerSearchListener = false;
289
		Class<? extends RegionFactory> cacheProviderClass = NoCachingRegionFactory.class;
290
		return getHibernatePropertiesBean(hbm2dll, showSql, formatSql, registerSearchListener, cacheProviderClass);
291
	}
292

    
293

    
294
	/**
295
	 * @param hbm2dll
296
	 * @param showSql
297
	 * @return
298
	 */
299
	@Override
300
	public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll, Boolean showSql, Boolean formatSql, Boolean registerSearchListener, Class<? extends RegionFactory> cacheProviderClass){
301
		//Hibernate default values
302
		if (hbm2dll == null){
303
			hbm2dll = DbSchemaValidation.VALIDATE;
304
		}
305
		if (showSql == null){
306
			showSql = false;
307
		}
308
		if (formatSql == null){
309
			formatSql = false;
310
		}
311
		if (cacheProviderClass == null){
312
			cacheProviderClass = NoCachingRegionFactory.class;
313
		}
314
		if(registerSearchListener == null){
315
			registerSearchListener = false;
316
		}
317

    
318
		DatabaseTypeEnum dbtype = getDatabaseType();
319
		AbstractBeanDefinition bd = new RootBeanDefinition(PropertiesFactoryBean.class);
320
		MutablePropertyValues hibernateProps = new MutablePropertyValues();
321

    
322
		Properties props = new Properties();
323
		props.setProperty("hibernate.hbm2ddl.auto", hbm2dll.toString());
324
		props.setProperty("hibernate.dialect", dbtype.getHibernateDialectCanonicalName());
325
		props.setProperty("hibernate.cache.region.factory_class", cacheProviderClass.getName());
326
		props.setProperty("hibernate.show_sql", String.valueOf(showSql));
327
		props.setProperty("hibernate.format_sql", String.valueOf(formatSql));
328
		props.setProperty("hibernate.search.autoregister_listeners", String.valueOf(registerSearchListener));
329

    
330
		hibernateProps.addPropertyValue("properties",props);
331
		bd.setPropertyValues(hibernateProps);
332
		return bd;
333
	}
334

    
335

    
336
	/**
337
	 * Tests existing of the datsource in the according config  file.
338
	 * @return true if a datasource with the given name exists in the according datasource config file.
339
	 */
340
	public static boolean exists(String strDataSourceName){
341
		Element bean = CdmPersistentSourceUtils.getCdmSourceBeanXml(strDataSourceName, DATASOURCE_BEAN_POSTFIX);
342
		return (bean != null);
343
	}
344

    
345
	/**
346
	 * @param strDataSourceName
347
	 * @param dataSource
348
	 * @param code
349
	 * @return
350
	 * 			the updated dataSource, null if not succesful
351
	 */
352
	public static CdmPersistentDataSource update(String strDataSourceName,
353
			ICdmDataSource dataSource) throws DataSourceNotFoundException, IllegalArgumentException{
354
		CdmPersistentSourceUtils.delete(CdmPersistentSourceUtils.getBeanName(strDataSourceName,DATASOURCE_BEAN_POSTFIX));
355
		return save(strDataSourceName, dataSource);
356
	}
357

    
358
	/**
359
	 * Replace the persisted datasource with another one.
360
	 * Used primarily for renaming a datasource.
361
	 *
362
	 * @param strDataSourceName
363
	 * @param dataSource
364
	 * @return
365
	 * @throws DataSourceNotFoundException
366
	 * @throws IllegalArgumentException
367
	 */
368
	public static CdmPersistentDataSource replace(String strDataSourceName,
369
			ICdmDataSource dataSource) throws DataSourceNotFoundException, IllegalArgumentException{
370
		CdmPersistentSourceUtils.delete(CdmPersistentSourceUtils.getBeanName(strDataSourceName,DATASOURCE_BEAN_POSTFIX));
371
		return save(dataSource);
372
	}
373

    
374
	/**
375
	 * @param dataSource
376
	 * @return
377
	 * @throws IllegalArgumentException
378
	 */
379
	public static CdmPersistentDataSource save(ICdmDataSource dataSource)  throws IllegalArgumentException {
380
		return save(dataSource.getName(),dataSource);
381
	}
382

    
383
	/**
384
	 *
385
	 * @param strDataSourceName
386
	 * @param databaseTypeEnum
387
	 * @param server
388
	 * @param database
389
	 * @param port
390
	 * @param username
391
	 * @param password
392
	 * @param dataSourceClass
393
	 * @param initMethod
394
	 * @param destroyMethod
395
	 * @param startSilent
396
	 * @param startServer
397
	 * @param filePath
398
	 * @param mode
399
	 * @return
400
	 */
401
	private static CdmPersistentDataSource save(String strDataSourceName,
402
			DatabaseTypeEnum databaseTypeEnum,
403
			String server,
404
			String database,
405
			String port,
406
			String username,
407
			String password,
408
			Class<? extends DataSource> dataSourceClass,
409
			String initMethod,
410
			String destroyMethod,
411
			Boolean startSilent,
412
			Boolean startServer,
413
			String filePath,
414
			H2Mode mode
415
		){
416

    
417
		int portNumber = "".equals(port) ? databaseTypeEnum.getDefaultPort() : Integer.valueOf(port);
418

    
419
		ICdmDataSource dataSource = new CdmDataSource(databaseTypeEnum, server, database, portNumber, username, password, filePath, mode);
420

    
421
		//root
422
		Element root = getBeansRoot(CdmPersistentSourceUtils.getCdmSourceInputStream());
423
		if (root == null){
424
			return null;
425
		}
426
		//bean
427
		Element bean = XmlHelp.getFirstAttributedChild(root, "bean", "id", CdmPersistentSourceUtils.getBeanName(strDataSourceName, DATASOURCE_BEAN_POSTFIX));
428
		if (bean != null){
429
			bean.detach();  //delete old version if necessary
430
		}
431
		bean = insertXmlBean(root, CdmPersistentSourceUtils.getBeanName(strDataSourceName, DATASOURCE_BEAN_POSTFIX), dataSourceClass.getName());
432
		//attributes
433
		bean.setAttribute("lazy-init", "true");
434
		if (initMethod != null) {bean.setAttribute("init-method", initMethod);}
435
		if (destroyMethod != null) {bean.setAttribute("destroy-method", destroyMethod);}
436

    
437
		//set properties
438
		insertXmlValueProperty(bean, "driverClassName", databaseTypeEnum.getDriverClassName());
439

    
440
		insertXmlValueProperty(bean, "url", databaseTypeEnum.getConnectionString(dataSource));
441
		if (username != null) {insertXmlValueProperty(bean, "username", username );}
442
		if (password != null) {insertXmlValueProperty(bean, "password", password );}
443
		if (startSilent != null) {insertXmlValueProperty(bean, "startSilent", startSilent.toString() );}
444
		if (startServer != null) {insertXmlValueProperty(bean, "startServer", startServer.toString() );}
445
		if (filePath != null) {insertXmlValueProperty(bean, "filePath", filePath );}
446
		if (mode != null) {insertXmlValueProperty(bean, "mode", mode.toString() );}
447

    
448
		//save
449
		saveToXml(root.getDocument(),
450
				CdmPersistentSourceUtils.getResourceDirectory(),
451
				CdmPersistentXMLSource.CDMSOURCE_FILE_NAME,
452
				XmlHelp.prettyFormat );
453
		try {
454
			return NewInstance(strDataSourceName) ;
455
		} catch (DataSourceNotFoundException e) {
456
			logger.error("Error when saving datasource");
457
			return null;
458
		}
459
	}
460

    
461

    
462
	/**
463
	 * Saves a datasource to the datasource config file. If strDataSourceName differs a new dataSource
464
	 * will be created in config file. Use update() of real update functionality.
465
	 *
466
	 * @param strDataSourceName
467
	 * @param dataSource
468
	 * @return
469
	 */
470
	public static CdmPersistentDataSource save(String strDataSourceName,
471
			ICdmDataSource dataSource)  throws IllegalArgumentException{
472

    
473
		if(dataSource.getDatabaseType() == null){
474
			new IllegalArgumentException("Database type not specified");
475
		}
476

    
477
		if(dataSource.getDatabaseType().equals(DatabaseTypeEnum.H2)){
478
			Class<? extends DataSource> dataSourceClass =  LocalH2.class;
479
			if(dataSource.getMode() == null) {
480
				new IllegalArgumentException("H2 mode not specified");
481
			}
482
			return save(
483
					strDataSourceName,
484
					dataSource.getDatabaseType(),
485
					"localhost",
486
					getCheckedDataSourceParameter(dataSource.getDatabase()),
487
					dataSource.getDatabaseType().getDefaultPort() + "",
488
					getCheckedDataSourceParameter(dataSource.getUsername()),
489
					getCheckedDataSourceParameter(dataSource.getPassword()),
490
					dataSourceClass,
491
					null, null, null, null,
492
					dataSource.getFilePath(),
493
					dataSource.getMode()
494
					);
495
		}else{
496

    
497
			Class<? extends DataSource> dataSourceClass;
498
			try {
499
				dataSourceClass = (Class<? extends DataSource>) Class.forName(dataSourceClassName);
500
				String server = getCheckedDataSourceParameter(dataSource.getServer());
501
				CdmPersistentDataSource persistendDatasource =  save(
502
					strDataSourceName,
503
					dataSource.getDatabaseType(),
504
					getCheckedDataSourceParameter(dataSource.getServer()),
505
					getCheckedDataSourceParameter(dataSource.getDatabase()),
506
					dataSource.getPort() + "",
507
					getCheckedDataSourceParameter(dataSource.getUsername()),
508
					getCheckedDataSourceParameter(dataSource.getPassword()),
509
					dataSourceClass,
510
					null, null, null, null, null, null
511
				);
512

    
513
				return persistendDatasource;
514
			} catch (ClassNotFoundException e) {
515
				logger.error("DataSourceClass not found - stopping application", e);
516
				System.exit(-1);
517
			}
518
			// will never be reached
519
			return null;
520
		}
521
	}
522

    
523
	private static String getCheckedDataSourceParameter(String parameter) throws IllegalArgumentException{
524
		if(parameter != null) {
525
			return parameter;
526
		} else {
527
			throw new IllegalArgumentException("Non obsolete paramater was assigned a null value: " + parameter);
528
		}
529
	}
530

    
531

    
532
	/**
533
	 * Returns a list of all datasources stored in the datasource config file
534
	 * @return all existing data sources
535
	 */
536
	@SuppressWarnings("unchecked")
537
	static public List<CdmPersistentDataSource> getAllDataSources(){
538
		List<CdmPersistentDataSource> dataSources = new ArrayList<CdmPersistentDataSource>();
539

    
540
		Element root = getBeansRoot(CdmPersistentSourceUtils.getCdmSourceInputStream());
541
		if (root == null){
542
			return null;
543
		}else{
544
	    	List<Element> lsChildren  = root.getChildren("bean", root.getNamespace());
545

    
546
	    	for (Element elBean : lsChildren){
547
	    		String strId = elBean.getAttributeValue("id");
548
	    		if (strId != null && strId.endsWith(DATASOURCE_BEAN_POSTFIX)){
549
	    			strId = strId.replace(DATASOURCE_BEAN_POSTFIX, "");
550
	    			dataSources.add(new CdmPersistentDataSource(strId));
551
	    		}
552
	    	}
553
		}
554
		return dataSources;
555
	}
556

    
557

    
558
	@Override
559
	public boolean equals(Object obj){
560
		if (obj == null){
561
			return false;
562
		}else if (! CdmPersistentDataSource.class.isAssignableFrom(obj.getClass())){
563
			return false;
564
		}else{
565
			CdmPersistentDataSource dataSource = (CdmPersistentDataSource)obj;
566
			return (getName() == dataSource.getName());
567
		}
568

    
569
	}
570

    
571
	@Override
572
	public String toString(){
573
		if (getName() != null){
574
			return getName();
575
		}else{
576
			return null;
577
		}
578
	}
579

    
580

    
581

    
582

    
583

    
584

    
585

    
586

    
587

    
588
}
(3-3/20)