KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jac > aspects > distrans > persistence > SimpleDbPersistence


1 /*
2   Copyright (C) 2001-2003 Lionel Seinturier <Lionel.Seinturier@lip6.fr>
3
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU Lesser General Public License as
6   published by the Free Software Foundation; either version 2 of the
7   License, or (at your option) any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12   GNU Lesser General Public License for more details.
13
14   You should have received a copy of the GNU Lesser General Public License
15   along with this program; if not, write to the Free Software
16   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */

17
18 package org.objectweb.jac.aspects.distrans.persistence;
19
20 import org.objectweb.jac.core.NameRepository;
21 import org.objectweb.jac.core.rtti.ClassItem;
22 import org.objectweb.jac.core.rtti.ClassRepository;
23 import org.objectweb.jac.core.rtti.FieldItem;
24 import org.objectweb.jac.util.Repository;
25
26 import java.sql.Connection JavaDoc;
27 import java.sql.PreparedStatement JavaDoc;
28 import java.sql.ResultSet JavaDoc;
29 import java.sql.SQLException JavaDoc;
30 import java.sql.Statement JavaDoc;
31 import java.util.Collection JavaDoc;
32 import java.util.HashMap JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.Map JavaDoc;
35
36 import javax.transaction.HeuristicMixedException JavaDoc;
37 import javax.transaction.HeuristicRollbackException JavaDoc;
38 import javax.transaction.NotSupportedException JavaDoc;
39 import javax.transaction.RollbackException JavaDoc;
40 import javax.transaction.SystemException JavaDoc;
41
42 import org.enhydra.jdbc.standard.StandardXADataSource;
43
44 /**
45  * Basic transaction-enabled persistence storage.
46  *
47  * Data is stored in SQL tables.
48  * Each table contains object field values and owns one more attribute
49  * than its associated class contains field. The additional attribute
50  * stores the object name.
51  *
52  * @author Lionel Seinturier <Lionel.Seinturier@lip6.fr>
53  * @version 1.0
54  */

