1 package eu
.etaxonomy
.cdm
.database
;
4 import java
.io
.FileInputStream
;
5 import java
.io
.FileNotFoundException
;
6 import java
.io
.FileOutputStream
;
7 import java
.io
.FilenameFilter
;
8 import java
.util
.ArrayList
;
9 import java
.util
.Enumeration
;
10 import java
.util
.Iterator
;
11 import java
.util
.List
;
12 import java
.util
.Properties
;
14 import org
.apache
.log4j
.Logger
;
15 import org
.hibernate
.cache
.CacheProvider
;
16 import org
.hibernate
.cache
.NoCacheProvider
;
17 import org
.jdom
.Attribute
;
18 import org
.jdom
.Document
;
19 import org
.jdom
.Element
;
20 import org
.jdom
.output
.Format
;
21 import org
.springframework
.beans
.MutablePropertyValues
;
22 import org
.springframework
.beans
.factory
.config
.BeanDefinition
;
23 import org
.springframework
.beans
.factory
.config
.PropertiesFactoryBean
;
24 import org
.springframework
.beans
.factory
.support
.AbstractBeanDefinition
;
25 import org
.springframework
.beans
.factory
.support
.RootBeanDefinition
;
26 import org
.springframework
.jdbc
.datasource
.DriverManagerDataSource
;
28 import eu
.etaxonomy
.cdm
.api
.application
.CdmApplicationUtils
;
29 import eu
.etaxonomy
.cdm
.common
.XmlHelp
;
31 import static eu
.etaxonomy
.cdm
.common
.XmlHelp
.getRoot
;
32 import static eu
.etaxonomy
.cdm
.common
.XmlHelp
.insertXmlBean
;
33 import static eu
.etaxonomy
.cdm
.common
.XmlHelp
.insertXmlValueProperty
;
34 import static eu
.etaxonomy
.cdm
.common
.XmlHelp
.saveToXml
;
38 * class to access an CdmDataSource
40 public class CdmDataSource
{
41 private static final Logger logger
= Logger
.getLogger(CdmDataSource
.class);
43 public static final String DATASOURCE_BEAN_POSTFIX
= "DataSource";
44 public final static String DATASOURCE_FILE_NAME
= "cdm.datasources.xml";
45 private final static Format format
= Format
.getPrettyFormat();
47 public enum DbProperties
{
54 public String
toString(){
57 return "driverClassName";
65 throw new IllegalArgumentException( "Unknown enumeration type" );
77 public String
toString(){
88 throw new IllegalArgumentException( "Unknown enumeration type" );
94 protected String dataSourceName
;
98 * Returns the default CdmDataSource
99 * @return the default CdmDataSource
101 public final static CdmDataSource
NewDefaultInstance(){
103 return NewInstance("default");
104 } catch (DataSourceNotFoundException e
) {
105 logger
.error("Default datasource does not exist in config file");
112 * Returns the default CdmDataSource
113 * @return the default CdmDataSource
115 public final static CdmDataSource
NewLocalHsqlInstance(){
117 return NewInstance("localDefaultHsql");
118 } catch (DataSourceNotFoundException e
) {
119 logger
.error("Local datasource does not exist in config file");
125 * Returns the CdmDataSource named by strDataSource
126 * @param strDataSource
129 public final static CdmDataSource
NewInstance(String dataSourceName
)
130 throws DataSourceNotFoundException
{
131 if (exists(dataSourceName
)){
132 return new CdmDataSource(dataSourceName
);
134 throw new DataSourceNotFoundException("Datasource not found: " + dataSourceName
);
139 * Private Constructor. Use NewXXX factory methods for creating a new instance of CdmDataSource!
140 * @param strDataSource
142 private CdmDataSource(String strDataSource
){
143 dataSourceName
= strDataSource
;
147 * Returns the name of the bean.
150 public String
getName(){
151 return dataSourceName
;
156 * Returns the name of the bean Element in the xml config file.
159 private static String
getBeanName(String name
){
160 return name
== null?
null : name
+ DATASOURCE_BEAN_POSTFIX
;
166 * Returns the database type of the data source.
167 * @return the database type of the data source. Null if the bean or the driver class property does not exist or the driver class is unknown.
169 public DatabaseTypeEnum
getDatabaseType(){
170 Element bean
= getDatasourceBeanXml(this.dataSourceName
);
174 Element driverProp
= XmlHelp
.getFirstAttributedChild(bean
, "property", "name", "driverClassName");
175 if (driverProp
== null){
176 logger
.warn("Unknown property driverClass");
179 String strDriverClass
= driverProp
.getAttributeValue("value");
180 DatabaseTypeEnum dbType
= DatabaseTypeEnum
.getDatabaseEnumByDriverClass(strDriverClass
);
188 * Returns the list of properties that are defined in the datasource
191 public List
<Attribute
> getDatasourceAttributes(){
192 List
<Attribute
> result
= new ArrayList
<Attribute
>();
193 Element bean
= getDatasourceBeanXml(this.dataSourceName
);
197 result
= bean
.getAttributes();
203 * Returns a defined property of the datasource
204 * @return the property of the data source. NULL if the datasource bean or the property does not exist.
206 public String
getDatasourceProperty(DbProperties dbProp
){
207 Element bean
= getDatasourceBeanXml(this.dataSourceName
);
211 Element elProperty
= XmlHelp
.getFirstAttributedChild(bean
, "property", "name", dbProp
.toString());
212 if (elProperty
== null){
213 logger
.warn("Unknown property: " + dbProp
.toString());
216 String strValue
= elProperty
.getAttributeValue("value");
224 * Returns the list of properties that are defined in the datasource
227 public Properties
getDatasourceProperties(){
228 Properties result
= new Properties();
229 Element bean
= getDatasourceBeanXml(this.dataSourceName
);
233 List
<Element
> elProperties
= XmlHelp
.getAttributedChildList(bean
, "property", "name");
234 Iterator
<Element
> iterator
= elProperties
.iterator();
235 while(iterator
.hasNext()){
236 Element next
= iterator
.next();
237 String strName
= next
.getAttributeValue("name");
238 String strValue
= next
.getAttributeValue("value");
239 result
.put(strName
, strValue
);
246 * Returns a BeanDefinition object of type DriverManagerDataSource that contains
247 * datsource properties (url, username, password, ...)
250 public BeanDefinition
getDatasourceBean(){
251 DatabaseTypeEnum dbtype
= DatabaseTypeEnum
.getDatabaseEnumByDriverClass(getDatasourceProperty(DbProperties
.DRIVER_CLASS
));
253 AbstractBeanDefinition bd
= new RootBeanDefinition(dbtype
.getDriverManagerDataSourceClass());
255 Iterator
<Attribute
> iterator
= getDatasourceAttributes().iterator();
256 while(iterator
.hasNext()){
257 Attribute attribute
= iterator
.next();
258 if (attribute
.getName().equals("lazy-init")){
259 bd
.setLazyInit(Boolean
.valueOf(attribute
.getValue()));
261 if (attribute
.getName().equals("init-method")){
262 bd
.setInitMethodName(attribute
.getValue());
264 if (attribute
.getName().equals("destroy-method")){
265 bd
.setDestroyMethodName(attribute
.getValue());
267 //Attribute attribute = iterator.next();
268 //bd.setAttribute(attribute.getName(), attribute.getValue());
272 MutablePropertyValues props
= new MutablePropertyValues();
273 Properties persistentProperties
= getDatasourceProperties();
274 Enumeration
<String
> keys
= (Enumeration
)persistentProperties
.keys();
275 while (keys
.hasMoreElements()){
276 String key
= (String
)keys
.nextElement();
277 props
.addPropertyValue(key
, persistentProperties
.getProperty(key
));
280 bd
.setPropertyValues(props
);
289 public BeanDefinition
getHibernatePropertiesBean(HBM2DDL hbm2dll
){
290 boolean showSql
= false;
291 boolean formatSql
= false;
292 Class
<?
extends CacheProvider
> cacheProviderClass
= NoCacheProvider
.class;
293 return getHibernatePropertiesBean(hbm2dll
, showSql
, formatSql
, cacheProviderClass
);
302 public BeanDefinition
getHibernatePropertiesBean(HBM2DDL hbm2dll
, Boolean showSql
, Boolean formatSql
, Class
<?
extends CacheProvider
> cacheProviderClass
){
303 //Hibernate default values
304 if (hbm2dll
== null){
305 hbm2dll
= HBM2DDL
.VALIDATE
;
307 if (showSql
== null){
310 if (formatSql
== null){
313 if (cacheProviderClass
== null){
314 cacheProviderClass
= NoCacheProvider
.class;
317 DatabaseTypeEnum dbtype
= getDatabaseType();
318 AbstractBeanDefinition bd
= new RootBeanDefinition(PropertiesFactoryBean
.class);
319 MutablePropertyValues hibernateProps
= new MutablePropertyValues();
321 Properties props
= new Properties();
322 props
.setProperty("hibernate.hbm2ddl.auto", hbm2dll
.toString());
323 props
.setProperty("hibernate.dialect", dbtype
.getHibernateDialect());
324 props
.setProperty("hibernate.cache.provider_class", cacheProviderClass
.getName());
325 props
.setProperty("hibernate.show_sql", String
.valueOf(showSql
));
326 props
.setProperty("hibernate.format_sql", String
.valueOf(formatSql
));
328 hibernateProps
.addPropertyValue("properties",props
);
329 bd
.setPropertyValues(hibernateProps
);
335 * Tests existing of the datsource in the according config file.
336 * @return true if a datasource with the given name exists in the according datasource config file.
338 public static boolean exists(String strDataSourceName
){
339 Element bean
= getDatasourceBeanXml(strDataSourceName
);
340 return (bean
!= null);
345 * Saves or updates the datasource to the datasource config file.
347 * @param strDataSourceName name of the datasource (without postfix DataSource)
348 * @param databaseTypeEnum
353 * @return the CdmDataSource, null if not successful.
355 public static CdmDataSource
save(String strDataSourceName
, DatabaseTypeEnum databaseTypeEnum
, String server
, String database
,
356 String username
, String password
){
357 return save(strDataSourceName
, databaseTypeEnum
, server
, database
,
358 databaseTypeEnum
.getDefaultPort(), username
, password
);
362 * Saves or updates the datasource to the datasource config file.
363 * @param strDataSourceName name of the datasource (without postfix DataSource)
364 * @param databaseTypeEnum
370 * @return the CdmDataSource, null if not successful.
372 public static CdmDataSource
save(String strDataSourceName
, DatabaseTypeEnum databaseTypeEnum
, String server
, String database
,
373 int port
, String username
, String password
){
374 Class
<?
extends DriverManagerDataSource
> driverManagerDataSource
= DriverManagerDataSource
.class;
375 return save(strDataSourceName
, databaseTypeEnum
, server
, database
, port
, username
, password
, driverManagerDataSource
, null, null, null, null, null);
379 public static CdmDataSource
saveLocalHsqlDb(String strDataSourceName
, String databasePath
, String databaseName
, String username
, String password
){
380 DatabaseTypeEnum databaseTypeEnum
= DatabaseTypeEnum
.HSqlDb
;
381 Class
<?
extends DriverManagerDataSource
> driverManagerDataSource
= LocalHsqldb
.class;
382 String server
= "localhost";
383 int port
= databaseTypeEnum
.getDefaultPort();
384 return save(strDataSourceName
, databaseTypeEnum
, server
, databaseName
, port
, username
, password
, driverManagerDataSource
, "init", "destroy", true, true, databasePath
);
388 private static CdmDataSource
save(String strDataSourceName
,
389 DatabaseTypeEnum databaseTypeEnum
,
395 Class
<?
extends DriverManagerDataSource
> driverManagerDataSource
,
397 String destroyMethod
,
403 Element root
= getRoot(getDataSourceInputStream());
408 Element bean
= XmlHelp
.getFirstAttributedChild(root
, "bean", "id", getBeanName(strDataSourceName
));
410 bean
.detach(); //delete old version if necessary
412 bean
= insertXmlBean(root
, getBeanName(strDataSourceName
), driverManagerDataSource
.getName());
414 bean
.setAttribute("lazy-init", "true");
415 if (initMethod
!= null) {bean
.setAttribute("init-method", initMethod
);}
416 if (destroyMethod
!= null) {bean
.setAttribute("destroy-method", destroyMethod
);}
419 insertXmlValueProperty(bean
, "driverClassName", databaseTypeEnum
.getDriverClassName());
420 insertXmlValueProperty(bean
, "url", databaseTypeEnum
.getConnectionString(server
, database
, port
));
421 if (username
!= null) {insertXmlValueProperty(bean
, "username", username
);}
422 if (password
!= null) {insertXmlValueProperty(bean
, "password", password
);}
423 if (startSilent
!= null) {insertXmlValueProperty(bean
, "startSilent", startSilent
.toString() );}
424 if (startServer
!= null) {insertXmlValueProperty(bean
, "startServer", startServer
.toString() );}
425 if (startServer
!= null) {insertXmlValueProperty(bean
, "databasePath", databasePath
);}
428 saveToXml(root
.getDocument(), getResourceDirectory(), DATASOURCE_FILE_NAME
, format
);
430 return NewInstance(strDataSourceName
) ;
431 } catch (DataSourceNotFoundException e
) {
432 logger
.error("Error when saving datasource");
439 * Deletes a dataSource
442 public static void delete (CdmDataSource dataSource
){
443 Element bean
= getDatasourceBeanXml(dataSource
.getName());
445 Document doc
= bean
.getDocument();
447 saveToXml(doc
, getDataSourceOutputStream(), format
);
453 * Returns a list of all datasources stored in the datasource config file
454 * @return all existing data sources
456 static public List
<CdmDataSource
> getAllDataSources(){
457 List
<CdmDataSource
> dataSources
= new ArrayList
<CdmDataSource
>();
459 Element root
= getRoot(getDataSourceInputStream());
463 List
<Element
> lsChildren
= root
.getChildren("bean", root
.getNamespace());
465 for (Element elBean
: lsChildren
){
466 String strId
= elBean
.getAttributeValue("id");
467 if (strId
!= null && strId
.endsWith(DATASOURCE_BEAN_POSTFIX
)){
468 strId
= strId
.replace(DATASOURCE_BEAN_POSTFIX
, "");
469 dataSources
.add(new CdmDataSource(strId
));
478 * @see java.lang.Object#toString()
480 public String
toString(){
481 if (this.dataSourceName
!= null){
482 return dataSourceName
;
491 * Returns the datasource config file input stream.
492 * @return data source config file input stream
494 static protected FileInputStream
getDataSourceInputStream(){
495 String dir
= getResourceDirectory();
496 File file
= new File(dir
+ File
.separator
+ DATASOURCE_FILE_NAME
);
497 return fileInputStream(file
);
502 * Returns the datasource config file outputStream.
503 * @return data source config file outputStream
505 static protected FileOutputStream
getDataSourceOutputStream(){
506 String dir
= getResourceDirectory();
507 File file
= new File(dir
+ File
.separator
+ DATASOURCE_FILE_NAME
);
508 return fileOutputStream(file
);
512 * Returns the jdom Element representing the data source bean in the config file.
515 private static Element
getDatasourceBeanXml(String strDataSourceName
){
516 FileInputStream inStream
= getDataSourceInputStream();
517 Element root
= getRoot(inStream
);
521 Element xmlBean
= XmlHelp
.getFirstAttributedChild(root
, "bean", "id", getBeanName(strDataSourceName
));
522 if (xmlBean
== null){
524 logger
.debug("Unknown Element 'bean id=" +strDataSourceName
+ "' ");
530 // returns the directory containing the resources
531 private static String
getResourceDirectory(){
532 File f
= CdmApplicationUtils
.getWritableResourceDir();
536 static private FileInputStream
fileInputStream(File file
){
538 FileInputStream fis
= new FileInputStream(file
);
540 } catch (FileNotFoundException e
) {
541 logger
.warn("File " + file
== null?
"null":file
.getAbsolutePath() + " does not exist in the file system");
546 static private FileOutputStream
fileOutputStream(File file
){
548 FileOutputStream fos
= new FileOutputStream(file
);
550 } catch (FileNotFoundException e
) {
551 logger
.warn("File " + (file
== null?
"null":file
.getAbsolutePath()) + " does not exist in the file system");
558 * Filter class to define datasource file format
560 private static class DataSourceFileNameFilter
implements FilenameFilter
{
561 public boolean accept(File dir
, String name
) {
562 return (name
.endsWith(DATASOURCE_FILE_NAME
));
566 public boolean equals(Object obj
){
569 }else if (! CdmDataSource
.class.isAssignableFrom(obj
.getClass())){
572 CdmDataSource dataSource
= (CdmDataSource
)obj
;
573 return (this.dataSourceName
== dataSource
.dataSourceName
);