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.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
/**
46
 * class to access an CdmDataSource
47
 */
48
public class CdmPersistentDataSource extends CdmDataSourceBase implements ICdmPersistentSource {
49
	private static final Logger logger = Logger.getLogger(CdmPersistentDataSource.class);
50

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

    
53

    
54
	private String beanName;
55

    
56
	private String database;
57

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

    
63
	private List<Attribute> cdmSourceAttributes;
64

    
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
	/**
73
	 * Returns the default CdmDataSource
74
	 * @return the default CdmDataSource
75
	 * @throws DataSourceNotFoundException
76
	 */
77
	public final static CdmPersistentDataSource NewDefaultInstance() throws DataSourceNotFoundException {
78
		return NewInstance("default");
79
	}
80

    
81

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

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

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

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

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

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

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

    
160

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

    
167
	}
168

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

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

    
189

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

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

    
199
	}
200

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

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

    
210
	}
211

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

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

    
221
	}
222

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

    
230

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

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

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

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

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

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

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

    
278
	/**
279
	 * @param hbm2dll
280
	 * @param showSql
281
	 * @return
282
	 */
283
	@Override
284
	public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll){
285
		HibernateConfiguration hibernateConfig = HibernateConfiguration.NewDefaultInstance();
286
        return getHibernatePropertiesBean(hbm2dll, hibernateConfig);
287
	}
288

    
289

    
290
    /**
291
     * {@inheritDoc}
292
     */
293
    @Override
294
    @Deprecated
295
    public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll, Boolean showSql, Boolean formatSql,
296
            Boolean registerSearchListener, Class<? extends RegionFactory> cacheProviderClass){
297
        HibernateConfiguration hibernateConfig = HibernateConfiguration.NewInstance(showSql, formatSql,
298
                registerSearchListener, null, cacheProviderClass);
299
        return this.getHibernatePropertiesBean(hbm2dll, hibernateConfig);
300
    }
301

    
302
    /**
303
     * {@inheritDoc}
304
     */
305
    @Override
306
    public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll,
307
            HibernateConfiguration hibernateConfig) {
308

    
309
        if (hibernateConfig == null){
310
            hibernateConfig = new HibernateConfiguration();
311
        }
312
        boolean showSql = hibernateConfig.getShowSql(HibernateConfiguration.SHOW_SQL_DEFAULT);
313
        boolean formatSql = hibernateConfig.getFormatSql(HibernateConfiguration.SHOW_SQL_DEFAULT);
314
        boolean registerAuditing = hibernateConfig.getRegisterEnvers(HibernateConfiguration.REGISTER_ENVERS_DEFAULT);
315
        boolean registerSearchListener = hibernateConfig.getRegisterSearch(HibernateConfiguration.REGISTER_SEARCH_DEFAULT);
316
        Class<? extends RegionFactory> cacheProviderClass = hibernateConfig.getCacheProviderClass(HibernateConfiguration.CACHE_PROVIDER_DEFAULT);
317

    
318
		//Hibernate default values
319
		if (hbm2dll == null){
320
			hbm2dll = DbSchemaValidation.VALIDATE;
321
		}
322

    
323
		return makeHibernatePropertiesBean(getDatabaseType(), hbm2dll, showSql, formatSql, registerAuditing,
324
		        registerSearchListener, cacheProviderClass);
325

    
326
	}
327

    
328

    
329
	/**
330
	 * Tests existing of the datsource in the according config  file.
331
	 * @return true if a datasource with the given name exists in the according datasource config file.
332
	 */
333
	public static boolean exists(String strDataSourceName){
334
		Element bean = CdmPersistentSourceUtils.getCdmSourceBeanXml(strDataSourceName, DATASOURCE_BEAN_POSTFIX);
335
		return (bean != null);
336
	}
337

    
338
	/**
339
	 * @param strDataSourceName
340
	 * @param dataSource
341
	 * @param code
342
	 * @return
343
	 * 			the updated dataSource, null if not succesful
344
	 */
