Project

General

Profile

Download (18.2 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.spi.RegionFactory;
27
import org.jdom.Attribute;
28
import org.jdom.Element;
29
import org.springframework.beans.MutablePropertyValues;
30
import org.springframework.beans.factory.config.BeanDefinition;
31
import org.springframework.beans.factory.support.AbstractBeanDefinition;
32
import org.springframework.beans.factory.support.RootBeanDefinition;
33

    
34
import com.mchange.v2.c3p0.ComboPooledDataSource;
35

    
36
import eu.etaxonomy.cdm.common.XmlHelp;
37
import eu.etaxonomy.cdm.config.CdmPersistentSourceUtils;
38
import eu.etaxonomy.cdm.config.CdmPersistentXMLSource;
39
import eu.etaxonomy.cdm.config.CdmPersistentXMLSource.CdmSourceProperties;
40
import eu.etaxonomy.cdm.config.ICdmPersistentSource;
41
import eu.etaxonomy.cdm.database.types.IDatabaseType;
42
import eu.etaxonomy.cdm.persistence.hibernate.HibernateConfiguration;
43

    
44
/**
45
 * Class to access a CdmDataSource which is stored in datasources.xml
46
 */
47
public class CdmPersistentDataSource
48
        extends CdmDataSourceBase
49
        implements ICdmPersistentSource {
50

    
51
    private static final Logger logger = Logger.getLogger(CdmPersistentDataSource.class);
52

    
53
	public static final String DATASOURCE_BEAN_POSTFIX = "DataSource";
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
	 * The Datasource class that Spring will use to set up the connection to the database
68
	 */
69
	private static String dataSourceClassName = ComboPooledDataSource.class.getName();
70

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

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

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

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

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

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

    
148
	@Override
149
    public String getBeanName() {
150
		return beanName;
151
	}
152

    
153
	@Override
154
	public String getDatabase() {
155
		return database;
156
	}
157

    
158
	@Override
159
	public void setDatabase(String database) {
160
		this.database = database;
161
		//update url string
162
		cdmSourceProperties.put(CdmSourceProperties.URL.toString(), getDatabaseType().getConnectionString(this));
163
	}
164

    
165
	@Override
166
	public void setServer(String server) {
167
		super.setServer(server);
168
		//update url string
169
		cdmSourceProperties.put(CdmSourceProperties.URL.toString(), getDatabaseType().getConnectionString(this));
170
	}
171

    
172
	@Override
173
	public void setPort(int port) {
174
		super.setPort(port);
175
		if(port != NULL_PORT) {
176
			//update url string
177
			cdmSourceProperties.put(CdmSourceProperties.URL.toString(), getDatabaseType().getConnectionString(this));
178
		}
179
	}
180

    
181
	@Override
182
	public String getFilePath() {
183
		return getCdmSourceProperty(CdmSourceProperties.FILEPATH);
184
	}
185

    
186
	@Override
187
	public H2Mode getMode() {
188
		return H2Mode.fromString(getCdmSourceProperty(CdmSourceProperties.MODE));
189
	}
190

    
191
	@Override
192
	public void setMode(H2Mode h2Mode) {
193
		cdmSourceProperties.put(CdmSourceProperties.MODE.toString(), h2Mode.name());
194
	}
195

    
196
	@Override
197
	public String getUsername(){
198
		return getCdmSourceProperty(CdmSourceProperties.USERNAME);
199
	}
200

    
201
	@Override
202
	public void setUsername(String username) {
203
		cdmSourceProperties.put(CdmSourceProperties.USERNAME.toString(), username);
204
	}
205

    
206
	@Override
207
	public String getPassword(){
208
		return getCdmSourceProperty(CdmSourceProperties.PASSWORD);
209
	}
210

    
211
	@Override
212
	public void setPassword(String password) {
213
		cdmSourceProperties.put(CdmSourceProperties.PASSWORD.toString(), password);
214
	}
215

    
216
	@Override
217
	public DatabaseTypeEnum getDatabaseType(){
218
		String strDriverClass = getCdmSourceProperty(CdmSourceProperties.DRIVER_CLASS);
219
		DatabaseTypeEnum dbType = DatabaseTypeEnum.byDriverClass(strDriverClass);
220
		return dbType;
221
	}
222

    
223
	public String getCdmSourceProperty(CdmSourceProperties property){
224
		return cdmSourceProperties.getProperty(property.toString(),null);
225
	}
226

    
227
	/**
228
	 * Returns a BeanDefinition object of type DataSource that contains
229
	 * datsource properties (url, username, password, ...)
230
	 * @return
231
	 */
232
	@SuppressWarnings("unchecked")
233
	@Override
234
	public BeanDefinition getDatasourceBean(){
235
		DatabaseTypeEnum dbtype =
236
				DatabaseTypeEnum.byDriverClass(getCdmSourceProperty(CdmSourceProperties.DRIVER_CLASS));
237

    
238
		AbstractBeanDefinition bd = new RootBeanDefinition(dbtype.getDataSourceClass());
239
		//attributes
240
		Iterator<Attribute> iterator = cdmSourceAttributes.iterator();
241
		while(iterator.hasNext()){
242
			Attribute attribute = iterator.next();
243
			if (attribute.getName().equals("lazy-init")){
244
				bd.setLazyInit(Boolean.valueOf(attribute.getValue()));
245
			}
246
			if (attribute.getName().equals("init-method")){
247
				bd.setInitMethodName(attribute.getValue());
248
			}
249
			if (attribute.getName().equals("destroy-method")){
250
				bd.setDestroyMethodName(attribute.getValue());
251
			}
252
			//Attribute attribute = iterator.next();
253
			//bd.setAttribute(attribute.getName(), attribute.getValue());
254
		}
255

    
256
		//properties
257
		MutablePropertyValues props = new MutablePropertyValues();
258

    
259
		Enumeration<String> keys = (Enumeration)cdmSourceProperties.keys();
260
		while (keys.hasMoreElements()){
261
			String key = keys.nextElement();
262

    
263
			props.addPropertyValue(key, cdmSourceProperties.getProperty(key));
264
		}
265

    
266
		bd.setPropertyValues(props);
267
		return bd;
268
	}
269

    
270
	@Override
271
	public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll){
272
		HibernateConfiguration hibernateConfig = HibernateConfiguration.NewDefaultInstance();
273
        return getHibernatePropertiesBean(hbm2dll, hibernateConfig);
274
	}
275

    
276
    @Override
277
    @Deprecated
278
    public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll, Boolean showSql, Boolean formatSql,
279
            Boolean registerSearchListener, Class<? extends RegionFactory> cacheProviderClass){
280
        HibernateConfiguration hibernateConfig = HibernateConfiguration.NewInstance(showSql, formatSql,
281
                registerSearchListener, null, cacheProviderClass);
282
        return this.getHibernatePropertiesBean(hbm2dll, hibernateConfig);
283
    }
