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 
10     by the Free Software Foundation, either version 3 of the License, or
11     (at your option) any later version.
12  
13     GoldenGate is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17  
18     You should have received a copy of the GNU General Public License
19     along with GoldenGate .  If not, see <http://www.gnu.org/licenses/>.
20   */
21  package goldengate.common.database.data;
22  
23  import java.io.InputStream;
24  import java.io.Reader;
25  import java.sql.Date;
26  import java.sql.PreparedStatement;
27  import java.sql.ResultSet;
28  import java.sql.SQLException;
29  import java.sql.Timestamp;
30  import java.sql.Types;
31  
32  import goldengate.common.database.DbPreparedStatement;
33  import goldengate.common.database.DbSession;
34  import goldengate.common.database.exception.GoldenGateDatabaseException;
35  import goldengate.common.database.exception.GoldenGateDatabaseNoConnectionException;
36  import goldengate.common.database.exception.GoldenGateDatabaseNoDataException;
37  import goldengate.common.database.exception.GoldenGateDatabaseSqlException;
38  
39  /**
40   * Abstract database table implementation without explicit COMMIT.<br><br>
41   * 
42   * If the connection is in autocommit, this is the right abstract to extend.<br>
43   * If the connection is not in autocommit, one could use this implementation to explicitly 
44   * commit when needed.
45   *
46   * @author Frederic Bregier
47   *
48   */
49  public abstract class AbstractDbData {
50      /**
51       * UpdatedInfo status
52       * @author Frederic Bregier
53       *
54       */
55      public static enum UpdatedInfo {
56          /**
57           * Unknown run status
58           */
59          UNKNOWN,
60          /**
61           * Not updated run status
62           */
63          NOTUPDATED,
64          /**
65           * Interrupted status (stop or cancel)
66           */
67          INTERRUPTED,
68          /**
69           * Updated run status meaning ready to be submitted
70           */
71          TOSUBMIT,
72          /**
73           * In error run status
74           */
75          INERROR,
76          /**
77           * Running status
78           */
79          RUNNING,
80          /**
81           * All done run status
82           */
83          DONE;
84      }
85      /**
86       *  To be implemented
87       */
88      //public static String table;
89      //public static final int NBPRKEY;
90      //protected static String selectAllFields;
91      //protected static String updateAllFields;
92      //protected static String insertAllValues;
93      protected DbValue[] primaryKey;
94      protected DbValue[] otherFields;
95      protected DbValue[] allFields;
96      
97      protected boolean isSaved = false;
98      /**
99       * The DbSession to use
100      */
101     protected final DbSession dbSession;
102     /**
103      * Abstract constructor to set the DbSession to use
104      * @param dbSession
105      */
106     public AbstractDbData(DbSession dbSession) {
107         this.dbSession = dbSession;
108         initObject();
109     }
110     /**
111      * To setup primaryKey, otherFields, allFields.
112      * Note this initObject is called within constructor of AbstractDbData.
113      * Be careful that no data is actually initialized at this stage.
114      */
115     protected abstract void initObject();
116     /**
117     *
118     * @return The Where condition on Primary Key
119     */
120    protected abstract String getWherePrimaryKey();
121    /**
122     * Set the primary Key as current value
123     */
124    protected abstract void setPrimaryKey();
125    protected abstract String getSelectAllFields();
126    protected abstract String getTable();
127    protected abstract String getInsertAllValues();
128    protected abstract String getUpdateAllFields();
129    
130     /**
131      * Test the existence of the current object
132      * @return True if the object exists
133      * @throws GoldenGateDatabaseException
134      */
135     public boolean exist() throws GoldenGateDatabaseException {
136         if (dbSession == null) {
137             return false;
138         }
139         DbPreparedStatement preparedStatement = new DbPreparedStatement(
140                 dbSession);
141         try {
142             preparedStatement.createPrepareStatement("SELECT " +
143                     primaryKey[0].column + " FROM " + getTable() + " WHERE " +
144                     getWherePrimaryKey());
145             setPrimaryKey();
146             setValues(preparedStatement, primaryKey);
147             preparedStatement.executeQuery();
148             return preparedStatement.getNext();
149         } finally {
150             preparedStatement.realClose();
151         }
152     }
153     /**
154      * Select object from table
155      * @throws GoldenGateDatabaseException
156      */
157     public void select() throws GoldenGateDatabaseException {
158         if (dbSession == null) {
159             throw new GoldenGateDatabaseNoDataException("No row found");
160         }
161         DbPreparedStatement preparedStatement = new DbPreparedStatement(
162                 dbSession);
163         try {
164             preparedStatement.createPrepareStatement("SELECT " + getSelectAllFields() +
165                     " FROM " + getTable() + " WHERE " +
166                     getWherePrimaryKey());
167             setPrimaryKey();
168             setValues(preparedStatement, primaryKey);
169             preparedStatement.executeQuery();
170             if (preparedStatement.getNext()) {
171                 getValues(preparedStatement, allFields);
172                 setFromArray();
173                 isSaved = true;
174             } else {
175                 throw new GoldenGateDatabaseNoDataException("No row found");
176             }
177         } finally {
178             preparedStatement.realClose();
179         }
180     }
181     /**
182      * Insert object into table
183      * @throws GoldenGateDatabaseException
184      */
185     public void insert() throws GoldenGateDatabaseException {
186         if (isSaved) {
187             return;
188         }
189         if (dbSession == null) {
190             isSaved = true;
191             return;
192         }
193         setToArray();
194         DbPreparedStatement preparedStatement = new DbPreparedStatement(
195                 dbSession);
196         try {
197             preparedStatement.createPrepareStatement("INSERT INTO " + getTable() +
198                     " (" + getSelectAllFields() + ") VALUES " + getInsertAllValues());
199             setValues(preparedStatement, allFields);
200             int count = preparedStatement.executeUpdate();
201             if (count <= 0) {
202                 throw new GoldenGateDatabaseNoDataException("No row found");
203             }
204             isSaved = true;
205         } finally {
206             preparedStatement.realClose();
207         }
208     }
209     /**
210      * Update object to table
211      * @throws GoldenGateDatabaseException
212      */
213     public void update() throws GoldenGateDatabaseException {
214         if (isSaved) {
215             return;
216         }
217         if (dbSession == null) {
218             isSaved = true;
219             return;
220         }
221         setToArray();
222         DbPreparedStatement preparedStatement = new DbPreparedStatement(
223                 dbSession);
224         try {
225             preparedStatement.createPrepareStatement("UPDATE " + getTable() +
226                     " SET " + getUpdateAllFields() + " WHERE " +
227                     getWherePrimaryKey());
228             setValues(preparedStatement, allFields);
229             int count = preparedStatement.executeUpdate();
230             if (count <= 0) {
231                 throw new GoldenGateDatabaseNoDataException("No row found");
232             }
233             isSaved = true;
234         } finally {
235             preparedStatement.realClose();
236         }
237     }
238     /**
239      * Delete object from table
240      * @throws GoldenGateDatabaseException
241      */
242     public void delete() throws GoldenGateDatabaseException {
243         if (dbSession == null) {
244             return;
245         }
246         DbPreparedStatement preparedStatement = new DbPreparedStatement(
247                 dbSession);
248         try {
249             preparedStatement.createPrepareStatement("DELETE FROM " + getTable() +
250                     " WHERE " + getWherePrimaryKey());
251             setPrimaryKey();
252             setValues(preparedStatement, primaryKey);
253             int count = preparedStatement.executeUpdate();
254             if (count <= 0) {
255                 throw new GoldenGateDatabaseNoDataException("No row found");
256             }
257             isSaved = false;
258         } finally {
259             preparedStatement.realClose();
260         }
261     }
262     /**
263      * Change UpdatedInfo status
264      * @param info
265      */
266     public abstract void changeUpdatedInfo(UpdatedInfo info);
267     /**
268      * Internal function to set to Array used to push data to database
269      */
270     protected abstract void setToArray();
271     /**
272      * Internal function to retrieve data from Array to pull data from database
273      * @throws GoldenGateDatabaseSqlException
274      */
275     protected abstract void setFromArray() throws GoldenGateDatabaseSqlException;
276     /**
277      * Set Value into PreparedStatement
278      * @param ps
279      * @param value
280      * @param rank >= 1
281      * @throws GoldenGateDatabaseSqlException
282      */
283     static public void setTrueValue(PreparedStatement ps, DbValue value, int rank)
284             throws GoldenGateDatabaseSqlException {
285         try {
286             switch (value.type) {
287                 case Types.VARCHAR:
288                     if (value.value == null) {
289                         ps.setNull(rank, Types.VARCHAR);
290                         break;
291                     }
292                     ps.setString(rank, (String) value.value);
293                     break;
294                 case Types.LONGVARCHAR:
295                     if (value.value == null) {
296                         ps.setNull(rank, Types.LONGVARCHAR);
297                         break;
298                     }
299                     ps.setString(rank, (String) value.value);
300                     break;
301                 case Types.BIT:
302                     if (value.value == null) {
303                         ps.setNull(rank, Types.BIT);
304                         break;
305                     }
306                     ps.setBoolean(rank, (Boolean) value.value);
307                     break;
308                 case Types.TINYINT:
309                     if (value.value == null) {
310                         ps.setNull(rank, Types.TINYINT);
311                         break;
312                     }
313                     ps.setByte(rank, (Byte) value.value);
314                     break;
315                 case Types.SMALLINT:
316                     if (value.value == null) {
317                         ps.setNull(rank, Types.SMALLINT);
318                         break;
319                     }
320                     ps.setShort(rank, (Short) value.value);
321                     break;
322                 case Types.INTEGER:
323                     if (value.value == null) {
324                         ps.setNull(rank, Types.INTEGER);
325                         break;
326                     }
327                     ps.setInt(rank, (Integer) value.value);
328                     break;
329                 case Types.BIGINT:
330                     if (value.value == null) {
331                         ps.setNull(rank, Types.BIGINT);
332                         break;
333                     }
334                     ps.setLong(rank, (Long) value.value);
335                     break;
336                 case Types.REAL:
337                     if (value.value == null) {
338                         ps.setNull(rank, Types.REAL);
339                         break;
340                     }
341                     ps.setFloat(rank, (Float) value.value);
342                     break;
343                 case Types.DOUBLE:
344                     if (value.value == null) {
345                         ps.setNull(rank, Types.DOUBLE);
346                         break;
347                     }
348                     ps.setDouble(rank, (Double) value.value);
349                     break;
350                 case Types.VARBINARY:
351                     if (value.value == null) {
352                         ps.setNull(rank, Types.VARBINARY);
353                         break;
354                     }
355                     ps.setBytes(rank, (byte[]) value.value);
356                     break;
357                 case Types.DATE:
358                     if (value.value == null) {
359                         ps.setNull(rank, Types.DATE);
360                         break;
361                     }
362                     ps.setDate(rank, (Date) value.value);
363                     break;
364                 case Types.TIMESTAMP:
365                     if (value.value == null) {
366                         ps.setNull(rank, Types.TIMESTAMP);
367                         break;
368                     }
369                     ps.setTimestamp(rank, (Timestamp) value.value);
370                     break;
371                 case Types.CLOB:
372                     if (value.value == null) {
373                         ps.setNull(rank, Types.CLOB);
374                         break;
375                     }
376                     ps.setClob(rank, (Reader) value.value);
377                     break;
378                 case Types.BLOB:
379                     if (value.value == null) {
380                         ps.setNull(rank, Types.BLOB);
381                         break;
382                     }
383                     ps.setBlob(rank, (InputStream) value.value);
384                     break;
385                 default:
386                     throw new GoldenGateDatabaseSqlException("Type not supported: " +
387                             value.type + " at " + rank);
388             }
389         } catch (ClassCastException e) {
390             throw new GoldenGateDatabaseSqlException("Setting values casting error: " +
391                     value.type + " at " + rank, e);
392         } catch (SQLException e) {
393             DbSession.error(e);
394             throw new GoldenGateDatabaseSqlException("Setting values in error: " +
395                     value.type + " at " + rank, e);
396         }
397     }
398     /**
399      * Set one value to a DbPreparedStatement
400      * @param preparedStatement
401      * @param value
402      * @throws GoldenGateDatabaseNoConnectionException
403      * @throws GoldenGateDatabaseSqlException
404      */
405     protected void setValue(DbPreparedStatement preparedStatement, DbValue value)
406             throws GoldenGateDatabaseNoConnectionException, GoldenGateDatabaseSqlException {
407         PreparedStatement ps = preparedStatement.getPreparedStatement();
408         setTrueValue(ps, value, 1);
409     }
410     /**
411      * Set several values to a DbPreparedStatement
412      * @param preparedStatement
413      * @param values
414      * @throws GoldenGateDatabaseNoConnectionException
415      * @throws GoldenGateDatabaseSqlException
416      */
417     protected void setValues(DbPreparedStatement preparedStatement,
418             DbValue[] values) throws GoldenGateDatabaseNoConnectionException,
419             GoldenGateDatabaseSqlException {
420         PreparedStatement ps = preparedStatement.getPreparedStatement();
421         for (int i = 0; i < values.length; i ++) {
422             DbValue value = values[i];
423             setTrueValue(ps, value, i + 1);
424         }
425     }
426     /**
427      * Get one value into DbValue from ResultSet
428      * @param rs
429      * @param value
430      * @throws GoldenGateDatabaseSqlException
431      */
432     static public void getTrueValue(ResultSet rs, DbValue value)
433             throws GoldenGateDatabaseSqlException {
434         try {
435             switch (value.type) {
436                 case Types.VARCHAR:
437                     value.value = rs.getString(value.column);
438                     break;
439                 case Types.LONGVARCHAR:
440                     value.value = rs.getString(value.column);
441                     break;
442                 case Types.BIT:
443                     value.value = rs.getBoolean(value.column);
444                     break;
445                 case Types.TINYINT:
446                     value.value = rs.getByte(value.column);
447                     break;
448                 case Types.SMALLINT:
449                     value.value = rs.getShort(value.column);
450                     break;
451                 case Types.INTEGER:
452                     value.value = rs.getInt(value.column);
453                     break;
454                 case Types.BIGINT:
455                     value.value = rs.getLong(value.column);
456                     break;
457                 case Types.REAL:
458                     value.value = rs.getFloat(value.column);
459                     break;
460                 case Types.DOUBLE:
461                     value.value = rs.getDouble(value.column);
462                     break;
463                 case Types.VARBINARY:
464                     value.value = rs.getBytes(value.column);
465                     break;
466                 case Types.DATE:
467                     value.value = rs.getDate(value.column);
468                     break;
469                 case Types.TIMESTAMP:
470                     value.value = rs.getTimestamp(value.column);
471                     break;
472                 case Types.CLOB:
473                     value.value = rs.getClob(value.column).getCharacterStream();
474                     break;
475                 case Types.BLOB:
476                     value.value = rs.getBlob(value.column).getBinaryStream();
477                     break;
478                 default:
479                     throw new GoldenGateDatabaseSqlException("Type not supported: " +
480                             value.type + " for " + value.column);
481             }
482         } catch (SQLException e) {
483             DbSession.error(e);
484             throw new GoldenGateDatabaseSqlException("Getting values in error: " +
485                     value.type + " for " + value.column, e);
486         }
487     }
488     /**
489      * Get one value into DbValue from DbPreparedStatement
490      * @param preparedStatement
491      * @param value
492      * @throws GoldenGateDatabaseNoConnectionException
493      * @throws GoldenGateDatabaseSqlException
494      */
495     protected void getValue(DbPreparedStatement preparedStatement, DbValue value)
496             throws GoldenGateDatabaseNoConnectionException, GoldenGateDatabaseSqlException {
497         ResultSet rs = preparedStatement.getResultSet();
498         getTrueValue(rs, value);
499     }
500     /**
501      * Get several values into DbValue from DbPreparedStatement
502      * @param preparedStatement
503      * @param values
504      * @throws GoldenGateDatabaseNoConnectionException
505      * @throws GoldenGateDatabaseSqlException
506      */
507     protected void getValues(DbPreparedStatement preparedStatement,
508             DbValue[] values) throws GoldenGateDatabaseNoConnectionException,
509             GoldenGateDatabaseSqlException {
510         ResultSet rs = preparedStatement.getResultSet();
511         for (DbValue value: values) {
512             getTrueValue(rs, value);
513         }
514     }
515     /**
516      * Get Values from PreparedStatement
517      * 
518      * @param preparedStatement
519      * @return True if OK, else False
520      */
521     public boolean get(DbPreparedStatement preparedStatement) {
522         try {
523             getValues(preparedStatement, allFields);
524             setFromArray();
525         } catch (GoldenGateDatabaseNoConnectionException e1) {
526             return false;
527         } catch (GoldenGateDatabaseSqlException e1) {
528             return false;
529         }
530         isSaved = true;
531         return true;
532     }
533 }