55 public class SimpleDbPersistence implements PersistenceItf {
56
57     /**
58      * The name of the attribute storing the persistent object name
59      * in SQL tables.
60      */

61     final static private String JavaDoc objectAttributeName = "_objname";
62
63     
64     /**
65      * Create a SQL table to hold persistent data.
66      * Implements PersistenceItf#createStorageIfNeeded()
67      *
68      * The table is not created if it already exists. This enables to reuse
69      * existing tables to map their content to JAC objects. However, this may
70      * cause problems if the schema is different than the expected one. In
71      * such a case, call createStorage instead.
72      *
73      * @param className the class name for which we want to create a table
74      * @param ds the data source
75      */

76     public void initStorageIfNeeded( String JavaDoc className, StandardXADataSource ds ) {
77         try {
78             _initStorageIfNeeded(className,ds);
79         } catch (SQLException JavaDoc e) {
80             e.printStackTrace();
81             System.exit(1);
82         }
83     }
84     
85     private void _initStorageIfNeeded( String JavaDoc className, StandardXADataSource ds )
86         throws SQLException JavaDoc {
87
88         /**
89          * Check whether a table exists for each element of classNames.
90          * The table name is the class name where dots delimiting package
91          * names are replaced by underscores.
92          */

93         Connection JavaDoc connection = XAPoolCache.getConnection(ds);
94         
95         String JavaDoc tableName = className.replace('.','_');
96         Statement JavaDoc st = connection.createStatement();
97         try {
98             st.executeQuery("SELECT * FROM "+tableName);
99         }
100         catch (SQLException JavaDoc sqle) {
101             /**
102              * If the table does not exist, the expected behavior is
103              * to throw a SQLException. In such a case, create the table.
104              */

105             initStorage(className,connection);
106         }
107     }
108     
109     
110     /**
111      * Create a SQL table to hold persistent data.
112      * If the table exists, it is deleted first.
113      * Implements PersistenceItf#createStorage()
114      *
115      * @param className the class name for which we want to create a table
116      * @param ds the data source
117      */

118     public void initStorage( String JavaDoc className, StandardXADataSource ds ) {
119         try {
120             _initStorage(className,ds);
121         } catch (SQLException JavaDoc e) {
122             e.printStackTrace();
123             System.exit(1);
124         }
125     }
126     
127     private void _initStorage( String JavaDoc className, StandardXADataSource ds )
128         throws SQLException JavaDoc {
129
130         /**
131          * Check whether a table exists for each element of classNames.
132          */

133         Connection JavaDoc connection = XAPoolCache.getConnection(ds);
134         
135         /**
136          * The table name is the class name where dots delimiting package
137          * names are replaced by underscores.
138          */

139         String JavaDoc tableName = className.replace('.','_');
140         Statement JavaDoc st = connection.createStatement();
141         try {
142             st.executeQuery("DROP TABLE "+tableName);
143         }
144         catch (SQLException JavaDoc sqle) {
145             /**
146              * If the table does not exist, the expected behavior is
147              * to throw a SQLException.
148              */

149         }
150         
151         initStorage(className,connection);
152     }
153
154     
155     /**
156      * Create a SQL table to hold persistent data.
157      *
158      * @param className the class name
159      * @param connection the connection towards the database
160      */

161     private void initStorage( String JavaDoc className, Connection JavaDoc connection )
162         throws SQLException JavaDoc {
163         
164         /**
165          * The table name is the class name where dots delimiting package names
166          * are replaced by underscores.
167          */

168         String JavaDoc tableName = className.replace('.','_');
169                 
170         String JavaDoc sql =
171             "CREATE TABLE "+tableName+" ( "+
172             objectAttributeName+" VARCHAR PRIMARY KEY";
173             
174         ClassItem classItem = classes.getClass(className);
175         Collection JavaDoc fields = classItem.getAllFields();
176         for (Iterator JavaDoc iter = fields.iterator(); iter.hasNext();) {
177             FieldItem field = (FieldItem) iter.next();
178             String JavaDoc fieldName = field.getName();
179             String JavaDoc fieldType = field.getType().getName();
180             String JavaDoc sqlType = (String JavaDoc) SimpleDbPersistence.javaTypesToSQL.get(fieldType);
181             sql += ", "+fieldName+" "+sqlType;
182         }
183         sql += ");";
184         
185         Statement JavaDoc st = connection.createStatement();
186         st.executeUpdate(sql);
187         st.close();
188     }
189     
190     /**
191      * Store mappings between Java types and SQL ones.
192      * For now on, this is only a quick-and-dirty partial mapping.
193      * To be completed.
194      */

195     private static Map JavaDoc javaTypesToSQL = new HashMap JavaDoc();
196     static {
197         javaTypesToSQL.put("java.lang.String","VARCHAR");
198         javaTypesToSQL.put("int","INT");
199         javaTypesToSQL.put("double","DOUBLE PRECISION");
200     }
201     
202     
203     /**
204      * Store an object into the persistence storage.
205      * Implements PersistenceItf#load()
206      *
207      * @param wrappee the object to store
208      * @param name the identifier for the object
209      * @param ds the data source
210      */

211     public void load( Object JavaDoc wrappee, String JavaDoc name, StandardXADataSource ds )
212         throws SQLException JavaDoc, IllegalArgumentException JavaDoc, IllegalAccessException JavaDoc, NotSupportedException JavaDoc, SecurityException JavaDoc, IllegalStateException JavaDoc, RollbackException JavaDoc, HeuristicMixedException JavaDoc, HeuristicRollbackException JavaDoc, SystemException JavaDoc {
213                 
214         ClassItem classItem = classes.getClass(wrappee);
215         
216         /**
217          * Get a prepared statement to fetch the data.
218          * It may be cached in the selectStatements map.
219          */

220         Connection JavaDoc connection = XAPoolCache.getConnection(ds);
221
222         PreparedStatement JavaDoc ps =
223             createSelectStatement(connection,classItem);
224         ps.setString(1,name);
225         ResultSet JavaDoc rs = ps.executeQuery();
226         
227         /**
228          * The object hasn't been found in the storage.
229          * The most likely reason is that it has never been
230          * written before. In such a case, do nothing (ie don't
231          * reflect any value on the wrappee).
232          */

233         boolean found = rs.next();
234         if (!found) return;
235         
236         /**
237          * Set fields with values retrieved from the ResultSet.
238          * Start at index 2 to skip the wrappeeName.
239          */

240         Collection JavaDoc fields = classItem.getAllFields();
241         int i=2;
242         for (Iterator JavaDoc iter = fields.iterator(); iter.hasNext();i++) {
243             FieldItem field = (FieldItem) iter.next();
244             Object JavaDoc value = rs.getObject(i);
245             field.set(wrappee,value);
246         }
247         rs.close();
248     }
249
250     
251     /**
252      * Update an object with the values retrieved from the persistent
253      * storage.
254      * Implements PersistenceItf#store()
255      *
256      * @param wrappee the object to update
257      * @param name the identifier for the object
258      * @param ds the data source
259      */

260     public void store( Object JavaDoc wrappee, String JavaDoc name, StandardXADataSource ds )
261         throws Exception JavaDoc {
262
263         ClassItem classItem = classes.getClass(wrappee);
264         
265         /**
266          * Save the wrappee field values into the database.
267          * Get a prepared statement to update the data.
268          * It may be cached in the updateStatements map.
269          */

270         Connection JavaDoc connection = XAPoolCache.getConnection(ds);
271         
272         PreparedStatement JavaDoc ps =
273             createUpdateStatement(connection,classItem);
274         
275         Collection JavaDoc fields = classItem.getAllFields();
276         int i=1;
277         for (Iterator JavaDoc iter = fields.iterator(); iter.hasNext();i++) {
278             FieldItem field = (FieldItem) iter.next();
279             Object JavaDoc value = field.get(wrappee);
280             ps.setObject(i,value);
281         }
282         ps.setString(i,name);
283         
284         /**
285          * Update the data in the table.
286          * If 0 row have been updates, the row didn't exist yet, create it.
287          */

288         int rowCount = ps.executeUpdate();
289         
290         if ( rowCount == 0 ) {
291             PreparedStatement JavaDoc insertps =
292                 createInsertStatement(
293                     connection,classItem,wrappee,name
294                 );
295             insertps.executeUpdate();
296             insertps.close();
297             ps.executeUpdate();
298         }
299     }
300
301     /**
302      * Create an INSERT SQL request to store the field values of an object.
303      * Each field is mapped onto a SQL attribute.
304      * The table contains one more attribute which is the name of the wrappee,
305      * and which is also the primary key of the table.
306      *
307      * @param connection the connection towards the database
308      * @param cl the class
309      * @param wrappee the persistent object (ie the wrappee)
310      * @param wrappeeName the wrappee name
311      * @return the prepared statement
312      */

313     private static PreparedStatement JavaDoc createInsertStatement(
314         Connection JavaDoc connection, ClassItem cl,
315         Object JavaDoc wrappee, String JavaDoc wrappeeName ) throws SQLException JavaDoc {
316             
317         /**
318          * The table name is the class name where dots delimiting package names
319          * are replaced by underscores.
320          */

321         String JavaDoc tableName = cl.getName();
322         tableName = tableName.replace('.','_');
323         String JavaDoc request = "INSERT INTO "+tableName+" VALUES (?";
324     
325         Collection JavaDoc fields = cl.getAllFields();
326         for (Iterator JavaDoc iter = fields.iterator(); iter.hasNext();) {
327             iter.next();
328             request += ",?";
329         }
330     
331         request += ");";
332         
333         PreparedStatement JavaDoc ps = connection.prepareStatement(request);
334     
335         ps.setString(1,wrappeeName);
336         int i=2;
337         for (Iterator JavaDoc iter = fields.iterator(); iter.hasNext();i++) {
338             iter.next();
339             ps.setObject(i,null);
340         }
341         
342         return ps;
343     }
344     
345     /**
346      * Create a SELECT SQL request to fetch the field values of an object.
347      * Each field is mapped onto a SQL attribute.
348      * The table contains one more attribute which is the name of the wrappee,
349      * and which is also the primary key of the table.
350      *
351      * @param connection the connection towards the database
352      * @param cl the class
353      * @return the prepared statement
354      */

355     static private PreparedStatement JavaDoc createSelectStatement(
356         Connection JavaDoc connection, ClassItem cl ) throws SQLException JavaDoc {
357             
358         /**
359          * The table name is the class name where dots delimiting package names
360          * are replaced by underscores.
361          */

362         String JavaDoc tableName = cl.getName();
363         tableName = tableName.replace('.','_');
364         String JavaDoc request =
365             "SELECT * FROM "+tableName+" WHERE "+
366             objectAttributeName+"=?;";
367
368         return connection.prepareStatement(request);
369     }
370
371     /**
372      * Create an UPDATE SQL request to store the field values of an object.
373      * Each field is mapped onto a SQL attribute.
374      * The table contains one more attribute which is the name of the wrappee,
375      * and which is also the primary key of the table.
376      *
377      * @param connection the connection towards the database
378      * @param cl the class
379      * @return the prepared statement
380      */

381     static private PreparedStatement JavaDoc createUpdateStatement(
382         Connection JavaDoc connection, ClassItem cl ) throws SQLException JavaDoc {
383             
384         /**
385          * The table name is the class name where dots delimiting package names
386          * are replaced by underscores.
387          */

388         String JavaDoc tableName = cl.getName();
389         tableName = tableName.replace('.','_');
390         String JavaDoc request = "UPDATE "+tableName+" SET ";
391         
392         Collection JavaDoc fields = cl.getAllFields();
393         boolean first = true;
394         for (Iterator JavaDoc iter = fields.iterator(); iter.hasNext();) {
395             FieldItem field = (FieldItem) iter.next();
396             String JavaDoc name = field.getName();
397             
398             if (first) first = false;
399             else request += ",";
400             request += name + "=?";
401         }
402         
403         request += " WHERE "+objectAttributeName+"=?;";
404         
405         return connection.prepareStatement(request);
406     }
407
408     /**
409      * The reference towards the RTTI class repository.
410      */

411     private ClassRepository classes = ClassRepository.get();
412
413     /**
414      * The reference towards the JAC name repository.
415      * Needed by applyPersistence().
416      */

417     private Repository names = NameRepository.get();
418 }
419
Popular Tags