284

    
285
    @Override
286
    public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll,
287
            HibernateConfiguration hibernateConfig) {
288

    
289
        if (hibernateConfig == null){
290
            hibernateConfig = new HibernateConfiguration();
291
        }
292
        boolean showSql = hibernateConfig.getShowSql(HibernateConfiguration.SHOW_SQL_DEFAULT);
293
        boolean formatSql = hibernateConfig.getFormatSql(HibernateConfiguration.SHOW_SQL_DEFAULT);
294
        boolean registerAuditing = hibernateConfig.getRegisterEnvers(HibernateConfiguration.REGISTER_ENVERS_DEFAULT);
295
        boolean registerSearchListener = hibernateConfig.getRegisterSearch(HibernateConfiguration.REGISTER_SEARCH_DEFAULT);
296
        Class<? extends RegionFactory> cacheProviderClass = hibernateConfig.getCacheProviderClass(HibernateConfiguration.CACHE_PROVIDER_DEFAULT);
297

    
298
		//Hibernate default values
299
		if (hbm2dll == null){
300
			hbm2dll = DbSchemaValidation.VALIDATE;
301
		}
302

    
303
		return makeHibernatePropertiesBean(getDatabaseType(), hbm2dll, showSql, formatSql, registerAuditing,
304
		        registerSearchListener, cacheProviderClass);
305
	}
306

    
307
	/**
308
	 * Tests existing of the datsource in the according config  file.
309
	 * @return true if a datasource with the given name exists in the according datasource config file.
310
	 */
311
	public static boolean exists(String strDataSourceName){
312
		Element bean = CdmPersistentSourceUtils.getCdmSourceBeanXml(strDataSourceName, DATASOURCE_BEAN_POSTFIX);
313
		return (bean != null);
314
	}
315

    
316
	/**
317
	 * @param strDataSourceName
318
	 * @param dataSource
319
	 * @param code
320
	 * @return
321
	 * 			the updated dataSource, null if not succesful
322
	 */
