View Javadoc

1   /**
2    * This file is part of GoldenGate Project (named also GoldenGate or GG).
3    * 
4    * Copyright 2009, Frederic Bregier, 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 GoldenGate 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   * GoldenGate 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   * GoldenGate . If not, see <http://www.gnu.org/licenses/>.
19   */
20  package goldengate.common.database;
21  
22  import goldengate.common.logging.GgInternalLogger;
23  import goldengate.common.logging.GgInternalLoggerFactory;
24  
25  import java.sql.Connection;
26  import java.sql.SQLException;
27  import java.util.concurrent.ConcurrentHashMap;
28  
29  import goldengate.common.database.exception.GoldenGateDatabaseNoConnectionException;
30  import goldengate.common.database.exception.GoldenGateDatabaseSqlException;
31  import goldengate.common.database.model.DbType;
32  import goldengate.common.database.model.DbModelFactory;
33  
34  /**
35   * Class for access to Database
36   * 
37   * @author Frederic Bregier
38   * 
39   */
40  public class DbAdmin {
41      /**
42       * Internal Logger
43       */
44      private static final GgInternalLogger logger = GgInternalLoggerFactory
45              .getLogger(DbAdmin.class);
46  
47      public static int RETRYNB = 3;
48  
49      public static long WAITFORNETOP = 100;
50  
51      /**
52       * Database type
53       */
54      public DbType typeDriver;
55  
56      /**
57       * DB Server
58       */
59      private String server = null;
60  
61      /**
62       * DB User
63       */
64      private String user = null;
65  
66      /**
67       * DB Password
68       */
69      private String passwd = null;
70  
71      /**
72       * Is this DB Admin connected
73       */
74      public boolean isConnected = false;
75  
76      /**
77       * Is this DB Admin Read Only
78       */
79      public boolean isReadOnly = false;
80  
81      /**
82       * Is this DB Admin accessed by only one thread at a time (no concurrency
83       * and no lock/unlock problem)
84       */
85      public boolean isMultipleDBAccess = false;
86  
87      /**
88       * session is the Session object for all type of requests
89       */
90      public DbSession session = null;
91  
92      /**
93       * Validate connection
94       * 
95       * @throws GoldenGateDatabaseNoConnectionException
96       */
97      public void validConnection() throws GoldenGateDatabaseNoConnectionException {
98          try {
99              DbModelFactory.dbModel.validConnection(session);
100         } catch (GoldenGateDatabaseNoConnectionException e) {
101             session.isDisconnected = true;
102             isConnected = false;
103             throw e;
104         }
105         session.isDisconnected = false;
106         isConnected = true;
107     }
108 
109     /**
110      * Use a default server for basic connection. Later on, specific connection
111      * to database for the scheme that provides access to the table R66DbIndex
112      * for one specific Legacy could be done.
113      * 
114      * A this time, only one driver is possible! If a new driver is needed, then
115      * we need to create a new DbSession object. Be aware that
116      * DbSession.initialize should be call only once for each driver, whatever
117      * the number of DbSession objects that could be created (=> need a
118      * hashtable for specific driver when created). Also, don't know if two
119      * drivers at the same time (two different DbSession) is allowed by JDBC.
120      * 
121      * @param driver
122      * @param server
123      * @param user
124      * @param passwd
125      * @throws GoldenGateDatabaseNoConnectionException
126      */
127     public DbAdmin(DbType driver, String server, String user, String passwd)
128             throws GoldenGateDatabaseNoConnectionException {
129         this.server = server;
130         this.user = user;
131         this.passwd = passwd;
132         this.typeDriver = driver;
133         if (typeDriver == null) {
134             logger.error("Cannot find TypeDriver:" + driver.name());
135             throw new GoldenGateDatabaseNoConnectionException(
136                     "Cannot find database drive:" + driver.name());
137         }
138         session = new DbSession(this.server, this.user, this.passwd, false);
139         session.admin = this;
140         isReadOnly = false;
141         validConnection();
142         session.useConnection(); // default since this is the top connection
143     }
144 
145     /**
146      * Use a default server for basic connection. Later on, specific connection
147      * to database for the scheme that provides access to the table R66DbIndex
148      * for one specific Legacy could be done.
149      * 
150      * A this time, only one driver is possible! If a new driver is needed, then
151      * we need to create a new DbSession object. Be aware that
152      * DbSession.initialize should be call only once for each driver, whatever
153      * the number of DbSession objects that could be created (=> need a
154      * hashtable for specific driver when created). Also, don't know if two
155      * drivers at the same time (two different DbSession) is allowed by JDBC.
156      * 
157      * @param driver
158      * @param server
159      * @param user
160      * @param passwd
161      * @param write
162      * @throws GoldenGateDatabaseSqlException
163      * @throws GoldenGateDatabaseNoConnectionException
164      */
165     public DbAdmin(DbType driver, String server, String user, String passwd,
166             boolean write) throws GoldenGateDatabaseNoConnectionException {
167         this.server = server;
168         this.user = user;
169         this.passwd = passwd;
170         this.typeDriver = driver;
171         if (typeDriver == null) {
172             logger.error("Cannot find TypeDriver");
173             throw new GoldenGateDatabaseNoConnectionException(
174                     "Cannot find database driver");
175         }
176         if (write) {
177             for (int i = 0; i < RETRYNB; i ++) {
178                 try {
179                     session = new DbSession(this.server, this.user,
180                             this.passwd, false);
181                 } catch (GoldenGateDatabaseNoConnectionException e) {
182                     logger.warn("Attempt of connection in error: " + i);
183                     continue;
184                 }
185                 isReadOnly = false;
186                 session.admin = this;
187                 validConnection();
188                 session.useConnection(); // default since this is the top
189                                          // connection
190                 return;
191             }
192         } else {
193             for (int i = 0; i < RETRYNB; i ++) {
194                 try {
195                     session = new DbSession(this.server, this.user,
196                             this.passwd, true);
197                 } catch (GoldenGateDatabaseNoConnectionException e) {
198                     logger.warn("Attempt of connection in error: " + i);
199                     continue;
200                 }
201                 isReadOnly = true;
202                 session.admin = this;
203                 validConnection();
204                 session.useConnection(); // default since this is the top
205                                          // connection
206                 return;
207             }
208         }
209         session = null;
210         isConnected = false;
211         logger.error("Cannot connect to Database!");
212         throw new GoldenGateDatabaseNoConnectionException(
213                 "Cannot connect to database");
214     }
215 
216     /**
217      * Use a default server for basic connection. Later on, specific connection
218      * to database for the scheme that provides access to the table R66DbIndex
219      * for one specific Legacy could be done.
220      * 
221      * A this time, only one driver is possible! If a new driver is needed, then
222      * we need to create a new DbSession object. Be aware that
223      * DbSession.initialize should be call only once for each driver, whatever
224      * the number of DbSession objects that could be created (=> need a
225      * hashtable for specific driver when created). Also, don't know if two
226      * drivers at the same time (two different DbSession) is allowed by JDBC.<BR>
227      * 
228      * <B>This version use given connection. typeDriver must be set before !</B>
229      * 
230      * @param conn
231      * @param isread
232      * @throws GoldenGateDatabaseNoConnectionException
233      */
234     public DbAdmin(Connection conn, boolean isread)
235             throws GoldenGateDatabaseNoConnectionException {
236         server = null;
237         if (conn == null) {
238             session = null;
239             isConnected = false;
240             logger.error("Cannot Get a Connection from Datasource");
241             throw new GoldenGateDatabaseNoConnectionException(
242                     "Cannot Get a Connection from Datasource");
243         }
244         session = new DbSession(conn, isread);
245         session.admin = this;
246         isReadOnly = isread;
247         isConnected = true;
248         validConnection();
249         session.useConnection(); // default since this is the top connection
250     }
251 
252     /**
253      * Empty constructor for no Database support (very thin client)
254      */
255     public DbAdmin() {
256         // not true but to enable pseudo database functions
257         DbModelFactory.classLoaded = true;
258         isConnected = false;
259     }
260 
261     /**
262      * Close the underlying session. Can be call even for connection given from
263      * the constructor DbAdmin(Connection, boolean).
264      * 
265      */
266     public void close() {
267         if (session != null) {
268             session.endUseConnection(); // default since this is the top
269                                         // connection
270             session.disconnect();
271             session = null;
272         }
273         isConnected = false;
274     }
275 
276     /**
277      * Commit on connection (since in autocommit, should not be used)
278      * 
279      * @throws GoldenGateDatabaseNoConnectionException
280      * @throws GoldenGateDatabaseSqlException
281      * 
282      */
283     public void commit() throws GoldenGateDatabaseSqlException,
284             GoldenGateDatabaseNoConnectionException {
285         if (session != null) {
286             session.commit();
287         }
288     }
289 
290     /**
291      * @return the server
292      */
293     public String getServer() {
294         return server;
295     }
296 
297     /**
298      * @return the user
299      */
300     public String getUser() {
301         return user;
302     }
303 
304     /**
305      * @return the passwd
306      */
307     public String getPasswd() {
308         return passwd;
309     }
310 
311     @Override
312     public String toString() {
313         return "Admin: "+typeDriver.name()+":"+server+":"+user+":"+(passwd.length());
314     }
315 
316     /**
317      * List all Connection to enable the close call on them
318      */
319     private static ConcurrentHashMap<Long, DbSession> listConnection = new ConcurrentHashMap<Long, DbSession>();
320 
321     /**
322      * Number of HttpSession
323      */
324     public static int nbHttpSession = 0;
325 
326     /**
327      * Add a Connection into the list
328      * 
329      * @param id
330      * @param session
331      */
332     public static void addConnection(long id, DbSession session) {
333         listConnection.put(Long.valueOf(id), session);
334     }
335 
336     /**
337      * Remove a Connection from the list
338      * 
339      * @param id
340      *            Id of the connection
341      */
342     public static void removeConnection(long id) {
343         listConnection.remove(Long.valueOf(id));
344     }
345 
346     /**
347      * 
348      * @return the number of connection (so number of network channels)
349      */
350     public static int getNbConnection() {
351         return listConnection.size() - 1;
352     }
353 
354     /**
355      * Close all database connections
356      */
357     public static void closeAllConnection() {
358         for (DbSession session: listConnection.values()) {
359             try {
360                 session.conn.close();
361             } catch (SQLException e) {
362             }
363         }
364         listConnection.clear();
365         if (DbModelFactory.dbModel != null) {
366             DbModelFactory.dbModel.releaseResources();
367         }
368     }
369 
370     /**
371      * Check all database connections and try to reopen them if disconnected
372      */
373     public static void checkAllConnections() {
374         for (DbSession session: listConnection.values()) {
375             try {
376                 session.checkConnection();
377             } catch (GoldenGateDatabaseNoConnectionException e) {
378                 logger.error("Database Connection cannot be reinitialized");
379             }
380         }
381     }
382 }