Project

General

Profile

Download (18.1 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
package eu.etaxonomy.cdm.database;
10

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

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

    
22
import javax.sql.DataSource;
23

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

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

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

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

    
50
    @SuppressWarnings("unused")
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
	 */
74
	public final static CdmPersistentDataSource NewDefaultInstance() throws DataSourceNotFoundException {
75
		return NewInstance("default");
76
	}
77

    
78
	/**
79
	 * Returns the default CdmDataSource
80
	 */
81
	public final static CdmPersistentDataSource NewLocalHsqlInstance() throws DataSourceNotFoundException{
82
		return NewInstance("localDefaultHsql");
83
	}
84

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

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

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

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

    
144
	@Override
145
    public String getBeanName() {
146
		return beanName;
147
	}
148

    
149
	@Override
150
	public String getDatabase() {
151
		return database;
152
	}
153

    
154
	@Override
155
	public void setDatabase(String database) {
156
		this.database = database;
157
		//update url string
158
		cdmSourceProperties.put(CdmSourceProperties.URL.toString(), getDatabaseType().getConnectionString(this));
159
	}
160

    
161
	@Override
162
	public void setServer(String server) {
163
		super.setServer(server);
164
		//update url string
165
		cdmSourceProperties.put(CdmSourceProperties.URL.toString(), getDatabaseType().getConnectionString(this));
166
	}
167

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

    
177
	@Override
178
	public String getFilePath() {
179
		return getCdmSourceProperty(CdmSourceProperties.FILEPATH);
180
	}
181

    
182
	@Override
183
	public H2Mode getMode() {
184
		return H2Mode.fromString(getCdmSourceProperty(CdmSourceProperties.MODE));
185
	}
186

    
187
	@Override
188
	public void setMode(H2Mode h2Mode) {
189
		cdmSourceProperties.put(CdmSourceProperties.MODE.toString(), h2Mode.name());
190
	}
191

    
192
	@Override
193
	public String getUsername(){
194
		return getCdmSourceProperty(CdmSourceProperties.USERNAME);
195
	}
196

    
197
	@Override
198
	public void setUsername(String username) {
199
		cdmSourceProperties.put(CdmSourceProperties.USERNAME.toString(), username);
200
	}
201

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

    
207
	@Override
208
	public void setPassword(String password) {
209
		cdmSourceProperties.put(CdmSourceProperties.PASSWORD.toString(), password);
210
	}
211

    
212
	@Override
213
	public DatabaseTypeEnum getDatabaseType(){
214
		String strDriverClass = getCdmSourceProperty(CdmSourceProperties.DRIVER_CLASS);
215
		DatabaseTypeEnum dbType = DatabaseTypeEnum.byDriverClass(strDriverClass);
216
		return dbType;
217
	}
218

    
219
	public String getCdmSourceProperty(CdmSourceProperties property){
220
		return cdmSourceProperties.getProperty(property.toString(),null);
221
	}
222

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

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

    
252
		//properties
253
		MutablePropertyValues props = new MutablePropertyValues();
254

    
255
		Enumeration<String> keys = (Enumeration)cdmSourceProperties.keys();
256
		while (keys.hasMoreElements()){
257
			String key = keys.nextElement();
258

    
259
			props.addPropertyValue(key, cdmSourceProperties.getProperty(key));
260
		}
261

    
262
		bd.setPropertyValues(props);
263
		return bd;
264
	}
265

    
266
	@Override
267
	public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll){
268
		HibernateConfiguration hibernateConfig = HibernateConfiguration.NewDefaultInstance();
269
        return getHibernatePropertiesBean(hbm2dll, hibernateConfig);
270
	}
271

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

    
281
    @Override
282
    public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll,
283
            HibernateConfiguration hibernateConfig) {
284

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

    
294
		//Hibernate default values
295
		if (hbm2dll == null){
296
			hbm2dll = DbSchemaValidation.VALIDATE;
297
		}
298

    
299
		return makeHibernatePropertiesBean(getDatabaseType(), hbm2dll, showSql, formatSql, registerAuditing,
300
		        registerSearchListener, cacheProviderClass);
301
	}
302

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

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

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

    
341
	/**
342
	 * @param dataSource
343
	 * @return
344
	 * @throws IllegalArgumentException
345
	 */
346
	public static CdmPersistentDataSource save(ICdmDataSource dataSource)  throws IllegalArgumentException {
347
		return save(dataSource.getName(),dataSource);
348
	}
349

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

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

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

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

    
404
		//set properties
405
		insertXmlValueProperty(bean, "driverClassName", databaseTypeEnum.getDriverClassName());
406

    
407
		insertXmlValueProperty(bean, "url", databaseTypeEnum.getConnectionString(dataSource));
408
		if (username != null) {insertXmlValueProperty(bean, "username", username );}
409
		if (password != null) {insertXmlValueProperty(bean, "password", password );}
410
		if (startSilent != null) {insertXmlValueProperty(bean, "startSilent", startSilent.toString() );}
411
		if (startServer != null) {insertXmlValueProperty(bean, "startServer", startServer.toString() );}
412
		if (filePath != null) {insertXmlValueProperty(bean, "filePath", filePath );}
413
		if (mode != null) {insertXmlValueProperty(bean, "mode", mode.toString() );}
414

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

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

    
438
		if(dataSource.getDatabaseType() == null){
439
			throw new IllegalArgumentException("Database type not specified");
440
		}
441

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

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

    
478
				return persistendDatasource;
479
			} catch (ClassNotFoundException e) {
480
			    throw new RuntimeException("DataSourceClass not found: " + dataSourceClassName, e);
481
			}
482
		}
483
	}
484

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

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

    
501
		Element root = getBeansRoot(CdmPersistentSourceUtils.getCdmSourceInputStream());
502
		if (root == null){
503
			return null;
504
		}else{
505
	    	List<Element> lsChildren  = root.getChildren("bean", root.getNamespace());
506

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

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

    
530
	@Override
531
	public String toString(){
532
		if (getName() != null){
533
			return getName();
534
		}else{
535
			return super.toString();
536
		}
537
	}
538
}
(4-4/22)