Project

General

Profile

Download (17.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
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.logging.log4j.LogManager;
25
import org.apache.logging.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
    @SuppressWarnings("unused")
52
    private static final Logger logger = LogManager.getLogger(CdmPersistentDataSource.class);
53

    
54
	public static final String DATASOURCE_BEAN_POSTFIX = "DataSource";
55

    
56
	private String beanName;
57

    
58
	private String database;
59

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

    
65
	private List<Attribute> cdmSourceAttributes;
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
	 * Returns the default CdmDataSource
74
	 */
75
	public final static CdmPersistentDataSource NewDefaultInstance() throws DataSourceNotFoundException {
76
		return NewInstance("default");
77
	}
78

    
79
	/**
80
	 * Returns the CdmDataSource named by strDataSource
81
	 * @param strDataSource
82
	 * @return
83
	 */
84
	public final static CdmPersistentDataSource NewInstance(String dataSourceName) throws DataSourceNotFoundException{
85
		if (exists(dataSourceName)){
86
			return new CdmPersistentDataSource(dataSourceName);
87
		}else{
88
			throw new DataSourceNotFoundException("Datasource not found: " + dataSourceName);
89
		}
90
	}
91

    
92
	/**
93
	 * Private Constructor. Use NewXXX factory methods for creating a new instance of CdmDataSource!
94
	 * @param strDataSource
95
	 */
96
	private CdmPersistentDataSource(String strDataSource){
97
		setName(strDataSource);
98
		loadSource(strDataSource);
99
	}
100

    
101
	private void loadSource(String strDataSource) {
102
		CdmPersistentXMLSource cdmPersistentXMLSource = CdmPersistentXMLSource.NewInstance(strDataSource, DATASOURCE_BEAN_POSTFIX);
103
		if(cdmPersistentXMLSource.getElement() != null) {
104
			beanName = cdmPersistentXMLSource.getBeanName();
105
			// properties from the persistent xml file
106
			cdmSourceProperties = cdmPersistentXMLSource.getCdmSourceProperties();
107
			cdmSourceAttributes = cdmPersistentXMLSource.getCdmSourceAttributes();
108

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

    
138
	@Override
139
    public String getBeanName() {
140
		return beanName;
141
	}
142

    
143
	@Override
144
	public String getDatabase() {
145
		return database;
146
	}
147

    
148
	@Override
149
	public void setDatabase(String database) {
150
		this.database = database;
151
		//update url string
152
		cdmSourceProperties.put(CdmSourceProperties.URL.toString(), getDatabaseType().getConnectionString(this));
153
	}
154

    
155
	@Override
156
	public void setServer(String server) {
157
		super.setServer(server);
158
		//update url string
159
		cdmSourceProperties.put(CdmSourceProperties.URL.toString(), getDatabaseType().getConnectionString(this));
160
	}
161

    
162
	@Override
163
	public void setPort(int port) {
164
		super.setPort(port);
165
		if(port != NULL_PORT) {
166
			//update url string
167
			cdmSourceProperties.put(CdmSourceProperties.URL.toString(), getDatabaseType().getConnectionString(this));
168
		}
169
	}
170

    
171
	@Override
172
	public String getFilePath() {
173
		return getCdmSourceProperty(CdmSourceProperties.FILEPATH);
174
	}
175

    
176
	@Override
177
	public H2Mode getMode() {
178
		return H2Mode.fromString(getCdmSourceProperty(CdmSourceProperties.MODE));
179
	}
180

    
181
	@Override
182
	public void setMode(H2Mode h2Mode) {
183
		cdmSourceProperties.put(CdmSourceProperties.MODE.toString(), h2Mode.name());
184
	}
185

    
186
	@Override
187
	public String getUsername(){
188
		return getCdmSourceProperty(CdmSourceProperties.USERNAME);
189
	}
190

    
191
	@Override
192
	public void setUsername(String username) {
193
		cdmSourceProperties.put(CdmSourceProperties.USERNAME.toString(), username);
194
	}
195

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

    
201
	@Override
202
	public void setPassword(String password) {
203
		cdmSourceProperties.put(CdmSourceProperties.PASSWORD.toString(), password);
204
	}
205

    
206
	@Override
207
	public DatabaseTypeEnum getDatabaseType(){
208
		String strDriverClass = getCdmSourceProperty(CdmSourceProperties.DRIVER_CLASS);
209
		DatabaseTypeEnum dbType = DatabaseTypeEnum.byDriverClass(strDriverClass);
210
		return dbType;
211
	}
212

    
213
	public String getCdmSourceProperty(CdmSourceProperties property){
214
		return cdmSourceProperties.getProperty(property.toString(),null);
215
	}
216

    
217
	/**
218
	 * Returns a BeanDefinition object of type DataSource that contains
219
	 * datsource properties (url, username, password, ...)
220
	 * @return
221
	 */
222
	@SuppressWarnings("unchecked")
223
	@Override
224
	public BeanDefinition getDatasourceBean(){
225
		DatabaseTypeEnum dbtype =
226
				DatabaseTypeEnum.byDriverClass(getCdmSourceProperty(CdmSourceProperties.DRIVER_CLASS));
227

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

    
246
		//properties
247
		MutablePropertyValues props = new MutablePropertyValues();
248

    
249
		Enumeration<String> keys = (Enumeration)cdmSourceProperties.keys();
250
		while (keys.hasMoreElements()){
251
			String key = keys.nextElement();
252

    
253
			props.addPropertyValue(key, cdmSourceProperties.getProperty(key));
254
		}
255

    
256
		bd.setPropertyValues(props);
257
		return bd;
258
	}
259

    
260
	@Override
261
	public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll){
262
		HibernateConfiguration hibernateConfig = HibernateConfiguration.NewDefaultInstance();
263
        return getHibernatePropertiesBean(hbm2dll, hibernateConfig);
264
	}
265

    
266
    @Override
267
    @Deprecated
268
    public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll, Boolean showSql, Boolean formatSql,
269
            Boolean registerSearchListener, Class<? extends RegionFactory> cacheProviderClass, String byteCodeProvider){
270
        HibernateConfiguration hibernateConfig = HibernateConfiguration.NewInstance(showSql, formatSql,
271
                registerSearchListener, null, cacheProviderClass, byteCodeProvider);
272
        return this.getHibernatePropertiesBean(hbm2dll, hibernateConfig);
273
    }
274

    
275
    @Override
276
    public BeanDefinition getHibernatePropertiesBean(DbSchemaValidation hbm2dll,
277
            HibernateConfiguration hibernateConfig) {
278

    
279
        if (hibernateConfig == null){
280
            hibernateConfig = HibernateConfiguration.NewDefaultInstance();
281
        }
282
        boolean showSql = hibernateConfig.getShowSql();
283
        boolean formatSql = hibernateConfig.getFormatSql();
284
        boolean registerAuditing = hibernateConfig.getRegisterEnvers();
285
        boolean registerSearchListener = hibernateConfig.getRegisterSearch();
286
        Class<? extends RegionFactory> cacheProviderClass = hibernateConfig.getCacheProviderClass();
287
        String byteCodeProvider = hibernateConfig.getByteCodeProvider();
288

    
289
		//Hibernate default values
290
		if (hbm2dll == null){
291
			hbm2dll = DbSchemaValidation.VALIDATE;
292
		}
293

    
294
		return makeHibernatePropertiesBean(getDatabaseType(), hbm2dll, showSql, formatSql, registerAuditing,
295
		        registerSearchListener, cacheProviderClass, byteCodeProvider);
296
	}
297

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

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

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

    
336
	/**
337
	 * @param dataSource
338
	 * @return
339
	 * @throws IllegalArgumentException
340
	 */
341
	public static CdmPersistentDataSource save(ICdmDataSource dataSource)  throws IllegalArgumentException {
342
		return save(dataSource.getName(),dataSource);
343
	}
344

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

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

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

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

    
399
		//set properties
400
		insertXmlValueProperty(bean, "driverClassName", databaseTypeEnum.getDriverClassName());
401

    
402
		insertXmlValueProperty(bean, "url", databaseTypeEnum.getConnectionString(dataSource));
403
		if (username != null) {insertXmlValueProperty(bean, "username", username );}
404
		if (password != null) {insertXmlValueProperty(bean, "password", password );}
405
		if (startSilent != null) {insertXmlValueProperty(bean, "startSilent", startSilent.toString() );}
406
		if (startServer != null) {insertXmlValueProperty(bean, "startServer", startServer.toString() );}
407
		if (filePath != null) {insertXmlValueProperty(bean, "filePath", filePath );}
408
		if (mode != null) {insertXmlValueProperty(bean, "mode", mode.toString() );}
409

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

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

    
433
		if(dataSource.getDatabaseType() == null){
434
			throw new IllegalArgumentException("Database type not specified");
435
		}
436

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

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

    
473
				return persistendDatasource;
474
			} catch (ClassNotFoundException e) {
475
			    throw new RuntimeException("DataSourceClass not found: " + dataSourceClassName, e);
476
			}