323
	public static CdmPersistentDataSource update(String strDataSourceName,
324
			ICdmDataSource dataSource) throws DataSourceNotFoundException, IllegalArgumentException{
325
		CdmPersistentSourceUtils.delete(CdmPersistentSourceUtils.getBeanName(strDataSourceName,DATASOURCE_BEAN_POSTFIX));
326
		return save(strDataSourceName, dataSource);
327
	}
328

    
329
	/**
330
	 * Replace the persisted datasource with another one.
331
	 * Used primarily for renaming a datasource.
332
	 *
333
	 * @param strDataSourceName
334
	 * @param dataSource
335
	 * @return
336
	 * @throws DataSourceNotFoundException
337
	 * @throws IllegalArgumentException
338
	 */
339
	public static CdmPersistentDataSource replace(String strDataSourceName,
340
			ICdmDataSource dataSource) throws DataSourceNotFoundException, IllegalArgumentException{
341
		CdmPersistentSourceUtils.delete(CdmPersistentSourceUtils.getBeanName(strDataSourceName,DATASOURCE_BEAN_POSTFIX));
342
		return save(dataSource);
343
	}
344

    
345
	/**
346
	 * @param dataSource
347
	 * @return
348
	 * @throws IllegalArgumentException
349
	 */
350
	public static CdmPersistentDataSource save(ICdmDataSource dataSource)  throws IllegalArgumentException {
351
		return save(dataSource.getName(),dataSource);
352
	}
353

    
354
	/**
355
	 *
356
	 * @param strDataSourceName
357
	 * @param databaseTypeEnum
358
	 * @param server
359
	 * @param database
360
	 * @param port
361
	 * @param username
362
	 * @param password
363
	 * @param dataSourceClass
364
	 * @param initMethod
365
	 * @param destroyMethod
366
	 * @param startSilent
367
	 * @param startServer
368
	 * @param filePath
369
	 * @param mode
370
	 * @return
371
	 */
372
	private static CdmPersistentDataSource save(String strDataSourceName,
373
			DatabaseTypeEnum databaseTypeEnum,
374
			String server,
375
			String database,
376
			String port,
377
			String username,
378
			String password,
379
			Class<? extends DataSource> dataSourceClass,
380
			String initMethod,
381
			String destroyMethod,
382
			Boolean startSilent,
383
			Boolean startServer,
384
			String filePath,
385
			H2Mode mode
386
		){
387

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

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

    
392
		//root
393
		Element root = getBeansRoot(CdmPersistentSourceUtils.getCdmSourceInputStream());
394
		if (root == null){
395
			return null;
396
		}
397
		//bean
398
		Element bean = XmlHelp.getFirstAttributedChild(root, "bean", "id", CdmPersistentSourceUtils.getBeanName(strDataSourceName, DATASOURCE_BEAN_POSTFIX));
399
		if (bean != null){
400
			bean.detach();  //delete old version if necessary
401
		}
402
		bean = insertXmlBean(root, CdmPersistentSourceUtils.getBeanName(strDataSourceName, DATASOURCE_BEAN_POSTFIX), dataSourceClass.getName());
403
		//attributes
404
		bean.setAttribute("lazy-init", "true");
405
		if (initMethod != null) {bean.setAttribute("init-method", initMethod);}
406
		if (destroyMethod != null) {bean.setAttribute("destroy-method", destroyMethod);}
407

    
408
		//set properties
409
		insertXmlValueProperty(bean, "driverClassName", databaseTypeEnum.getDriverClassName());
410

    
411
		insertXmlValueProperty(bean, "url", databaseTypeEnum.getConnectionString(dataSource));
412
		if (username != null) {insertXmlValueProperty(bean, "username", username );}
413
		if (password != null) {insertXmlValueProperty(bean, "password", password );}
414
		if (startSilent != null) {insertXmlValueProperty(bean, "startSilent", startSilent.toString() );}
415
		if (startServer != null) {insertXmlValueProperty(bean, "startServer", startServer.toString() );}
416
		if (filePath != null) {insertXmlValueProperty(bean, "filePath", filePath );}
417
		if (mode != null) {insertXmlValueProperty(bean, "mode", mode.toString() );}
418

    
419
		//save
420
		saveToXml(root.getDocument(),
421
				CdmPersistentSourceUtils.getResourceDirectory(),
422
				CdmPersistentXMLSource.CDMSOURCE_FILE_NAME,
423
				XmlHelp.prettyFormat );
424
		try {
425
			return NewInstance(strDataSourceName) ;
426
		} catch (DataSourceNotFoundException e) {
427
			throw new RuntimeException("Error when saving CdmPersistentDatasource", e);
428
		}
429
	}
