- fully implemented deep delete (child derivates)
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / DatabaseServiceHibernateImpl.java
1 // $Id$
2 /**
3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
9 */
10
11 package eu.etaxonomy.cdm.api.service;
12
13 import java.sql.Connection;
14 import java.sql.ResultSet;
15 import java.sql.SQLException;
16 import java.sql.Statement;
17 import java.util.HashMap;
18 import java.util.Map;
19
20 import javax.sql.DataSource;
21
22 import org.apache.log4j.Logger;
23 import org.hibernate.SessionFactory;
24 import org.springframework.beans.BeansException;
25 import org.springframework.beans.factory.annotation.Autowired;
26 import org.springframework.context.ApplicationContext;
27 import org.springframework.context.ApplicationContextAware;
28 import org.springframework.jdbc.datasource.AbstractDriverBasedDataSource;
29 import org.springframework.orm.hibernate4.SessionFactoryUtils;
30 import org.springframework.stereotype.Service;
31 import org.springframework.transaction.annotation.Transactional;
32
33 import eu.etaxonomy.cdm.api.application.CdmApplicationController;
34 import eu.etaxonomy.cdm.config.CdmPersistentSourceUtils;
35 import eu.etaxonomy.cdm.config.CdmSourceException;
36 import eu.etaxonomy.cdm.database.CdmDataSource;
37 import eu.etaxonomy.cdm.database.CdmPersistentDataSource;
38 import eu.etaxonomy.cdm.database.DataSourceNotFoundException;
39 import eu.etaxonomy.cdm.database.DatabaseTypeEnum;
40 import eu.etaxonomy.cdm.database.H2Mode;
41 import eu.etaxonomy.cdm.database.ICdmDataSource;
42 import eu.etaxonomy.cdm.model.common.init.TermNotFoundException;
43 import eu.etaxonomy.cdm.model.metadata.CdmMetaData.MetaDataPropertyName;
44 import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
45
46
47
48 /**
49 * Implementation of service which provides functionality to directly access database
50 * related information.
51 *
52 * @author a.mueller
53 *
54 */
55 @Service
56 @Transactional(readOnly = true)
57 public class DatabaseServiceHibernateImpl implements IDatabaseService, ApplicationContextAware {
58 private static final Logger logger = Logger.getLogger(DatabaseServiceHibernateImpl.class);
59
60 private static final String TMP_DATASOURCE = "tmp";
61
62 @Autowired
63 private SessionFactory factory;
64
65 @Autowired
66 protected ApplicationContext appContext;
67
68 private CdmApplicationController application;
69
70
71
72
73 /* (non-Javadoc)
74 * @see eu.etaxonomy.cdm.api.service.IDatabaseService#setApplicationController(eu.etaxonomy.cdm.api.application.CdmApplicationController)
75 */
76 public void setApplicationController(CdmApplicationController cdmApplicationController){
77 this.application = cdmApplicationController;
78 }
79
80
81 /* (non-Javadoc)
82 * @see eu.etaxonomy.cdm.api.service.IDatabaseService#connectToDatasource(eu.etaxonomy.cdm.database.CdmDataSource)
83 */
84 public boolean connectToDatasource(CdmPersistentDataSource dataSource) throws TermNotFoundException{
85 this.application.changeDataSource(dataSource);
86 logger.debug("DataSource changed to " + dataSource.getName());
87 return true;
88 }
89
90 /* (non-Javadoc)
91 * @see eu.etaxonomy.cdm.api.service.IDatabaseService#connectToDatabase(eu.etaxonomy.cdm.database.DatabaseTypeEnum, java.lang.String, java.lang.String, java.lang.String, java.lang.String, int)
92 */
93 public boolean connectToDatabase(DatabaseTypeEnum databaseTypeEnum, String server,
94 String database, String username, String password, int port, String filePath, H2Mode mode, NomenclaturalCode code) throws TermNotFoundException {
95 ICdmDataSource dataSource = CdmDataSource.NewInstance(databaseTypeEnum, server, database, port, username, password, code);
96 CdmPersistentDataSource tmpDataSource = saveDataSource(TMP_DATASOURCE, dataSource);
97 boolean result = connectToDatasource(tmpDataSource);
98 CdmPersistentSourceUtils.delete(tmpDataSource);
99 return result;
100 }
101
102
103 /* (non-Javadoc)
104 * @see eu.etaxonomy.cdm.api.service.IDatabaseService#connectToDatabase(eu.etaxonomy.cdm.database.DatabaseTypeEnum, java.lang.String, java.lang.String, java.lang.String, java.lang.String)
105 */
106 public boolean connectToDatabase(DatabaseTypeEnum databaseTypeEnum, String server,
107 String database, String username, String password) throws TermNotFoundException {
108 return connectToDatabase(databaseTypeEnum, server, database, username, password, databaseTypeEnum.getDefaultPort(), null, null, null) ;
109 }
110
111 /* (non-Javadoc)
112 * @see eu.etaxonomy.cdm.api.service.IDatabaseService#saveDataSource(java.lang.String, eu.etaxonomy.cdm.database.ICdmDataSource)
113 */
114 public CdmPersistentDataSource saveDataSource(String strDataSourceName,
115 ICdmDataSource dataSource) {
116 return CdmPersistentDataSource.save(strDataSourceName, dataSource);
117 }
118
119 /* (non-Javadoc)
120 * @see eu.etaxonomy.cdm.api.service.IDatabaseService#updateDataSource(java.lang.String, eu.etaxonomy.cdm.database.CdmPersistentDataSource)
121 */
122 public CdmPersistentDataSource updateDataSource(String strDataSourceName,
123 CdmPersistentDataSource dataSource) throws DataSourceNotFoundException {
124 return CdmPersistentDataSource.update(strDataSourceName, dataSource);
125 }
126
127 /* (non-Javadoc)
128 * @see eu.etaxonomy.cdm.api.service.IDatabaseService#getUrl()
129 */
130 public String getUrl() {
131 return getDataSource().getUrl();
132 }
133
134 /* (non-Javadoc)
135 * @see eu.etaxonomy.cdm.api.service.IDatabaseService#getUsername()
136 */
137 public String getUsername() {
138 return getDataSource().getUsername();
139 }
140
141 /**
142 * Returns the AbstractDriverBasedDataSource from hibernate,
143 * generalized in order to also allow using SimpleDriverDataSource.
144 *
145 * @return the AbstractDriverBasedDataSource from the hibernate layer
146 */
147 private AbstractDriverBasedDataSource getDataSource(){
148 AbstractDriverBasedDataSource ds = (AbstractDriverBasedDataSource)SessionFactoryUtils.getDataSource(factory);
149 return ds;
150 }
151
152
153 /* (non-Javadoc)
154 * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
155 */
156 public void setApplicationContext(ApplicationContext applicationContext)
157 throws BeansException {
158 this.appContext = applicationContext;
159 }
160
161
162
163 /* (non-Javadoc)
164 * @see eu.etaxonomy.cdm.api.service.IDatabaseService#getDbSchemaVersion()
165 */
166 @Override
167 public String getDbSchemaVersion() throws CdmSourceException {
168 try {
169 return (String)getSingleValue(MetaDataPropertyName.DB_SCHEMA_VERSION.getSqlQuery());
170 } catch (SQLException e) {
171 throw new CdmSourceException(e.getMessage());
172 }
173 }
174
175
176 /* (non-Javadoc)
177 * @see eu.etaxonomy.cdm.api.service.IDatabaseService#isDbEmpty()
178 */
179 @Override
180 public boolean isDbEmpty() throws CdmSourceException {
181 // Any CDM DB should have a schema version
182 String dbSchemaVersion = (String) getDbSchemaVersion();
183 return (dbSchemaVersion == null || dbSchemaVersion.equals(""));
184 }
185
186 /**
187 * Execute a SQL query which returns a single value
188 *
189 * @param query , which returns a single value
190 * @return
191 * @throws SQLException
192 */
193 private Object getSingleValue(String query) throws SQLException {
194 String queryString = query == null? "(null)": query;
195 //ResultSet resultSet = executeQuery(query);
196 ResultSet resultSet = null;
197
198 Connection connection = SessionFactoryUtils.getDataSource(factory).getConnection();
199 if (connection != null){
200
201 Statement statement = connection.createStatement();
202 resultSet = statement.executeQuery(query);
203
204 if (resultSet == null || resultSet.next() == false){
205 logger.info("No record returned for query " + queryString);
206 return null;
207 }
208 if (resultSet.getMetaData().getColumnCount() != 1){
209 logger.info("More than one column selected in query" + queryString);
210 //first value will be taken
211 }
212 Object object = resultSet.getObject(1);
213 if (resultSet.next()){
214 logger.info("Multiple results for query " + queryString);
215 //first row will be taken
216 }
217 // making sure we close all resources so we don't run out of
218 // connections in the connection pool
219 resultSet.close();
220 statement.close();
221 connection.close();
222
223 return object;
224 }else{
225 throw new RuntimeException("Could not establish connection to database");
226 }
227
228 }
229
230
231 @Override
232 public Map<MetaDataPropertyName, String> getCdmMetadataMap() throws CdmSourceException {
233 Map<MetaDataPropertyName, String> cdmMetaDataMap = new HashMap<MetaDataPropertyName, String>();
234
235 for(MetaDataPropertyName mdpn : MetaDataPropertyName.values()){
236 String value = null;
237 try {
238 value = (String)getSingleValue(mdpn.getSqlQuery());
239 } catch (SQLException e) {
240 throw new CdmSourceException(e.getMessage());
241 }
242 if(value != null) {
243 cdmMetaDataMap.put(mdpn, value);
244 }
245 }
246 return cdmMetaDataMap;
247 }
248
249 }