477
		}
478
	}
479

    
480
	private static String getCheckedDataSourceParameter(String parameter) throws IllegalArgumentException{
481
		if(parameter != null) {
482
			return parameter;
483
		} else {
484
			throw new IllegalArgumentException("Non obsolete paramater was assigned a null value: " + parameter);
485
		}
486
	}
487

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

    
496
		Element root = getBeansRoot(CdmPersistentSourceUtils.getCdmSourceInputStream());
497
		if (root == null){
498
			return null;
499
		}else{
500
	    	List<Element> lsChildren  = root.getChildren("bean", root.getNamespace());
501

    
502
	    	for (Element elBean : lsChildren){
503
	    		String strId = elBean.getAttributeValue("id");
504
	    		if (strId != null && strId.endsWith(DATASOURCE_BEAN_POSTFIX)){
505
	    			strId = strId.replace(DATASOURCE_BEAN_POSTFIX, "");
506
	    			dataSources.add(new CdmPersistentDataSource(strId));
507
	    		}
508
	    	}
509
		}
510
		return dataSources;
511
	}
512

    
513
	@Override
514
	public boolean equals(Object obj){
515
		if (obj == null){
516
			return false;
517
		}else if (! CdmPersistentDataSource.class.isAssignableFrom(obj.getClass())){
518
			return false;
519
		}else{
520
			CdmPersistentDataSource dataSource = (CdmPersistentDataSource)obj;
521
			return (getName() == dataSource.getName());
522
		}
523
	}
524

    
525
	@Override
526
	public String toString(){
527
		if (getName() != null){
528
			return getName();
529
		}else{
530
			return super.toString();
531
		}
532
	}
533
}
(4-4/21)