430

    
431
	/**
432
	 * Saves a datasource to the datasource config file. If strDataSourceName differs a new dataSource
433
	 * will be created in config file. Use update() of real update functionality.
434
	 *
435
	 * @param strDataSourceName
436
	 * @param dataSource
437
	 * @return
438
	 */
439
	public static CdmPersistentDataSource save(String strDataSourceName,
440
			ICdmDataSource dataSource)  throws IllegalArgumentException{
441

    
442
		if(dataSource.getDatabaseType() == null){
443
			throw new IllegalArgumentException("Database type not specified");
444
		}
445

    
446
		if(dataSource.getDatabaseType().equals(DatabaseTypeEnum.H2)){
447
			Class<? extends DataSource> dataSourceClass =  LocalH2.class;
448
			if(dataSource.getMode() == null) {
449
			    throw new IllegalArgumentException("H2 mode not specified");
450
			}
451
			return save(
452
					strDataSourceName,
453
					dataSource.getDatabaseType(),
454
					"localhost",
455
					getCheckedDataSourceParameter(dataSource.getDatabase()),
456
					dataSource.getDatabaseType().getDefaultPort() + "",
457
					getCheckedDataSourceParameter(dataSource.getUsername()),
458
					getCheckedDataSourceParameter(dataSource.getPassword()),
459
					dataSourceClass,
460
					null, null, null, null,
461
					dataSource.getFilePath(),
462
					dataSource.getMode()
463
				);
464
		}else{
465

    
466
			Class<? extends DataSource> dataSourceClass;
467
			try {
468
				dataSourceClass = (Class<? extends DataSource>) Class.forName(dataSourceClassName);
469
				String server = getCheckedDataSourceParameter(dataSource.getServer());
470
				CdmPersistentDataSource persistendDatasource =  save(
471
					strDataSourceName,
472
					dataSource.getDatabaseType(),
473
					getCheckedDataSourceParameter(dataSource.getServer()),
474
					getCheckedDataSourceParameter(dataSource.getDatabase()),
475
					dataSource.getPort() + "",
476
					getCheckedDataSourceParameter(dataSource.getUsername()),
477
					getCheckedDataSourceParameter(dataSource.getPassword()),
478
					dataSourceClass,
479
					null, null, null, null, null, null
480
				);
481

    
482
				return persistendDatasource;
483
			} catch (ClassNotFoundException e) {
484
			    throw new RuntimeException("DataSourceClass not found: " + dataSourceClassName, e);
485
			}
486
		}
487
	}
488

    
489
	private static String getCheckedDataSourceParameter(String parameter) throws IllegalArgumentException{
490
		if(parameter != null) {
491
			return parameter;
492
		} else {
493
			throw new IllegalArgumentException("Non obsolete paramater was assigned a null value: " + parameter);
494
		}
495
	}
496

    
497
	/**
498
	 * Returns a list of all datasources stored in the datasource config file
499
	 * @return all existing data sources
500
	 */
501
	@SuppressWarnings("unchecked")
502
	static public List<CdmPersistentDataSource> getAllDataSources(){
503
		List<CdmPersistentDataSource> dataSources = new ArrayList<>();
504

    
505
		Element root = getBeansRoot(CdmPersistentSourceUtils.getCdmSourceInputStream());
506
		if (root == null){
507
			return null;
508
		}else{
509
	    	List<Element> lsChildren  = root.getChildren("bean", root.getNamespace());
510

    
511
	    	for (Element elBean : lsChildren){
512
	    		String strId = elBean.getAttributeValue("id");
513
	    		if (strId != null && strId.endsWith(DATASOURCE_BEAN_POSTFIX)){
514
	    			strId = strId.replace(DATASOURCE_BEAN_POSTFIX, "");
515
	    			dataSources.add(new CdmPersistentDataSource(strId));
516
	    		}
517
	    	}
518
		}
519
		return dataSources;
520
	}
521

    
522
	@Override
523
	public boolean equals(Object obj){
524
		if (obj == null){
525
			return false;
526
		}else if (! CdmPersistentDataSource.class.isAssignableFrom(obj.getClass())){
527
			return false;
528
		}else{
529
			CdmPersistentDataSource dataSource = (CdmPersistentDataSource)obj;
530
			return (getName() == dataSource.getName());
531
		}
532
	}
533

    
534
	@Override
535
	public String toString(){
536
		if (getName() != null){
537
			return getName();
538
		}else{
539
			return super.toString();
540
		}
541
	}
542
}
(4-4/21)