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 String strName
= iterator
.next().getAttributeValue("name");
229 String strValue
= iterator
.next().getAttributeValue("value");
230 result
.put(strName
, strValue
);
237 * Returns a BeanDefinition object of type DriverManagerDataSource that contains
238 * datsource properties (url, username, password, ...)
241 public BeanDefinition
getDatasourceBean(){
242 DatabaseTypeEnum dbtype
= DatabaseTypeEnum
.getDatabaseEnumByDriverClass(getDbProperty(DbProperties
.DRIVER_CLASS
));
244 AbstractBeanDefinition bd
= new RootBeanDefinition(dbtype
.getDriverManagerDataSourceClass());
246 MutablePropertyValues props
= new MutablePropertyValues();
247 Properties persistentProperties
= getDbProperties();
248 Enumeration
<String
> keys
= (Enumeration
)persistentProperties
.keys();
249 while (keys
.hasMoreElements()){
250 String key
= (String
)keys
.nextElement();
251 props
.addPropertyValue(key
, persistentProperties
.getProperty(key
));
253 // props.addPropertyValue("driverClassName", dbtype.getDriverClassName());
254 // props.addPropertyValue("url", getDbProperty(DbProperties.URL));
255 // props.addPropertyValue("username", getDbProperty(DbProperties.USERNAME));
256 // props.addPropertyValue("password", getDbProperty(DbProperties.PASSWORD));
257 bd
.setPropertyValues(props
);
266 public BeanDefinition
getHibernatePropertiesBean(HBM2DDL hbm2dll
){
267 boolean showSql
= false;
268 boolean formatSql
= false;
269 Class
<?
extends CacheProvider
> cacheProviderClass
= NoCacheProvider
.class;
270 return getHibernatePropertiesBean(hbm2dll
, showSql
, formatSql
, cacheProviderClass
);
279 public BeanDefinition
getHibernatePropertiesBean(HBM2DDL hbm2dll
, Boolean showSql
, Boolean formatSql
, Class
<?
extends CacheProvider
> cacheProviderClass
){
280 //Hibernate default values
281 if (hbm2dll
== null){
282 hbm2dll
= HBM2DDL
.VALIDATE
;
284 if (showSql
== null){
287 if (formatSql
== null){
290 if (cacheProviderClass
== null){
291 cacheProviderClass
= NoCacheProvider
.class;
294 DatabaseTypeEnum dbtype
= getDatabaseType();
295 AbstractBeanDefinition bd
= new RootBeanDefinition(PropertiesFactoryBean
.class);
296 MutablePropertyValues hibernateProps
= new MutablePropertyValues();
298 Properties props
= new Properties();
299 props
.setProperty("hibernate.hbm2ddl.auto", hbm2dll
.toString());
300 props
.setProperty("hibernate.dialect", dbtype
.getHibernateDialect());
301 props
.setProperty("hibernate.cache.provider_class", cacheProviderClass
.getName());
302 props
.setProperty("hibernate.show_sql", String
.valueOf(showSql
));
303 props
.setProperty("hibernate.format_sql", String
.valueOf(formatSql
));
305 hibernateProps
.addPropertyValue("properties",props
);
306 bd
.setPropertyValues(hibernateProps
);
312 * Tests existing of the datsource in the according config file.
313 * @return true if a datasource with the given name exists in the according datasource config file.
315 public static boolean exists(String strDataSourceName
){
316 Element bean
= getDatasourceBeanXml(strDataSourceName
);
317 return (bean
!= null);
322 * Saves or updates the datasource to the datasource config file.
324 * @param strDataSourceName name of the datasource (without postfix DataSource)
325 * @param databaseTypeEnum
330 * @return the CdmDataSource, null if not successful.
332 public static CdmDataSource
save(String strDataSourceName
, DatabaseTypeEnum databaseTypeEnum
, String server
, String database
,
333 String username
, String password
){
334 return save(strDataSourceName
, databaseTypeEnum
, server
, database
,
335 databaseTypeEnum
.getDefaultPort(), username
, password
);
339 * Saves or updates the datasource to the datasource config file.
340 * @param strDataSourceName name of the datasource (without postfix DataSource)
341 * @param databaseTypeEnum
347 * @return the CdmDataSource, null if not successful.
349 public static CdmDataSource
save(String strDataSourceName
, DatabaseTypeEnum databaseTypeEnum
, String server
, String database
,
350 int port
, String username
, String password
){
351 Class
<?
extends DriverManagerDataSource
> driverManagerDataSource
= DriverManagerDataSource
.class;
352 return save(strDataSourceName
, databaseTypeEnum
, server
, database
, port
, username
, password
, driverManagerDataSource
, null, null, null, null, null);
356 public static CdmDataSource
saveLocalHsqlDb(String strDataSourceName
, String databasePath
, String databaseName
, String username
, String password
){
357 DatabaseTypeEnum databaseTypeEnum
= DatabaseTypeEnum
.HSqlDb
;
358 Class
<?
extends DriverManagerDataSource
> driverManagerDataSource
= LocalHsqldb
.class;
359 String server
= "localhost";
360 int port
= databaseTypeEnum
.getDefaultPort();
361 return save(strDataSourceName
, databaseTypeEnum
, server
, databaseName
, port
, username
, password
, driverManagerDataSource
, "init", "destroy", true, true, databasePath
);
365 private static CdmDataSource
save(String strDataSourceName
,
366 DatabaseTypeEnum databaseTypeEnum
,
372 Class
<?
extends DriverManagerDataSource
> driverManagerDataSource
,
374 String destroyMethod
,
380 Element root
= getRoot(getDataSourceInputStream());
385 Element bean
= XmlHelp
.getFirstAttributedChild(root
, "bean", "id", getBeanName(strDataSourceName
));
387 bean
.detach(); //delete old version if necessary
389 bean
= insertXmlBean(root
, getBeanName(strDataSourceName
), driverManagerDataSource
.getName());
391 bean
.setAttribute("lazy-init", "true");
392 if (initMethod
!= null) {bean
.setAttribute("init-method", initMethod
);}
393 if (destroyMethod
!= null) {bean
.setAttribute("destroy-method", destroyMethod
);}
396 insertXmlValueProperty(bean
, "driverClassName", databaseTypeEnum
.getDriverClassName());
397 insertXmlValueProperty(bean
, "url", databaseTypeEnum
.getConnectionString(server
, database
, port
));
398 if (username
!= null) {insertXmlValueProperty(bean
, "username", username
);}
399 if (password
!= null) {insertXmlValueProperty(bean
, "password", password
);}
400 if (startSilent
!= null) {insertXmlValueProperty(bean
, "startSilent", startSilent
.toString() );}
401 if (startServer
!= null) {insertXmlValueProperty(bean
, "startServer", startServer
.toString() );}
402 if (startServer
!= null) {insertXmlValueProperty(bean
, "databasePath", databasePath
);}
405 saveToXml(root
.getDocument(), getResourceDirectory(), DATASOURCE_FILE_NAME
, format
);
407 return NewInstance(strDataSourceName
) ;
408 } catch (DataSourceNotFoundException e
) {
409 logger
.error("Error when saving datasource");
416 * Deletes a dataSource
419 public static void delete (CdmDataSource dataSource
){
420 Element bean
= getDatasourceBeanXml(dataSource
.getName());
422 Document doc
= bean
.getDocument();
424 saveToXml(doc
, getDataSourceOutputStream(), format
);
430 * Returns a list of all datasources stored in the datasource config file
431 * @return all existing data sources
433 static public List
<CdmDataSource
> getAllDataSources(){
434 List
<CdmDataSource
> dataSources
= new ArrayList
<CdmDataSource
>();
436 Element root
= getRoot(getDataSourceInputStream());
440 List
<Element
> lsChildren
= root
.getChildren("bean", root
.getNamespace());
442 for (Element elBean
: lsChildren
){
443 String strId
= elBean
.getAttributeValue("id");
444 if (strId
!= null && strId
.endsWith(DATASOURCE_BEAN_POSTFIX
)){
445 strId
= strId
.replace(DATASOURCE_BEAN_POSTFIX
, "");
446 dataSources
.add(new CdmDataSource(strId
));
455 * @see java.lang.Object#toString()
457 public String
toString(){
458 if (this.dataSourceName
!= null){
459 return dataSourceName
;
468 * Returns the datasource config file input stream.
469 * @return data source config file input stream
471 static protected FileInputStream
getDataSourceInputStream(){
472 String dir
= getResourceDirectory();
473 File file
= new File(dir
+ File
.separator
+ DATASOURCE_FILE_NAME
);
474 return fileInputStream(file
);
479 * Returns the datasource config file outputStream.
480 * @return data source config file outputStream
482 static protected FileOutputStream
getDataSourceOutputStream(){
483 String dir
= getResourceDirectory();
484 File file
= new File(dir
+ File
.separator
+ DATASOURCE_FILE_NAME
);
485 return fileOutputStream(file
);
489 * Returns the jdom Element representing the data source bean in the config file.
492 private static Element
getDatasourceBeanXml(String strDataSourceName
){
493 Element root
= getRoot(getDataSourceInputStream());
497 Element xmlBean
= XmlHelp
.getFirstAttributedChild(root
, "bean", "id", getBeanName(strDataSourceName
));
498 if (xmlBean
== null){
500 logger
.debug("Unknown Element 'bean id=" +strDataSourceName
+ "' ");
506 // returns the directory containing the resources
507 private static String
getResourceDirectory(){
508 File f
= CdmApplicationUtils
.getWritableResourceDir();
512 static private FileInputStream
fileInputStream(File file
){
514 FileInputStream fis
= new FileInputStream(file
);
516 } catch (FileNotFoundException e
) {
517 logger
.warn("File " + file
== null?
"null":file
.getAbsolutePath() + " does not exist in the file system");
522 static private FileOutputStream
fileOutputStream(File file
){
524 FileOutputStream fos
= new FileOutputStream(file
);
526 } catch (FileNotFoundException e
) {
527 logger
.warn("File " + (file
== null?
"null":file
.getAbsolutePath()) + " does not exist in the file system");
534 * Filter class to define datasource file format
536 private static class DataSourceFileNameFilter
implements FilenameFilter
{
537 public boolean accept(File dir
, String name
) {
538 return (name
.endsWith(DATASOURCE_FILE_NAME
));
542 public boolean equals(Object obj
){
545 }else if (! CdmDataSource
.class.isAssignableFrom(obj
.getClass())){
548 CdmDataSource dataSource
= (CdmDataSource
)obj
;
549 return (this.dataSourceName
== dataSource
.dataSourceName
);