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
.HashMap
;
11 import java
.util
.Iterator
;
12 import java
.util
.List
;
14 import java
.util
.Properties
;
16 import org
.apache
.log4j
.Logger
;
17 import org
.hibernate
.cache
.CacheProvider
;
18 import org
.hibernate
.cache
.NoCacheProvider
;
19 import org
.jdom
.Attribute
;
20 import org
.jdom
.Document
;
21 import org
.jdom
.Element
;
22 import org
.jdom
.output
.Format
;
23 import org
.springframework
.beans
.MutablePropertyValues
;
24 import org
.springframework
.beans
.factory
.config
.BeanDefinition
;
25 import org
.springframework
.beans
.factory
.config
.PropertiesFactoryBean
;
26 import org
.springframework
.beans
.factory
.support
.AbstractBeanDefinition
;
27 import org
.springframework
.beans
.factory
.support
.RootBeanDefinition
;
28 import org
.springframework
.jdbc
.datasource
.DriverManagerDataSource
;
30 import eu
.etaxonomy
.cdm
.api
.application
.CdmApplicationUtils
;
31 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
32 import eu
.etaxonomy
.cdm
.common
.XmlHelp
;
34 import static eu
.etaxonomy
.cdm
.common
.XmlHelp
.getFirstAttributedChild
;
35 import static eu
.etaxonomy
.cdm
.common
.XmlHelp
.getOrAddChild
;
36 import static eu
.etaxonomy
.cdm
.common
.XmlHelp
.getRoot
;
37 import static eu
.etaxonomy
.cdm
.common
.XmlHelp
.insertXmlBean
;
38 import static eu
.etaxonomy
.cdm
.common
.XmlHelp
.insertXmlRefProperty
;
39 import static eu
.etaxonomy
.cdm
.common
.XmlHelp
.insertXmlValueProperty
;
40 import static eu
.etaxonomy
.cdm
.common
.XmlHelp
.saveToXml
;
44 * class to access an CdmDataSource
46 public class CdmDataSource
{
47 private static final Logger logger
= Logger
.getLogger(CdmDataSource
.class);
49 public static final String DATASOURCE_BEAN_POSTFIX
= "DataSource";
50 public final static String DATASOURCE_FILE_NAME
= "cdm.datasources.xml";
51 private final static Format format
= Format
.getPrettyFormat();
53 public enum DbProperties
{
60 public String
toString(){
63 return "driverClassName";
71 throw new IllegalArgumentException( "Unknown enumeration type" );
83 public String
toString(){
94 throw new IllegalArgumentException( "Unknown enumeration type" );
100 protected String dataSourceName
;
104 * Returns the default CdmDataSource
105 * @return the default CdmDataSource
107 public final static CdmDataSource
NewDefaultInstance(){
109 return NewInstance("default");
110 } catch (DataSourceNotFoundException e
) {
111 logger
.error("Default datasource does not exist in config file");
118 * Returns the default CdmDataSource
119 * @return the default CdmDataSource
121 public final static CdmDataSource
NewLocalHsqlInstance(){
123 return NewInstance("localDefaultHsql");
124 } catch (DataSourceNotFoundException e
) {
125 logger
.error("Local datasource does not exist in config file");
131 * Returns the CdmDataSource named by strDataSource
132 * @param strDataSource
135 public final static CdmDataSource
NewInstance(String dataSourceName
)
136 throws DataSourceNotFoundException
{
137 if (exists(dataSourceName
)){
138 return new CdmDataSource(dataSourceName
);
140 throw new DataSourceNotFoundException("Datasource not found: " + dataSourceName
);
145 * Private Constructor. Use NewXXX factory methods for creating a new instance of CdmDataSource!
146 * @param strDataSource
148 private CdmDataSource(String strDataSource
){
149 dataSourceName
= strDataSource
;
153 * Returns the name of the bean.
156 public String
getName(){
157 return dataSourceName
;
162 * Returns the name of the bean Element in the xml config file.
165 private static String
getBeanName(String name
){
166 return name
== null?
null : name
+ DATASOURCE_BEAN_POSTFIX
;
172 * Returns the database type of the data source.
173 * @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.
175 public DatabaseTypeEnum
getDatabaseType(){
176 Element bean
= getDatasourceBeanXml(this.dataSourceName
);
180 Element driverProp
= XmlHelp
.getFirstAttributedChild(bean
, "property", "name", "driverClassName");
181 if (driverProp
== null){
182 logger
.warn("Unknown property driverClass");
185 String strDriverClass
= driverProp
.getAttributeValue("value");
186 DatabaseTypeEnum dbType
= DatabaseTypeEnum
.getDatabaseEnumByDriverClass(strDriverClass
);
195 * Returns a defined property of the datasource
196 * @return the property of the data source. NULL if the datasource bean or the property does not exist.
198 public String
getDbProperty(DbProperties dbProp
){
199 Element bean
= getDatasourceBeanXml(this.dataSourceName
);
203 Element elProperty
= XmlHelp
.getFirstAttributedChild(bean
, "property", "name", dbProp
.toString());
204 if (elProperty
== null){
205 logger
.warn("Unknown property: " + dbProp
.toString());
208 String strValue
= elProperty
.getAttributeValue("value");
216 * Returns the list of properties that are defined in the datasource
219 public Properties
getDbProperties(){
220 Properties result
= new Properties();
221 Element bean
= getDatasourceBeanXml(this.dataSourceName
);
225 List
<Element
> elProperties
= XmlHelp
.getAttributedChildList(bean
, "property", "name");
226 Iterator
<Element
> iterator
= elProperties
.iterator();
227 while(iterator
.hasNext()){
228 Element next
= iterator
.next();
229 String strName
= next
.getAttributeValue("name");
230 String strValue
= next
.getAttributeValue("value");
231 result
.put(strName
, strValue
);
238 * Returns a BeanDefinition object of type DriverManagerDataSource that contains
239 * datsource properties (url, username, password, ...)
242 public BeanDefinition
getDatasourceBean(){
243 DatabaseTypeEnum dbtype
= DatabaseTypeEnum
.getDatabaseEnumByDriverClass(getDbProperty(DbProperties
.DRIVER_CLASS
));
245 AbstractBeanDefinition bd
= new RootBeanDefinition(dbtype
.getDriverManagerDataSourceClass());
247 MutablePropertyValues props
= new MutablePropertyValues();
248 Properties persistentProperties
= getDbProperties();
249 Enumeration
<String
> keys
= (Enumeration
)persistentProperties
.keys();
250 while (keys
.hasMoreElements()){
251 String key
= (String
)keys
.nextElement();
252 props
.addPropertyValue(key
, persistentProperties
.getProperty(key
));
254 // props.addPropertyValue("driverClassName", dbtype.getDriverClassName());
255 // props.addPropertyValue("url", getDbProperty(DbProperties.URL));
256 // props.addPropertyValue("username", getDbProperty(DbProperties.USERNAME));
257 // props.addPropertyValue("password", getDbProperty(DbProperties.PASSWORD));
258 bd
.setPropertyValues(props
);
267 public BeanDefinition
getHibernatePropertiesBean(HBM2DDL hbm2dll
){
268 boolean showSql
= false;
269 boolean formatSql
= false;
270 Class
<?
extends CacheProvider
> cacheProviderClass
= NoCacheProvider
.class;
271 return getHibernatePropertiesBean(hbm2dll
, showSql
, formatSql
, cacheProviderClass
);
280 public BeanDefinition
getHibernatePropertiesBean(HBM2DDL hbm2dll
, Boolean showSql
, Boolean formatSql
, Class
<?
extends CacheProvider
> cacheProviderClass
){
281 //Hibernate default values
282 if (hbm2dll
== null){
283 hbm2dll
= HBM2DDL
.VALIDATE
;
285 if (showSql
== null){
288 if (formatSql
== null){
291 if (cacheProviderClass
== null){
292 cacheProviderClass
= NoCacheProvider
.class;
295 DatabaseTypeEnum dbtype
= getDatabaseType();
296 AbstractBeanDefinition bd
= new RootBeanDefinition(PropertiesFactoryBean
.class);
297 MutablePropertyValues hibernateProps
= new MutablePropertyValues();
299 Properties props
= new Properties();
300 props
.setProperty("hibernate.hbm2ddl.auto", hbm2dll
.toString());
301 props
.setProperty("hibernate.dialect", dbtype
.getHibernateDialect());
302 props
.setProperty("hibernate.cache.provider_class", cacheProviderClass
.getName());
303 props
.setProperty("hibernate.show_sql", String
.valueOf(showSql
));
304 props
.setProperty("hibernate.format_sql", String
.valueOf(formatSql
));
306 hibernateProps
.addPropertyValue("properties",props
);
307 bd
.setPropertyValues(hibernateProps
);
313 * Tests existing of the datsource in the according config file.
314 * @return true if a datasource with the given name exists in the according datasource config file.
316 public static boolean exists(String strDataSourceName
){
317 Element bean
= getDatasourceBeanXml(strDataSourceName
);
318 return (bean
!= null);
323 * Saves or updates the datasource to the datasource config file.
325 * @param strDataSourceName name of the datasource (without postfix DataSource)
326 * @param databaseTypeEnum
331 * @return the CdmDataSource, null if not successful.
333 public static CdmDataSource
save(String strDataSourceName
, DatabaseTypeEnum databaseTypeEnum
, String server
, String database
,
334 String username
, String password
){
335 return save(strDataSourceName
, databaseTypeEnum
, server
, database
,
336 databaseTypeEnum
.getDefaultPort(), username
, password
);
340 * Saves or updates the datasource to the datasource config file.
341 * @param strDataSourceName name of the datasource (without postfix DataSource)
342 * @param databaseTypeEnum
348 * @return the CdmDataSource, null if not successful.
350 public static CdmDataSource
save(String strDataSourceName
, DatabaseTypeEnum databaseTypeEnum
, String server
, String database
,
351 int port
, String username
, String password
){
352 Class
<?
extends DriverManagerDataSource
> driverManagerDataSource
= DriverManagerDataSource
.class;
353 return save(strDataSourceName
, databaseTypeEnum
, server
, database
, port
, username
, password
, driverManagerDataSource
, null, null, null, null, null);
357 public static CdmDataSource
saveLocalHsqlDb(String strDataSourceName
, String databasePath
, String databaseName
, String username
, String password
){
358 DatabaseTypeEnum databaseTypeEnum
= DatabaseTypeEnum
.HSqlDb
;
359 Class
<?
extends DriverManagerDataSource
> driverManagerDataSource
= LocalHsqldb
.class;
360 String server
= "localhost";
361 int port
= databaseTypeEnum
.getDefaultPort();
362 return save(strDataSourceName
, databaseTypeEnum
, server
, databaseName
, port
, username
, password
, driverManagerDataSource
, "init", "destroy", true, true, databasePath
);
366 private static CdmDataSource
save(String strDataSourceName
,
367 DatabaseTypeEnum databaseTypeEnum
,
373 Class
<?
extends DriverManagerDataSource
> driverManagerDataSource
,
375 String destroyMethod
,
381 Element root
= getRoot(getDataSourceInputStream());
386 Element bean
= XmlHelp
.getFirstAttributedChild(root
, "bean", "id", getBeanName(strDataSourceName
));
388 bean
.detach(); //delete old version if necessary
390 bean
= insertXmlBean(root
, getBeanName(strDataSourceName
), driverManagerDataSource
.getName());
392 bean
.setAttribute("lazy-init", "true");
393 if (initMethod
!= null) {bean
.setAttribute("init-method", initMethod
);}
394 if (destroyMethod
!= null) {bean
.setAttribute("destroy-method", destroyMethod
);}
397 insertXmlValueProperty(bean
, "driverClassName", databaseTypeEnum
.getDriverClassName());
398 insertXmlValueProperty(bean
, "url", databaseTypeEnum
.getConnectionString(server
, database
, port
));
399 if (username
!= null) {insertXmlValueProperty(bean
, "username", username
);}
400 if (password
!= null) {insertXmlValueProperty(bean
, "password", password
);}
401 if (startSilent
!= null) {insertXmlValueProperty(bean
, "startSilent", startSilent
.toString() );}
402 if (startServer
!= null) {insertXmlValueProperty(bean
, "startServer", startServer
.toString() );}
403 if (startServer
!= null) {insertXmlValueProperty(bean
, "databasePath", databasePath
);}
406 saveToXml(root
.getDocument(), getResourceDirectory(), DATASOURCE_FILE_NAME
, format
);
408 return NewInstance(strDataSourceName
) ;
409 } catch (DataSourceNotFoundException e
) {
410 logger
.error("Error when saving datasource");
417 * Deletes a dataSource
420 public static void delete (CdmDataSource dataSource
){
421 Element bean
= getDatasourceBeanXml(dataSource
.getName());
423 Document doc
= bean
.getDocument();
425 saveToXml(doc
, getDataSourceOutputStream(), format
);
431 * Returns a list of all datasources stored in the datasource config file
432 * @return all existing data sources
434 static public List
<CdmDataSource
> getAllDataSources(){
435 List
<CdmDataSource
> dataSources
= new ArrayList
<CdmDataSource
>();
437 Element root
= getRoot(getDataSourceInputStream());
441 List
<Element
> lsChildren
= root
.getChildren("bean", root
.getNamespace());
443 for (Element elBean
: lsChildren
){
444 String strId
= elBean
.getAttributeValue("id");
445 if (strId
!= null && strId
.endsWith(DATASOURCE_BEAN_POSTFIX
)){
446 strId
= strId
.replace(DATASOURCE_BEAN_POSTFIX
, "");
447 dataSources
.add(new CdmDataSource(strId
));
456 * @see java.lang.Object#toString()
458 public String
toString(){
459 if (this.dataSourceName
!= null){
460 return dataSourceName
;
469 * Returns the datasource config file input stream.
470 * @return data source config file input stream
472 static protected FileInputStream
getDataSourceInputStream(){
473 String dir
= getResourceDirectory();
474 File file
= new File(dir
+ File
.separator
+ DATASOURCE_FILE_NAME
);
475 return fileInputStream(file
);
480 * Returns the datasource config file outputStream.
481 * @return data source config file outputStream
483 static protected FileOutputStream
getDataSourceOutputStream(){
484 String dir
= getResourceDirectory();
485 File file
= new File(dir
+ File
.separator
+ DATASOURCE_FILE_NAME
);
486 return fileOutputStream(file
);
490 * Returns the jdom Element representing the data source bean in the config file.
493 private static Element
getDatasourceBeanXml(String strDataSourceName
){
494 Element root
= getRoot(getDataSourceInputStream());
498 Element xmlBean
= XmlHelp
.getFirstAttributedChild(root
, "bean", "id", getBeanName(strDataSourceName
));
499 if (xmlBean
== null){
501 logger
.debug("Unknown Element 'bean id=" +strDataSourceName
+ "' ");
507 // returns the directory containing the resources
508 private static String
getResourceDirectory(){
509 File f
= CdmApplicationUtils
.getWritableResourceDir();
513 static private FileInputStream
fileInputStream(File file
){
515 FileInputStream fis
= new FileInputStream(file
);
517 } catch (FileNotFoundException e
) {
518 logger
.warn("File " + file
== null?
"null":file
.getAbsolutePath() + " does not exist in the file system");
523 static private FileOutputStream
fileOutputStream(File file
){
525 FileOutputStream fos
= new FileOutputStream(file
);
527 } catch (FileNotFoundException e
) {
528 logger
.warn("File " + (file
== null?
"null":file
.getAbsolutePath()) + " does not exist in the file system");
535 * Filter class to define datasource file format
537 private static class DataSourceFileNameFilter
implements FilenameFilter
{
538 public boolean accept(File dir
, String name
) {
539 return (name
.endsWith(DATASOURCE_FILE_NAME
));
543 public boolean equals(Object obj
){
546 }else if (! CdmDataSource
.class.isAssignableFrom(obj
.getClass())){
549 CdmDataSource dataSource
= (CdmDataSource
)obj
;
550 return (this.dataSourceName
== dataSource
.dataSourceName
);