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 org.mariadb.jdbc.Driver;
23  import org.mariadb.jdbc.MariaDbDataSource;
24  import org.waarp.common.database.DbConnectionPool;
25  import org.waarp.common.database.DbConstant;
26  import org.waarp.common.database.DbPreparedStatement;
27  import org.waarp.common.database.DbRequest;
28  import org.waarp.common.database.DbSession;
29  import org.waarp.common.database.data.DbDataModel;
30  import org.waarp.common.database.exception.WaarpDatabaseNoConnectionException;
31  import org.waarp.common.database.exception.WaarpDatabaseNoDataException;
32  import org.waarp.common.database.exception.WaarpDatabaseSqlException;
33  import org.waarp.common.logging.SysErrLogger;
34  import org.waarp.common.logging.WaarpLogger;
35  import org.waarp.common.logging.WaarpLoggerFactory;
36  
37  import java.sql.Connection;
38  import java.sql.DriverManager;
39  import java.sql.SQLException;
40  import java.util.Timer;
41  
42  /**
43   * MariaDB Database Model implementation
44   */
45  public abstract class DbModelMariadb extends DbModelCommonMariadbMySql {
46    /**
47     * Internal Logger
48     */
49    private static final WaarpLogger logger =
50        WaarpLoggerFactory.getLogger(DbModelMariadb.class);
51  
52    private static final DbType type = DbType.MariaDB;
53  
54    protected static class DbTypeResolverMariadDb
55        extends DbModelAbstract.DbTypeResolver {
56  
57      @Override
58      public final String getType(final int sqlType) {
59        return DBType.getType(sqlType);
60      }
61  
62      @Override
63      public final String getCreateTable() {
64        return "CREATE TABLE IF NOT EXISTS ";
65      }
66  
67      @Override
68      public final String getCreateIndex() {
69        return "CREATE INDEX IF NOT EXISTS ";
70      }
71  
72      @Override
73      public final DbType getDbType() {
74        return type;
75      }
76    }
77  
78    static {
79      dbTypeResolver = new DbTypeResolverMariadDb();
80    }
81  
82    protected MariaDbDataSource mysqlConnectionPoolDataSource;
83    protected DbConnectionPool pool;
84  
85    @Override
86    public final DbType getDbType() {
87      return type;
88    }
89  
90    /**
91     * Create the object and initialize if necessary the driver
92     *
93     * @param dbserver
94     * @param dbuser
95     * @param dbpasswd
96     * @param timer
97     * @param delay
98     *
99     * @throws WaarpDatabaseNoConnectionException
100    */
101   protected DbModelMariadb(final String dbserver, final String dbuser,
102                            final String dbpasswd, final Timer timer,
103                            final long delay)
104       throws WaarpDatabaseNoConnectionException {
105     this();
106     mysqlConnectionPoolDataSource = new MariaDbDataSource();
107     try {
108       mysqlConnectionPoolDataSource.setUrl(dbserver);
109     } catch (final SQLException e) {
110       throw new WaarpDatabaseNoConnectionException("Url setting is wrong", e);
111     }
112 
113     try {
114       mysqlConnectionPoolDataSource.setUser(dbuser);
115       mysqlConnectionPoolDataSource.setPassword(dbpasswd);
116     } catch (final SQLException e) {
117       throw new WaarpDatabaseNoConnectionException("Wrong username or password",
118                                                    e);
119     }
120     // Create a pool with no limit
121     if (timer != null && delay != 0) {
122       pool = new DbConnectionPool(mysqlConnectionPoolDataSource, timer, delay);
123     } else {
124       pool = new DbConnectionPool(mysqlConnectionPoolDataSource);
125     }
126 
127     logger.info("Some info: MaxConn: {} LogTimeout: {} ForceClose: {}",
128                 pool.getMaxConnections(), pool.getLoginTimeout(),
129                 pool.getTimeoutForceClose());
130   }
131 
132   /**
133    * Create the object and initialize if necessary the driver
134    *
135    * @param dbserver
136    * @param dbuser
137    * @param dbpasswd
138    *
139    * @throws WaarpDatabaseNoConnectionException
140    */
141   protected DbModelMariadb(final String dbserver, final String dbuser,
142                            final String dbpasswd)
143       throws WaarpDatabaseNoConnectionException {
144     this(dbserver, dbuser, dbpasswd, null, 0);
145   }
146 
147   /**
148    * Create the object and initialize if necessary the driver
149    *
150    * @throws WaarpDatabaseNoConnectionException
151    */
152   protected DbModelMariadb() throws WaarpDatabaseNoConnectionException {
153     if (DbModelFactory.classLoaded.contains(type.name())) {
154       return;
155     }
156     try {
157       DriverManager.registerDriver(new Driver());
158       DbModelFactory.classLoaded.add(type.name());
159     } catch (final SQLException e) {
160       // SQLException
161       logger.error(
162           "Cannot register Driver " + type.name() + ' ' + e.getMessage());
163       DbConstant.error(e);
164       throw new WaarpDatabaseNoConnectionException(
165           "Cannot load database drive:" + type.name(), e);
166     }
167   }
168 
169   @Override
170   public final Connection getDbConnection(final String server,
171                                           final String user,
172                                           final String passwd)
173       throws SQLException {
174     synchronized (this) {
175       if (pool != null) {
176         try {
177           return pool.getConnection();
178         } catch (final SQLException e) {
179           // try to renew the pool
180           mysqlConnectionPoolDataSource = new MariaDbDataSource();
181           mysqlConnectionPoolDataSource.setUrl(server);
182           mysqlConnectionPoolDataSource.setUser(user);
183           mysqlConnectionPoolDataSource.setPassword(passwd);
184           pool.resetPoolDataSource(mysqlConnectionPoolDataSource);
185           try {
186             return pool.getConnection();
187           } catch (final SQLException e2) {
188             pool.dispose();
189             pool = null;
190             return super.getDbConnection(server, user, passwd);
191           }
192         }
193       }
194     }
195     return super.getDbConnection(server, user, passwd);
196   }
197 
198   @Override
199   public void resetSequence(final DbSession session, final long newvalue)
200       throws WaarpDatabaseNoConnectionException {
201     final String action =
202         "ALTER SEQUENCE IF EXISTS " + DbDataModel.fieldseq + " MINVALUE " +
203         (DbConstant.ILLEGALVALUE + 1) + " RESTART WITH " + newvalue;
204     final DbRequest request = new DbRequest(session);
205     try {
206       request.query(action);
207     } catch (final WaarpDatabaseNoConnectionException e) {
208       SysErrLogger.FAKE_LOGGER.ignoreLog(e);
209     } catch (final WaarpDatabaseSqlException e) {
210       SysErrLogger.FAKE_LOGGER.ignoreLog(e);
211       // Old way
212       super.resetSequence(session, newvalue);
213     } finally {
214       request.close();
215     }
216     logger.warn(action);
217   }
218 
219   @Override
220   public long nextSequence(final DbSession dbSession)
221       throws WaarpDatabaseNoConnectionException, WaarpDatabaseSqlException,
222              WaarpDatabaseNoDataException {
223     long result;
224     final String action = "SELECT NEXT VALUE FOR " + DbDataModel.fieldseq;
225     final DbPreparedStatement preparedStatement =
226         new DbPreparedStatement(dbSession);
227     try {
228       preparedStatement.createPrepareStatement(action);
229       // Limit the search
230       preparedStatement.executeQuery();
231       if (preparedStatement.getNext()) {
232         try {
233           result = preparedStatement.getResultSet().getLong(1);
234         } catch (final SQLException e) {
235           // Old way
236           return super.nextSequence(dbSession);
237         }
238         return result;
239       } else {
240         // Old way
241         return super.nextSequence(dbSession);
242       }
243     } finally {
244       preparedStatement.realClose();
245     }
246   }
247 
248   @Override
249   public synchronized void releaseResources() {
250     if (pool != null) {
251       try {
252         pool.dispose();
253       } catch (final SQLException ignored) {
254         SysErrLogger.FAKE_LOGGER.ignoreLog(ignored);
255       }
256     }
257     pool = null;
258   }
259 
260 }