From cd3f5dcb49ae93a121f9e63400dfe1ce07b91e52 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Andreas=20M=C3=BCller?= Date: Wed, 23 Jan 2008 17:34:54 +0000 Subject: [PATCH] --- .gitattributes | 2 + .../etaxonomy/cdm/database/CdmDataSource.java | 434 ++++++++++++++++++ .../etaxonomy/cdm/database/LocalHsqldb.java | 256 +++++++++++ 3 files changed, 692 insertions(+) create mode 100644 cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/CdmDataSource.java create mode 100644 cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/LocalHsqldb.java diff --git a/.gitattributes b/.gitattributes index ad16227bc0..c3faf426b3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -253,8 +253,10 @@ cdmlib-model/src/test/java/eu/etaxonomy/cdm/test/function/TestModel.java -text cdmlib-model/src/test/java/eu/etaxonomy/cdm/test/suite/CdmTestSuite.java -text cdmlib-model/src/test/java/eu/etaxonomy/cdm/test/unit/CdmUnitTestBase.java -text cdmlib-persistence/pom.xml -text +cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/CdmDataSource.java -text cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/DataSourceNotFoundException.java -text cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/DatabaseTypeEnum.java -text +cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/LocalHsqldb.java -text cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/types/AbstractDatabaseType.java -text cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/types/Db2DatabaseType.java -text cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/types/HSqlDbDatabaseType.java -text diff --git a/cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/CdmDataSource.java b/cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/CdmDataSource.java new file mode 100644 index 0000000000..761b76dde2 --- /dev/null +++ b/cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/CdmDataSource.java @@ -0,0 +1,434 @@ +package eu.etaxonomy.cdm.database; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FilenameFilter; +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.jdom.Attribute; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.output.Format; +import org.springframework.jdbc.datasource.DriverManagerDataSource; + +import eu.etaxonomy.cdm.api.application.CdmApplicationUtils; +import eu.etaxonomy.cdm.common.CdmUtils; +import eu.etaxonomy.cdm.common.XmlHelp; + +import static eu.etaxonomy.cdm.common.XmlHelp.getFirstAttributedChild; +import static eu.etaxonomy.cdm.common.XmlHelp.getOrAddChild; +import static eu.etaxonomy.cdm.common.XmlHelp.getRoot; +import static eu.etaxonomy.cdm.common.XmlHelp.insertXmlBean; +import static eu.etaxonomy.cdm.common.XmlHelp.insertXmlRefProperty; +import static eu.etaxonomy.cdm.common.XmlHelp.insertXmlValueProperty; +import static eu.etaxonomy.cdm.common.XmlHelp.saveToXml; + + +/** + * class to access an CdmDataSource + */ +public class CdmDataSource { + private static final Logger logger = Logger.getLogger(CdmDataSource.class); + + public static final String DATASOURCE_BEAN_POSTFIX = "DataSource"; + public static final String SESSION_FACTORY_FILE = "sessionfactory.xml"; + public final static String DATASOURCE_FILE_NAME = "cdm.datasource.xml"; + public final static String APPLICATION_CONTEXT_FILE_NAME = "applicationContext.xml"; + private final static Format format = Format.getPrettyFormat(); + + //name + protected String dataSourceName; + + + /** + * Returns the default CdmDataSource + * @return the default CdmDataSource + */ + public final static CdmDataSource NewDefaultInstance(){ + try { + return NewInstance("default"); + } catch (DataSourceNotFoundException e) { + logger.error("Default datasource does not exist in config file"); + return null; + } + } + + + /** + * Returns the default CdmDataSource + * @return the default CdmDataSource + */ + public final static CdmDataSource NewLocalHsqlInstance(){ + try { + return NewInstance("localDefaultHsql"); + } catch (DataSourceNotFoundException e) { + logger.error("Local datasource does not exist in config file"); + return null; + } + } + + /** + * Returns the CdmDataSource named by strDataSource + * @param strDataSource + * @return + */ + public final static CdmDataSource NewInstance(String dataSourceName) + throws DataSourceNotFoundException{ + if (exists(dataSourceName)){ + return new CdmDataSource(dataSourceName); + }else{ + throw new DataSourceNotFoundException("Datasource not found: " + dataSourceName); + } + } + + /** + * Private Constructor. Use NewXXX factory methods for creating a new instance of CdmDataSource! + * @param strDataSource + */ + private CdmDataSource(String strDataSource){ + dataSourceName = strDataSource; + } + + /** + * Returns the name of the bean. + * @return + */ + public String getName(){ + return dataSourceName; + } + + + /** + * Returns the name of the bean Element in the xml config file. + * @return bean name + */ + private static String getBeanName(String name){ + return name == null? null : name + DATASOURCE_BEAN_POSTFIX; + } + + + + /** + * Updates the session factory config file for using this database. + * Writes the datasource property and the dialect property into the session factory. + * @param hibernateHbm2ddlAuto value for the hibernate property hibernate.hbm2dll.auto . If null the properties is not changed. Possible values are 'validate', 'create', 'update' and 'create-drop'. + * @return true if successful. + */ + public boolean updateSessionFactory(String hibernateHbm2ddlAuto){ + Element root = getRoot(getSessionFactoryInputStream()); + if (root == null){ + return false; + } + //get sessionFactory bean + Element sessionFactoryBean = getFirstAttributedChild(root, "bean", "id", "sessionFactory"); + //sessionFactory must exist + if (sessionFactoryBean == null){ + return false; + } + + //set dataSource property + Element dataSourceProperty = getFirstAttributedChild(sessionFactoryBean, "property", "name", "dataSource"); + if (dataSourceProperty == null){ + dataSourceProperty = insertXmlRefProperty(sessionFactoryBean, "dataSource", getBeanName(this.dataSourceName)); + } + Attribute attrRef = dataSourceProperty.getAttribute("ref"); + if (attrRef == null){ + dataSourceProperty.setAttribute("ref", getBeanName(this.dataSourceName)); + }else{ + attrRef.setValue(getBeanName(this.dataSourceName)); + } + + //set dialect + Element elHibernateProperties = getOrAddChild(sessionFactoryBean, "property", "name", "hibernateProperties"); + Element props = getOrAddChild(elHibernateProperties, "props", null, null); + Element elDialectProp = getOrAddChild(props, "prop", "key", "hibernate.dialect"); + elDialectProp.setText(this.getDatabaseType().getHibernateDialect()); + + //set hibernateHbm2ddlAuto + if (hibernateHbm2ddlAuto != null){ + if (hibernateHbm2ddlAuto != "validate" && hibernateHbm2ddlAuto != "create" && hibernateHbm2ddlAuto != "update " && hibernateHbm2ddlAuto != "create-drop" ){ + logger.warn("Invalid value " + hibernateHbm2ddlAuto + " for property hibernate.hbm2ddl.auto"); + } + Element elHbm2ddlAutoProp = getOrAddChild(props, "prop", "key", "hibernate.hbm2ddl.auto"); + elHbm2ddlAutoProp.setText(hibernateHbm2ddlAuto); + } + + //save + saveToXml(root.getDocument(), getSessionFactoryOutputStream() , format ); + return true; + } + + + /** + * Returns the database type of the data source. + * @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. + */ + public DatabaseTypeEnum getDatabaseType(){ + Element bean = getDatasourceBeanXml(this.dataSourceName); + if (bean == null){ + return null; + }else{ + Element driverProp = XmlHelp.getFirstAttributedChild(bean, "property", "name", "driverClassName"); + if (driverProp == null){ + logger.warn("Unknown property driverClass"); + return null; + }else{ + String strDriverClass = driverProp.getAttributeValue("value"); + DatabaseTypeEnum dbType = DatabaseTypeEnum.getDatabaseEnumByDriverClass(strDriverClass); + return dbType; + } + } + } + + /** + * Tests existing of the datsource in the according config file. + * @return true if a datasource with the given name exists in the according datasource config file. + */ + public static boolean exists(String strDataSourceName){ + Element bean = getDatasourceBeanXml(strDataSourceName); + return (bean != null); + } + + + /** + * Saves or updates the datasource to the datasource config file. + * Uses default port. + * @param strDataSourceName name of the datasource (without postfix DataSource) + * @param databaseTypeEnum + * @param server + * @param database + * @param username + * @param password + * @return the CdmDataSource, null if not successful. + */ + public static CdmDataSource save(String strDataSourceName, DatabaseTypeEnum databaseTypeEnum, String server, String database, + String username, String password){ + return save(strDataSourceName, databaseTypeEnum, server, database, + databaseTypeEnum.getDefaultPort(), username, password); + } + + /** + * Saves or updates the datasource to the datasource config file. + * @param strDataSourceName name of the datasource (without postfix DataSource) + * @param databaseTypeEnum + * @param server + * @param database + * @param port + * @param username + * @param password + * @return the CdmDataSource, null if not successful. + */ + public static CdmDataSource save(String strDataSourceName, DatabaseTypeEnum databaseTypeEnum, String server, String database, + int port, String username, String password){ + Class driverManagerDataSource = DriverManagerDataSource.class; + return save(strDataSourceName, databaseTypeEnum, server, database, port, username, password, driverManagerDataSource, null, null, null, null, null); + } + + + public static CdmDataSource saveLocalHsqlDb(String strDataSourceName, String databasePath, String databaseName, String username, String password){ + DatabaseTypeEnum databaseTypeEnum = DatabaseTypeEnum.HSqlDb; + Class driverManagerDataSource = LocalHsqldb.class; + String server = "localhost"; + int port = databaseTypeEnum.getDefaultPort(); + return save(strDataSourceName, databaseTypeEnum, server, databaseName, port, username, password, driverManagerDataSource, "init", "destroy", true, true, databasePath); + } + + // + private static CdmDataSource save(String strDataSourceName, + DatabaseTypeEnum databaseTypeEnum, + String server, + String database, + int port, + String username, + String password, + Class driverManagerDataSource, + String initMethod, + String destroyMethod, + Boolean startSilent, + Boolean startServer, + String databasePath + ){ + //root + Element root = getRoot(getDataSourceInputStream()); + if (root == null){ + return null; + } + //bean + Element bean = XmlHelp.getFirstAttributedChild(root, "bean", "id", getBeanName(strDataSourceName)); + if (bean != null){ + bean.detach(); //delete old version if necessary + } + bean = insertXmlBean(root, getBeanName(strDataSourceName), driverManagerDataSource.getName()); + //attributes + bean.setAttribute("lazy-init", "true"); + if (initMethod != null) {bean.setAttribute("init-method", initMethod);} + if (destroyMethod != null) {bean.setAttribute("destroy-method", destroyMethod);} + + //set properties + insertXmlValueProperty(bean, "driverClassName", databaseTypeEnum.getDriverClassName()); + insertXmlValueProperty(bean, "url", databaseTypeEnum.getConnectionString(server, database, port)); + if (username != null) {insertXmlValueProperty(bean, "username", username );} + if (startSilent != null) {insertXmlValueProperty(bean, "startSilent", startSilent.toString() );} + if (startServer != null) {insertXmlValueProperty(bean, "startServer", startServer.toString() );} + if (startServer != null) {insertXmlValueProperty(bean, "databasePath", databasePath );} + + //save + saveToXml(root.getDocument(), getResourceDirectory(), DATASOURCE_FILE_NAME, format ); + try { + return NewInstance(strDataSourceName) ; + } catch (DataSourceNotFoundException e) { + logger.error("Error when saving datasource"); + return null; + } + } + + + /** + * Deletes a dataSource + * @param dataSource + */ + public static void delete (CdmDataSource dataSource){ + Element bean = getDatasourceBeanXml(dataSource.getName()); + if (bean != null){ + Document doc = bean.getDocument(); + bean.detach(); + saveToXml(doc, getDataSourceOutputStream(), format ); + } + } + + + /** + * Returns a list of all datasources stored in the datasource config file + * @return all existing data sources + */ + static public List getAllDataSources(){ + List dataSources = new ArrayList(); + + Element root = getRoot(getDataSourceInputStream()); + if (root == null){ + return null; + }else{ + List lsChildren = root.getChildren("bean", root.getNamespace()); + + for (Element elBean : lsChildren){ + String strId = elBean.getAttributeValue("id"); + if (strId != null && strId.endsWith(DATASOURCE_BEAN_POSTFIX)){ + strId = strId.replace(DATASOURCE_BEAN_POSTFIX, ""); + dataSources.add(new CdmDataSource(strId)); + } + } + } + return dataSources; + } + + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString(){ + if (this.dataSourceName != null){ + return dataSourceName; + }else{ + return null; + } + } + + + + /** + * Returns the datasource config file input stream. + * @return data source config file input stream + */ + static protected FileInputStream getDataSourceInputStream(){ + String dir = getResourceDirectory(); + File file = new File(dir + File.separator + DATASOURCE_FILE_NAME); + return fileInputStream(file); + } + + + /** + * Returns the datasource config file outputStream. + * @return data source config file outputStream + */ + static protected FileOutputStream getDataSourceOutputStream(){ + String dir = getResourceDirectory(); + File file = new File(dir + File.separator + DATASOURCE_FILE_NAME); + return fileOutputStream(file); + } + + /** + * Returns the jdom Element representing the data source bean in the config file. + * @return + */ + private static Element getDatasourceBeanXml(String strDataSourceName){ + Element root = getRoot(getDataSourceInputStream()); + if (root == null){ + return null; + }else{ + Element xmlBean = XmlHelp.getFirstAttributedChild(root, "bean", "id", getBeanName(strDataSourceName)); + if (xmlBean == null){logger.warn("Unknown Element 'bean' ");}; + return xmlBean; + } + } + + // returns the directory containing the resources + private static String getResourceDirectory(){ + File f = CdmApplicationUtils.getWritableResourceDir(); + return f.getPath(); + } + + /** + * Returns the session factory config file input stream. + * @return session factory config file + */ + private FileInputStream getSessionFactoryInputStream(){ + String dir = getResourceDirectory(); + File file = new File(dir + File.separator + SESSION_FACTORY_FILE); + return fileInputStream(file); + } + + /** + * Returns the session factory output stream. + * @return + */ + private FileOutputStream getSessionFactoryOutputStream(){ + String dir = getResourceDirectory(); + File file = new File(dir + File.separator + SESSION_FACTORY_FILE); + return fileOutputStream(file); + } + + + static private FileInputStream fileInputStream(File file){ + try { + FileInputStream fis = new FileInputStream(file); + return fis; + } catch (FileNotFoundException e) { + logger.warn("File " + file == null?"null":file.getAbsolutePath() + " does not exist in the file system"); + return null; + } + } + + static private FileOutputStream fileOutputStream(File file){ + try { + FileOutputStream fos = new FileOutputStream(file); + return fos; + } catch (FileNotFoundException e) { + logger.warn("File " + (file == null?"null":file.getAbsolutePath()) + " does not exist in the file system"); + return null; + } + } + + + /** + * Filter class to define datasource file format + */ + private static class DataSourceFileNameFilter implements FilenameFilter{ + public boolean accept(File dir, String name) { + return (name.endsWith(DATASOURCE_FILE_NAME)); + } + } +} \ No newline at end of file diff --git a/cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/LocalHsqldb.java b/cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/LocalHsqldb.java new file mode 100644 index 0000000000..0c40aeeab7 --- /dev/null +++ b/cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/LocalHsqldb.java @@ -0,0 +1,256 @@ +/** + * + */ +package eu.etaxonomy.cdm.database; + +import java.io.File; +import java.sql.Connection; +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Properties; + +import org.apache.log4j.Logger; +import org.hsqldb.Server; +import org.springframework.jdbc.CannotGetJdbcConnectionException; +import org.springframework.jdbc.datasource.DriverManagerDataSource; + +import eu.etaxonomy.cdm.api.application.CdmApplicationUtils; +import eu.etaxonomy.cdm.common.CdmUtils; + +/** + * @author a.mueller + * + */ + +public class LocalHsqldb extends DriverManagerDataSource { + private static final Logger logger = Logger.getLogger(LocalHsqldb.class); + + private String sep = System.getProperty("file.separator"); + + /** url without database name */ + protected String pureUrl = "jdbc:hsqldb:hsql://localhost/"; + /** database name */ + protected String dbName = "cdm"; + /** path, where database should be stored in the file system */ + protected String databasePath = getDefaultPath(); + /** Server instance */ + protected Server hsqldbServer; + /** if true starts server on init() */ + protected boolean isStartServer = true; + /** makes the Server silent (no messages) */ + protected boolean isSilent = true; + /** default driver class name */ + protected String DEFAULT_DRIVER_CLASS_NAME = "org.hsqldb.jdbcDriver"; + + + /** + * + */ + public LocalHsqldb() { + setDriverClassName(DEFAULT_DRIVER_CLASS_NAME); + setComposedUrl(); + } + + /** + * @param url + * @throws CannotGetJdbcConnectionException + */ + public LocalHsqldb(String url) throws CannotGetJdbcConnectionException { + super(url); + setDriverClassName(DEFAULT_DRIVER_CLASS_NAME); + } + + /** + * @param url + * @param username + * @param password + * @throws CannotGetJdbcConnectionException + */ + public LocalHsqldb(String url, String username, String password) + throws CannotGetJdbcConnectionException { + super(url, username, password); + this.setDriverClassName(DEFAULT_DRIVER_CLASS_NAME); + } + + /** + * @param driverClassName + * @param url + * @param username + * @param password + * @throws CannotGetJdbcConnectionException + */ + public LocalHsqldb(String driverClassName, String url, String username, + String password) throws CannotGetJdbcConnectionException { + super(driverClassName, url, username, password); + } + + public void init(){ + if (isStartServer){ + this.startHsqldbServer(); + } + } + + public void destroy(){ + this.stopHsqldbServer(); + } + + + /* (non-Javadoc) + * @see org.springframework.jdbc.datasource.DriverManagerDataSource#getUrl() + */ + @Override + public String getUrl() { + return super.getUrl(); + } + + /* (non-Javadoc) + * @see org.springframework.jdbc.datasource.DriverManagerDataSource#setUrl(java.lang.String) + */ + @Override + public void setUrl(String url) { + super.setUrl(url); + } + + /** + * @return the pureUrl + */ + public String getPureUrl() { + return pureUrl; + } + + /** + * @param pureUrl the pureUrl to set + */ + public void setPureUrl(String pureUrl) { + this.pureUrl = pureUrl; + if (dbName != null){ + setComposedUrl(); + } + } + + /** + * @return the dbName + */ + public String getDbName() { + return dbName; + } + + /** + * @param dbName the dbName to set + */ + public void setDbName(String dbName) { + this.dbName = dbName; + if (pureUrl != null){ + setComposedUrl(); + } + } + + private void setComposedUrl(){ + setUrl(getPureUrl() + getDbName()); + } + + //checks if hsqldb-server is started, if not it will be started + private void startHsqldbServer(){ + try { + Driver driver = DriverManager.getDriver(getUrl()); + Properties prop = new Properties(); + prop.setProperty("user", this.getUsername()); + prop.setProperty("password", this.getPassword()); + Connection con = driver.connect(getUrl(), prop); + if (con == null) { + logger.warn("Connection to URL " + getUrl() + " could not be established"); + throw new SQLException(); + } + } catch (SQLException e) { + try { + //server is probably not runing on the url (or login is wrong !!) + logger.warn("Start HsqldbServer"); //TODO make it .info + hsqldbServer = new Server(); + hsqldbServer.setSilent(this.isSilent); + for (int i = 0; i < 10; i++){ + logger.info("DatabaseName " + i + ": " + hsqldbServer.getDatabaseName(i, true)); + logger.info("DatabaseName " + i + ": " + hsqldbServer.getDatabaseName(i, false)); + logger.info("DatabasePath " + i + ": " + hsqldbServer.getDatabasePath(i, true)); + logger.info("DatabasePath " + i + ": " + hsqldbServer.getDatabasePath(i, false)); + logger.info("DatabaseType " + i + ": " + hsqldbServer.getDatabaseType(i)); + } + hsqldbServer.setDatabaseName(0, getDbName()); + hsqldbServer.setDatabasePath(0, getDatabasePath()); + hsqldbServer.start(); + hsqldbServer.checkRunning(true); + } catch (RuntimeException e1) { + logger.error("Local hsqlServer could not be started or connection to existing server could not be established."); + } + } + } + + + /** + * stops the Hsqldb Server + */ + private void stopHsqldbServer(){ + if (hsqldbServer != null){ + logger.info("stop HsqldbServer"); + hsqldbServer.stop(); + } + } + + private static final String getDefaultPath(){ + //String path = System.getProperty("user.dir"); + File path = CdmApplicationUtils.getWritableResourceDir(); + String supPath = File.separator + "db" + File.separator + "LocalHsqldb"; + return path + supPath; + } + + /** + * @return the dbPath + */ + public String getDatabasePath() { + return databasePath; + } + + /** + * @param dbPath the dbPath to set + */ + public void setDatabasePath(String databasePath) { + if (databasePath.endsWith(sep)){ + databasePath = databasePath + "localCdm"; + } + this.databasePath = databasePath; + } + + /** + * @return the isStartServer + */ + public boolean isStartServer() { + return isStartServer; + } + + /** + * @param isStartServer the isStartServer to set + */ + public void setStartServer(boolean isStartServer) { + this.isStartServer = isStartServer; + } + + /** + * @return the isSilent + */ + public boolean isSilent() { + return isSilent; + } + + /** + * @param isSilent the isSilent to set + */ + public void setSilent(boolean isSilent) { + if (this.hsqldbServer != null){ + this.hsqldbServer.setSilent(isSilent); + } + this.isSilent = isSilent; + } + + + +} -- 2.34.1