2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
9 package eu
.etaxonomy
.cdm
.database
;
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
;
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
;
22 import javax
.sql
.DataSource
;
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
;
34 import com
.mchange
.v2
.c3p0
.ComboPooledDataSource
;
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
;
45 * Class to access a CdmDataSource which is stored in datasources.xml
47 public class CdmPersistentDataSource
48 extends CdmDataSourceBase
49 implements ICdmPersistentSource
{
51 @SuppressWarnings("unused")
52 private static final Logger logger
= LogManager
.getLogger();
54 public static final String DATASOURCE_BEAN_POSTFIX
= "DataSource";
56 private String beanName
;
58 private String database
;
61 * This is strictly a <String, String> list of properties
63 private Properties cdmSourceProperties
;
65 private List
<Attribute
> cdmSourceAttributes
;
68 * The Datasource class that Spring will use to set up the connection to the database
70 private static String dataSourceClassName
= ComboPooledDataSource
.class.getName();
73 * Returns the default CdmDataSource
75 public final static CdmPersistentDataSource
NewDefaultInstance() throws DataSourceNotFoundException
{
76 return NewInstance("default");
80 * Returns the CdmDataSource named by strDataSource
81 * @param strDataSource
84 public final static CdmPersistentDataSource
NewInstance(String dataSourceName
) throws DataSourceNotFoundException
{
85 if (exists(dataSourceName
)){
86 return new CdmPersistentDataSource(dataSourceName
);
88 throw new DataSourceNotFoundException("Datasource not found: " + dataSourceName
);
93 * Private Constructor. Use NewXXX factory methods for creating a new instance of CdmDataSource!
94 * @param strDataSource
96 private CdmPersistentDataSource(String strDataSource
){
97 setName(strDataSource
);
98 loadSource(strDataSource
);
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();
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
);
120 if(getCdmSourceProperty(CdmSourceProperties
.SERVER
) == null){
121 String server
= dbType
.getServerNameByConnectionString(url
);
126 if(getCdmSourceProperty(CdmSourceProperties
.PORT
) == null){
127 int port
= dbType
.getPortByConnectionString(url
);
139 public String
getBeanName() {
144 public String
getDatabase() {
149 public void setDatabase(String database
) {
150 this.database
= database
;
152 cdmSourceProperties
.put(CdmSourceProperties
.URL
.toString(), getDatabaseType().getConnectionString(this));
156 public void setServer(String server
) {
157 super.setServer(server
);
159 cdmSourceProperties
.put(CdmSourceProperties
.URL
.toString(), getDatabaseType().getConnectionString(this));
163 public void setPort(int port
) {
165 if(port
!= NULL_PORT
) {
167 cdmSourceProperties
.put(CdmSourceProperties
.URL
.toString(), getDatabaseType().getConnectionString(this));
172 public String
getFilePath() {
173 return getCdmSourceProperty(CdmSourceProperties
.FILEPATH
);
177 public H2Mode
getMode() {
178 return H2Mode
.fromString(getCdmSourceProperty(CdmSourceProperties
.MODE
));
182 public void setMode(H2Mode h2Mode
) {
183 cdmSourceProperties
.put(CdmSourceProperties
.MODE
.toString(), h2Mode
.name());
187 public String
getUsername(){
188 return getCdmSourceProperty(CdmSourceProperties
.USERNAME
);
192 public void setUsername(String username
) {
193 cdmSourceProperties
.put(CdmSourceProperties
.USERNAME
.toString(), username
);
197 public String
getPassword(){
198 return getCdmSourceProperty(CdmSourceProperties
.PASSWORD
);
202 public void setPassword(String password
) {
203 cdmSourceProperties
.put(CdmSourceProperties
.PASSWORD
.toString(), password
);
207 public DatabaseTypeEnum
getDatabaseType(){
208 String strDriverClass
= getCdmSourceProperty(CdmSourceProperties
.DRIVER_CLASS
);
209 DatabaseTypeEnum dbType
= DatabaseTypeEnum
.byDriverClass(strDriverClass
);
213 public String
getCdmSourceProperty(CdmSourceProperties property
){
214 return cdmSourceProperties
.getProperty(property
.toString(),null);
218 * Returns a BeanDefinition object of type DataSource that contains
219 * datsource properties (url, username, password, ...)
222 @SuppressWarnings("unchecked")
224 public BeanDefinition
getDatasourceBean(){
225 DatabaseTypeEnum dbtype
=
226 DatabaseTypeEnum
.byDriverClass(getCdmSourceProperty(CdmSourceProperties
.DRIVER_CLASS
));
228 AbstractBeanDefinition bd
= new RootBeanDefinition(dbtype
.getDataSourceClass());
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()));
236 if (attribute
.getName().equals("init-method")){
237 bd
.setInitMethodName(attribute
.getValue());
239 if (attribute
.getName().equals("destroy-method")){
240 bd
.setDestroyMethodName(attribute
.getValue());
242 //Attribute attribute = iterator.next();
243 //bd.setAttribute(attribute.getName(), attribute.getValue());
247 MutablePropertyValues props
= new MutablePropertyValues();
249 Enumeration
<String
> keys
= (Enumeration
)cdmSourceProperties
.keys();
250 while (keys
.hasMoreElements()){
251 String key
= keys
.nextElement();
253 props
.addPropertyValue(key
, cdmSourceProperties
.getProperty(key
));
256 bd
.setPropertyValues(props
);
261 public BeanDefinition
getHibernatePropertiesBean(DbSchemaValidation hbm2dll
){
262 HibernateConfiguration hibernateConfig
= HibernateConfiguration
.NewDefaultInstance();
263 return getHibernatePropertiesBean(hbm2dll
, hibernateConfig
);
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
);
276 public BeanDefinition
getHibernatePropertiesBean(DbSchemaValidation hbm2dll
,
277 HibernateConfiguration hibernateConfig
) {
279 if (hibernateConfig
== null){
280 hibernateConfig
= HibernateConfiguration
.NewDefaultInstance();
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();
289 //Hibernate default values
290 if (hbm2dll
== null){
291 hbm2dll
= DbSchemaValidation
.VALIDATE
;
294 return makeHibernatePropertiesBean(getDatabaseType(), hbm2dll
, showSql
, formatSql
, registerAuditing
,
295 registerSearchListener
, cacheProviderClass
, byteCodeProvider
);
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.
302 public static boolean exists(String strDataSourceName
){
303 Element bean
= CdmPersistentSourceUtils
.getCdmSourceBeanXml(strDataSourceName
, DATASOURCE_BEAN_POSTFIX
);
304 return (bean
!= null);
308 * @param strDataSourceName
312 * the updated dataSource, null if not succesful
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
);
321 * Replace the persisted datasource with another one.
322 * Used primarily for renaming a datasource.
324 * @param strDataSourceName
327 * @throws DataSourceNotFoundException
328 * @throws IllegalArgumentException
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
);
339 * @throws IllegalArgumentException
341 public static CdmPersistentDataSource
save(ICdmDataSource dataSource
) throws IllegalArgumentException
{
342 return save(dataSource
.getName(),dataSource
);
347 * @param strDataSourceName
348 * @param databaseTypeEnum
354 * @param dataSourceClass
356 * @param destroyMethod
363 private static CdmPersistentDataSource
save(String strDataSourceName
,
364 DatabaseTypeEnum databaseTypeEnum
,
370 Class
<?
extends DataSource
> dataSourceClass
,
372 String destroyMethod
,
379 int portNumber
= "".equals(port
) ? databaseTypeEnum
.getDefaultPort() : Integer
.valueOf(port
);
381 ICdmDataSource dataSource
= new CdmDataSource(databaseTypeEnum
, server
, database
, portNumber
, username
, password
, filePath
, mode
);
384 Element root
= getBeansRoot(CdmPersistentSourceUtils
.getCdmSourceInputStream());
389 Element bean
= XmlHelp
.getFirstAttributedChild(root
, "bean", "id", CdmPersistentSourceUtils
.getBeanName(strDataSourceName
, DATASOURCE_BEAN_POSTFIX
));
391 bean
.detach(); //delete old version if necessary
393 bean
= insertXmlBean(root
, CdmPersistentSourceUtils
.getBeanName(strDataSourceName
, DATASOURCE_BEAN_POSTFIX
), dataSourceClass
.getName());
395 bean
.setAttribute("lazy-init", "true");
396 if (initMethod
!= null) {bean
.setAttribute("init-method", initMethod
);}
397 if (destroyMethod
!= null) {bean
.setAttribute("destroy-method", destroyMethod
);}
400 insertXmlValueProperty(bean
, "driverClassName", databaseTypeEnum
.getDriverClassName());
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() );}
411 saveToXml(root
.getDocument(),
412 CdmPersistentSourceUtils
.getResourceDirectory(),
413 CdmPersistentXMLSource
.CDMSOURCE_FILE_NAME
,
414 XmlHelp
.prettyFormat
);
416 return NewInstance(strDataSourceName
) ;
417 } catch (DataSourceNotFoundException e
) {
418 throw new RuntimeException("Error when saving CdmPersistentDatasource", e
);
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.
426 * @param strDataSourceName
430 public static CdmPersistentDataSource
save(String strDataSourceName
,
431 ICdmDataSource dataSource
) throws IllegalArgumentException
{
433 if(dataSource
.getDatabaseType() == null){
434 throw new IllegalArgumentException("Database type not specified");
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");
444 dataSource
.getDatabaseType(),
446 getCheckedDataSourceParameter(dataSource
.getDatabase()),
447 dataSource
.getDatabaseType().getDefaultPort() + "",
448 getCheckedDataSourceParameter(dataSource
.getUsername()),
449 getCheckedDataSourceParameter(dataSource
.getPassword()),
451 null, null, null, null,
452 dataSource
.getFilePath(),
457 Class
<?
extends DataSource
> dataSourceClass
;
459 dataSourceClass
= (Class
<?
extends DataSource
>) Class
.forName(dataSourceClassName
);
460 String server
= getCheckedDataSourceParameter(dataSource
.getServer());
461 CdmPersistentDataSource persistendDatasource
= save(
463 dataSource
.getDatabaseType(),
464 getCheckedDataSourceParameter(dataSource
.getServer()),
465 getCheckedDataSourceParameter(dataSource
.getDatabase()),
466 dataSource
.getPort() + "",
467 getCheckedDataSourceParameter(dataSource
.getUsername()),
468 getCheckedDataSourceParameter(dataSource
.getPassword()),
470 null, null, null, null, null, null
473 return persistendDatasource
;
474 } catch (ClassNotFoundException e
) {
475 throw new RuntimeException("DataSourceClass not found: " + dataSourceClassName
, e
);
480 private static String
getCheckedDataSourceParameter(String parameter
) throws IllegalArgumentException
{
481 if(parameter
!= null) {
484 throw new IllegalArgumentException("Non obsolete paramater was assigned a null value: " + parameter
);
489 * Returns a list of all datasources stored in the datasource config file
490 * @return all existing data sources
492 @SuppressWarnings("unchecked")
493 static public List
<CdmPersistentDataSource
> getAllDataSources(){
494 List
<CdmPersistentDataSource
> dataSources
= new ArrayList
<>();
496 Element root
= getBeansRoot(CdmPersistentSourceUtils
.getCdmSourceInputStream());
500 List
<Element
> lsChildren
= root
.getChildren("bean", root
.getNamespace());
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
));
514 public boolean equals(Object obj
){
517 }else if (! CdmPersistentDataSource
.class.isAssignableFrom(obj
.getClass())){
520 CdmPersistentDataSource dataSource
= (CdmPersistentDataSource
)obj
;
521 return (getName() == dataSource
.getName());
526 public String
toString(){
527 if (getName() != null){
530 return super.toString();