345
	public static CdmPersistentDataSource update(String strDataSourceName,
346
			ICdmDataSource dataSource) throws DataSourceNotFoundException, IllegalArgumentException{
347
		CdmPersistentSourceUtils.delete(CdmPersistentSourceUtils.getBeanName(strDataSourceName,DATASOURCE_BEAN_POSTFIX));
348
		return save(strDataSourceName, dataSource);
349
	}
350

    
351
	/**
352
	 * Replace the persisted datasource with another one.
353
	 * Used primarily for renaming a datasource.
354
	 *
355
	 * @param strDataSourceName
356
	 * @param dataSource
357
	 * @return
358
	 * @throws DataSourceNotFoundException
359
	 * @throws IllegalArgumentException
360
	 */
361
	public static CdmPersistentDataSource replace(String strDataSourceName,
362
			ICdmDataSource dataSource) throws DataSourceNotFoundException, IllegalArgumentException{
363
		CdmPersistentSourceUtils.delete(CdmPersistentSourceUtils.getBeanName(strDataSourceName,DATASOURCE_BEAN_POSTFIX));
364
		return save(dataSource);
365
	}
366

    
367
	/**
368
	 * @param dataSource
369
	 * @return
370
	 * @throws IllegalArgumentException
371
	 */
372
	public static CdmPersistentDataSource save(ICdmDataSource dataSource)  throws IllegalArgumentException {
373
		return save(dataSource.getName(),dataSource);
374
	}
375

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

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

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

    
414
		//root
415
		Element root = getBeansRoot(CdmPersistentSourceUtils.getCdmSourceInputStream());
416
		if (root == null){
417
			return null;
418
		}
419
		//bean
420
		Element bean = XmlHelp.getFirstAttributedChild(root, "bean", "id", CdmPersistentSourceUtils.getBeanName(strDataSourceName, DATASOURCE_BEAN_POSTFIX));
421
		if (bean != null){
422
			bean.detach();  //delete old version if necessary
423
		}
424
		bean = insertXmlBean(root, CdmPersistentSourceUtils.getBeanName(strDataSourceName, DATASOURCE_BEAN_POSTFIX), dataSourceClass.getName());
425
		//attributes
426
		bean.setAttribute("lazy-init", "true");
427
		if (initMethod != null) {bean.setAttribute("init-method", initMethod);}
428
		if (destroyMethod != null) {bean.setAttribute("destroy-method", destroyMethod);}
429

    
430
		//set properties
431
		insertXmlValueProperty(bean, "driverClassName", databaseTypeEnum.getDriverClassName());
432

    
433
		insertXmlValueProperty(bean, "url", databaseTypeEnum.getConnectionString(dataSource));
434
		if (username != null) {insertXmlValueProperty(bean, "username", username );}
435
		if (password != null) {insertXmlValueProperty(bean, "password", password );}
436
		if (startSilent != null) {insertXmlValueProperty(bean, "startSilent", startSilent.toString() );}
437
		if (startServer != null) {insertXmlValueProperty(bean, "startServer", startServer.toString() );}
438
		if (filePath != null) {insertXmlValueProperty(bean, "filePath", filePath );}
439
		if (mode != null) {insertXmlValueProperty(bean, "mode", mode.toString() );}
440

    
441
		//save
442
		saveToXml(root.getDocument(),
443
				CdmPersistentSourceUtils.getResourceDirectory(),
444
				CdmPersistentXMLSource.CDMSOURCE_FILE_NAME,
445
				XmlHelp.prettyFormat );
446
		try {
447
			return NewInstance(strDataSourceName) ;
448
		} catch (DataSourceNotFoundException e) {
449
			logger.error("Error when saving datasource");
450
			return null;
451
		}
452
	}
453

    
454

    
455
	/**
456
	 * Saves a datasource to the datasource config file. If strDataSourceName differs a new dataSource
457
	 * will be created in config file. Use update() of real update functionality.
458
	 *
459
	 * @param strDataSourceName
460
	 * @param dataSource
461
	 * @return
462
	 */
