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