001/* 002 * Copyright 2012 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.core.datasource; 017 018import java.sql.Connection; 019import java.sql.ResultSet; 020import java.sql.SQLException; 021import java.sql.Statement; 022import java.util.Map; 023 024import javax.sql.DataSource; 025 026import org.apache.avalon.framework.activity.Disposable; 027import org.apache.avalon.framework.component.Component; 028import org.apache.avalon.framework.service.ServiceException; 029import org.apache.avalon.framework.service.ServiceManager; 030import org.apache.avalon.framework.service.Serviceable; 031import org.apache.commons.lang3.StringUtils; 032import org.slf4j.Logger; 033import org.slf4j.LoggerFactory; 034 035import org.ametys.core.datasource.AbstractDataSourceManager.DataSourceDefinition; 036 037/** 038 * Helper component used to retrieve java.sql.Connection from pools 039 */ 040public final class ConnectionHelper implements Component, Serviceable, Disposable 041{ 042 /** The Avalon role */ 043 public static final String ROLE = ConnectionHelper.class.getName(); 044 045 /** ID of database extension for Unknown */ 046 public static final String DATABASE_UNKNOWN = ""; 047 /** ID of database extension for Mysql */ 048 public static final String DATABASE_MYSQL = "mysql"; 049 /** ID of database extension for Oracle */ 050 public static final String DATABASE_ORACLE = "oracle"; 051 /** ID of database extension for Postgres */ 052 public static final String DATABASE_POSTGRES = "postgresql"; 053 /** ID of database extension for Derby */ 054 public static final String DATABASE_DERBY = "derby"; 055 /** ID of database extension for Hsqldb */ 056 public static final String DATABASE_HSQLDB = "hsqldb"; 057 058 059 /** Logger for traces */ 060 private static Logger _logger = LoggerFactory.getLogger(ConnectionHelper.class.getName()); 061 062 /** The manager for SQL data source */ 063 private static SQLDataSourceManager _sqlDataSourceManager; 064 065 private static ServiceManager _manager; 066 067 @Override 068 public void service(ServiceManager serviceManager) throws ServiceException 069 { 070 _manager = serviceManager; 071 } 072 073 public void dispose() 074 { 075 _sqlDataSourceManager = null; 076 } 077 078 private static SQLDataSourceManager getSQLDataSourceManager() 079 { 080 if (_sqlDataSourceManager == null) 081 { 082 try 083 { 084 _sqlDataSourceManager = (SQLDataSourceManager) _manager.lookup(SQLDataSourceManager.ROLE); 085 } 086 catch (ServiceException e) 087 { 088 throw new RuntimeException(e); 089 } 090 } 091 return _sqlDataSourceManager; 092 } 093 094 /** 095 * Get a connection to the internal sql data source 096 * @return java.sql.Connection to query the internal SQL database 097 */ 098 public static Connection getInternalSQLDataSourceConnection() 099 { 100 return getSQLDataSourceManager().getInternalSQLDataSourceConnection(); 101 } 102 103 /** 104 * Returns a Connection from the pool. 105 * @param id the id of the data source 106 * @return a java.sql.Connection to query a SQL database 107 */ 108 public static Connection getConnection(String id) 109 { 110 DataSource dataSource; 111 Connection connection = null; 112 113 if (getSQLDataSourceManager() == null) 114 { 115 throw new RuntimeException("ConnectionHelper cannot be used statically during or before components initialization"); 116 } 117 118 try 119 { 120 dataSource = getSQLDataSourceManager().getSQLDataSource(id); 121 connection = dataSource.getConnection(); 122 } 123 catch (SQLException e) 124 { 125 throw new RuntimeException("Unable to get Connection from pool " + id, e); 126 } 127 128 return connection; 129 } 130 131 /** 132 * Commit and closes a java.sql.Connection 133 * @param con the Connection to close 134 */ 135 public static void cleanup(Connection con) 136 { 137 if (con != null) 138 { 139 try 140 { 141 if (!con.getAutoCommit()) 142 { 143 con.commit(); 144 } 145 } 146 catch (SQLException s) 147 { 148 _logger.error("Error while closing database", s); 149 } 150 151 try 152 { 153 con.close(); 154 } 155 catch (SQLException s) 156 { 157 _logger.error("Error while closing database", s); 158 } 159 } 160 } 161 162 /** 163 * Closes a java.sql.Statement 164 * @param stmt the Statement to close 165 */ 166 public static void cleanup(Statement stmt) 167 { 168 if (stmt != null) 169 { 170 try 171 { 172 stmt.close(); 173 } 174 catch (SQLException s) 175 { 176 _logger.error("Error while closing statement", s); 177 } 178 } 179 } 180 181 /** 182 * Closes a java.sql.ResultSet 183 * @param rs the ResultSet to close 184 */ 185 public static void cleanup(ResultSet rs) 186 { 187 if (rs != null) 188 { 189 try 190 { 191 rs.close(); 192 } 193 catch (SQLException s) 194 { 195 _logger.error("Error while closing statement", s); 196 } 197 } 198 } 199 200 /** 201 * Determine the database type 202 * @param connection The jdbc connection to the database 203 * @return The database type id or empty string if unknown 204 */ 205 public static String getDatabaseType(Connection connection) 206 { 207 try 208 { 209 return getDatabaseType(connection.getMetaData().getURL()); 210 } 211 catch (SQLException e) 212 { 213 LoggerFactory.getLogger(ConnectionHelper.class).error("Cannot determine database type", e); 214 return DATABASE_UNKNOWN; 215 } 216 } 217 218 /** 219 * Determine the database type 220 * @param jdbcURL The jdbc url used to connect to the database 221 * @return The database type id or null if unknown 222 */ 223 public static String getDatabaseType(String jdbcURL) 224 { 225 // Get the definition url without jdbc parameters (e.g. internal-db have ;create=true) 226 String jdbcURLWithoutParams = StringUtils.substringBefore(jdbcURL, ";"); 227 228 Map<String, DataSourceDefinition> dataSourceDefinitions = getSQLDataSourceManager().getDataSourceDefinitions(true, true, false); 229 for (DataSourceDefinition definition : dataSourceDefinitions.values()) 230 { 231 // Get the definition url without jdbc parameters (e.g. internal-db have ;create=true) 232 String url = StringUtils.substringBefore((String) definition.getParameters().get("url"), ";"); 233 if (StringUtils.equals(url, jdbcURLWithoutParams)) 234 { 235 return (String) definition.getParameters().get("dbtype"); 236 } 237 } 238 239 return DATABASE_UNKNOWN; 240 } 241 242 /** 243 * Returns the SQL {@link DataSourceDefinition} corresponding to the given id. 244 * @param id the id of the data source 245 * @return the {@link DataSourceDefinition}. 246 */ 247 public static DataSourceDefinition getDataSourceDefinition(String id) 248 { 249 return getSQLDataSourceManager().getDataSourceDefinition(id); 250 } 251}