463
	public static CdmPersistentDataSource save(String strDataSourceName,
464
			ICdmDataSource dataSource)  throws IllegalArgumentException{
465

    
466
		if(dataSource.getDatabaseType() == null){
467
			throw new IllegalArgumentException("Database type not specified");
468
		}
469

    
470
		if(dataSource.getDatabaseType().equals(DatabaseTypeEnum.H2)){
471
			Class<? extends DataSource> dataSourceClass =  LocalH2.class;
472
			if(dataSource.getMode() == null) {
473
			    throw new IllegalArgumentException("H2 mode not specified");
474
			}
475
			return save(
476
					strDataSourceName,
477
					dataSource.getDatabaseType(),
478
					"localhost",
479
					getCheckedDataSourceParameter(dataSource.getDatabase()),
480
					dataSource.getDatabaseType().getDefaultPort() + "",
481
					getCheckedDataSourceParameter(dataSource.getUsername()),
482
					getCheckedDataSourceParameter(dataSource.getPassword()),
483
					dataSourceClass,
484
					null, null, null, null,
485
					dataSource.getFilePath(),
486
					dataSource.getMode()
487
					);
488
		}else{
489

    
490
			Class<? extends DataSource> dataSourceClass;
491
			try {
492
				dataSourceClass = (Class<? extends DataSource>) Class.forName(dataSourceClassName);
493
				String server = getCheckedDataSourceParameter(dataSource.getServer());
494
				CdmPersistentDataSource persistendDatasource =  save(
495
					strDataSourceName,
496
					dataSource.getDatabaseType(),
497
					getCheckedDataSourceParameter(dataSource.getServer()),
498
					getCheckedDataSourceParameter(dataSource.getDatabase()),
499
					dataSource.getPort() + "",
500
					getCheckedDataSourceParameter(dataSource.getUsername()),
501
					getCheckedDataSourceParameter(dataSource.getPassword()),
502
					dataSourceClass,
503
					null, null, null, null, null, null
504
				);
505

    
506
				return persistendDatasource;
507
			} catch (ClassNotFoundException e) {
508
				logger.error("DataSourceClass not found - stopping application", e);
509
				System.exit(-1);
510
			}
511
			// will never be reached
512
			return null;
513
		}
514
	}
515

    
516
	private static String getCheckedDataSourceParameter(String parameter) throws IllegalArgumentException{
517
		if(parameter != null) {
518
			return parameter;
519
		} else {
520
			throw new IllegalArgumentException("Non obsolete paramater was assigned a null value: " + parameter);
521
		}
522
	}
523

    
524

    
525
	/**
526
	 * Returns a list of all datasources stored in the datasource config file
527
	 * @return all existing data sources
528
	 */
529
	@SuppressWarnings("unchecked")
530
	static public List<CdmPersistentDataSource> getAllDataSources(){
531
		List<CdmPersistentDataSource> dataSources = new ArrayList<>();
532

    
533
		Element root = getBeansRoot(CdmPersistentSourceUtils.getCdmSourceInputStream());
534
		if (root == null){
535
			return null;
536
		}else{
537
	    	List<Element> lsChildren  = root.getChildren("bean", root.getNamespace());
538

    
539
	    	for (Element elBean : lsChildren){
540
	    		String strId = elBean.getAttributeValue("id");
541
	    		if (strId != null && strId.endsWith(DATASOURCE_BEAN_POSTFIX)){
542
	    			strId = strId.replace(DATASOURCE_BEAN_POSTFIX, "");
543
	    			dataSources.add(new CdmPersistentDataSource(strId));
544
	    		}
545
	    	}
546
		}
547
		return dataSources;
548
	}
549

    
550

    
551
	@Override
552
	public boolean equals(Object obj){
553
		if (obj == null){
554
			return false;
555
		}else if (! CdmPersistentDataSource.class.isAssignableFrom(obj.getClass())){
556
			return false;
557
		}else{
558
			CdmPersistentDataSource dataSource = (CdmPersistentDataSource)obj;
559
			return (getName() == dataSource.getName());
560
		}
561
	}
562

    
563
	@Override
564
	public String toString(){
565
		if (getName() != null){
566
			return getName();
567
		}else{
568
			return super.toString();
569
		}
570
	}
571
}
(3-3/20)