View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.waarp.common.database.model;
21  
22  import com.mysql.jdbc.Driver;
23  import io.netty.util.internal.PlatformDependent;
24  import org.waarp.common.database.DbAdmin;
25  import org.waarp.common.database.DbConnectionPool;
26  import org.waarp.common.database.DbConstant;
27  import org.waarp.common.database.exception.WaarpDatabaseNoConnectionException;
28  import org.waarp.common.logging.SysErrLogger;
29  import org.waarp.common.logging.WaarpLogger;
30  import org.waarp.common.logging.WaarpLoggerFactory;
31  import org.waarp.common.utility.WaarpSystemUtil;
32  
33  import javax.sql.ConnectionPoolDataSource;
34  import java.lang.reflect.Method;
35  import java.sql.Connection;
36  import java.sql.DriverManager;
37  import java.sql.SQLException;
38  import java.util.Timer;
39  
40  /**
41   * MySQL Database Model implementation
42   */
43  public abstract class DbModelMysql extends DbModelCommonMariadbMySql {
44    /**
45     * Internal Logger
46     */
47    private static final WaarpLogger logger =
48        WaarpLoggerFactory.getLogger(DbModelMysql.class);
49  
50    private static final DbType type = DbType.MySQL;
51    private static final String MYSQL_CONNECTION_POOL_DATA_SOURCE_JRE6 =
52        "com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource";
53    private static final String MYSQL_CONNECTION_POOL_DATA_SOURCE_JRE8 =
54        "com.mysql.cj.jdbc.MysqlConnectionPoolDataSource";
55    public static final String MYSQL_DRIVER_JRE6 = "com.mysql.jdbc.Driver";
56    public static final String MYSQL_DRIVER_JRE8 = "com.mysql.cj.jdbc.Driver";
57    private static final String
58        CANNOT_INITIALIZE_MYSQL_CONNECTION_POOL_DATA_SOURCE =
59        "Cannot initialize MysqlConnectionPoolDataSource";
60  
61    protected static class DbTypeResolverMySQL
62        extends DbModelAbstract.DbTypeResolver {
63  
64      @Override
65      public final String getType(final int sqlType) {
66        return DBType.getType(sqlType);
67      }
68  
69      @Override
70      public final String getCreateTable() {
71        return "CREATE TABLE IF NOT EXISTS ";
72      }
73  
74      @Override
75      public final String getCreateIndex() {
76        return "CREATE INDEX ";
77      }
78  
79      @Override
80      public final DbType getDbType() {
81        return type;
82      }
83    }
84  
85    static {
86      dbTypeResolver = new DbTypeResolverMySQL();
87    }
88  
89    protected ConnectionPoolDataSource mysqlConnectionPoolDataSource;
90    protected DbConnectionPool pool;
91  
92    @Override
93    public final DbType getDbType() {
94      return type;
95    }
96  
97    /**
98     * @return a ConnectionPoolDataSource as MysqlConnectionPoolDataSource
99     *
100    * @throws WaarpDatabaseNoConnectionException if class not found
101    */
102   private ConnectionPoolDataSource createMysqlConnectionPoolDataSource(
103       final String dbServer, final String dbUser, final String dbPwd)
104       throws WaarpDatabaseNoConnectionException {
105     Class<?> mysqlConnectionPoolDataSourceClass = null;
106     if (PlatformDependent.javaVersion() >= 8) {
107       try {
108         Class.forName(MYSQL_DRIVER_JRE8);
109         mysqlConnectionPoolDataSourceClass =
110             Class.forName(MYSQL_CONNECTION_POOL_DATA_SOURCE_JRE8);
111       } catch (final Exception e) {
112         try {
113           mysqlConnectionPoolDataSourceClass =
114               Class.forName(MYSQL_CONNECTION_POOL_DATA_SOURCE_JRE6);
115         } catch (final ClassNotFoundException classNotFoundException) {
116           try {
117             mysqlConnectionPoolDataSourceClass =
118                 Class.forName(MYSQL_CONNECTION_POOL_DATA_SOURCE_JRE8);
119           } catch (final ClassNotFoundException e2) {
120             logger.error(CANNOT_INITIALIZE_MYSQL_CONNECTION_POOL_DATA_SOURCE);
121             throw new WaarpDatabaseNoConnectionException(
122                 CANNOT_INITIALIZE_MYSQL_CONNECTION_POOL_DATA_SOURCE, e);
123           }
124         }
125       }
126     } else {
127       try {
128         mysqlConnectionPoolDataSourceClass =
129             Class.forName(MYSQL_CONNECTION_POOL_DATA_SOURCE_JRE6);
130       } catch (final ClassNotFoundException e) {
131         logger.error(CANNOT_INITIALIZE_MYSQL_CONNECTION_POOL_DATA_SOURCE);
132         throw new WaarpDatabaseNoConnectionException(
133             CANNOT_INITIALIZE_MYSQL_CONNECTION_POOL_DATA_SOURCE, e);
134       }
135     }
136     try {
137       final ConnectionPoolDataSource cpds =
138           (ConnectionPoolDataSource) WaarpSystemUtil.newInstance(
139               mysqlConnectionPoolDataSourceClass);
140       Method method = mysqlConnectionPoolDataSourceClass.getMethod("setUrl",
141                                                                    dbServer.getClass());
142       method.invoke(cpds, dbServer);
143       method = mysqlConnectionPoolDataSourceClass.getMethod("setUser",
144                                                             dbUser.getClass());
145       method.invoke(cpds, dbUser);
146       method = mysqlConnectionPoolDataSourceClass.getMethod("setPassword",
147                                                             dbPwd.getClass());
148       method.invoke(cpds, dbPwd);
149       return cpds;
150     } catch (final Exception e) {
151       throw new WaarpDatabaseNoConnectionException(
152           CANNOT_INITIALIZE_MYSQL_CONNECTION_POOL_DATA_SOURCE, e);
153     }
154   }
155 
156   /**
157    * Create the object and initialize if necessary the driver
158    *
159    * @param dbserver
160    * @param dbuser
161    * @param dbpasswd
162    * @param timer
163    * @param delay
164    *
165    * @throws WaarpDatabaseNoConnectionException
166    */
167   protected DbModelMysql(final String dbserver, final String dbuser,
168                          final String dbpasswd, final Timer timer,
169                          final long delay)
170       throws WaarpDatabaseNoConnectionException {
171     this();
172     mysqlConnectionPoolDataSource =
173         createMysqlConnectionPoolDataSource(dbserver, dbuser, dbpasswd);
174     // Create a pool with no limit
175     pool = new DbConnectionPool(mysqlConnectionPoolDataSource, timer, delay);
176     logger.info("Some info: MaxConn: {} LogTimeout: {} ForceClose: {}",
177                 pool.getMaxConnections(), pool.getLoginTimeout(),
178                 pool.getTimeoutForceClose());
179   }
180 
181   /**
182    * Create the object and initialize if necessary the driver
183    *
184    * @param dbserver
185    * @param dbuser
186    * @param dbpasswd
187    *
188    * @throws WaarpDatabaseNoConnectionException
189    */
190   protected DbModelMysql(final String dbserver, final String dbuser,
191                          final String dbpasswd)
192       throws WaarpDatabaseNoConnectionException {
193     this();
194     mysqlConnectionPoolDataSource =
195         createMysqlConnectionPoolDataSource(dbserver, dbuser, dbpasswd);
196     // Create a pool with no limit
197     pool = new DbConnectionPool(mysqlConnectionPoolDataSource);
198     logger.warn(
199         "Some info: MaxConn: " + pool.getMaxConnections() + " LogTimeout: " +
200         pool.getLoginTimeout() + " ForceClose: " + pool.getTimeoutForceClose());
201   }
202 
203   /**
204    * Create the object and initialize if necessary the driver
205    *
206    * @throws WaarpDatabaseNoConnectionException
207    */
208   protected DbModelMysql() throws WaarpDatabaseNoConnectionException {
209     if (DbModelFactory.classLoaded.contains(type.name())) {
210       return;
211     }
212     try {
213       DriverManager.registerDriver(new Driver());
214       DbModelFactory.classLoaded.add(type.name());
215     } catch (final SQLException e) {
216       // SQLException
217       logger.error(
218           "Cannot register Driver " + type.name() + ' ' + e.getMessage());
219       DbConstant.error(e);
220       throw new WaarpDatabaseNoConnectionException(
221           "Cannot load database drive:" + type.name(), e);
222     }
223   }
224 
225   @Override
226   public final void releaseResources() {
227     if (pool != null) {
228       try {
229         pool.dispose();
230       } catch (final SQLException ignored) {
231         SysErrLogger.FAKE_LOGGER.ignoreLog(ignored);
232       }
233     }
234     pool = null;
235   }
236 
237   @Override
238   public synchronized int currentNumberOfPooledConnections() {
239     if (pool != null) {
240       return pool.getActiveConnections();
241     }
242     return DbAdmin.getNbConnection();
243   }
244 
245   @Override
246   public final Connection getDbConnection(final String server,
247                                           final String user,
248                                           final String passwd)
249       throws SQLException {
250     synchronized (this) {
251       if (pool != null) {
252         try {
253           return pool.getConnection();
254         } catch (final SQLException e) {
255           // try to renew the pool
256           try {
257             mysqlConnectionPoolDataSource =
258                 createMysqlConnectionPoolDataSource(server, user, passwd);
259           } catch (final WaarpDatabaseNoConnectionException e1) {
260             logger.debug("Cannot found MySQLPooled class", e1);
261             pool.dispose();
262             pool = null;
263             return super.getDbConnection(server, user, passwd);
264           }
265           pool.resetPoolDataSource(mysqlConnectionPoolDataSource);
266           try {
267             return pool.getConnection();
268           } catch (final SQLException e2) {
269             pool.dispose();
270             pool = null;
271             return super.getDbConnection(server, user, passwd);
272           }
273         }
274       }
275     }
276     return super.getDbConnection(server, user, passwd);
277   }
278 
279 }