KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jorm > mapper > rdb > lib > RdbPMapCluster


1 /**
2  * JORM: an implementation of a generic mapping system for persistent Java
3  * objects. Two mapping are supported: to RDBMS and to binary files.
4  * Copyright (C) 2001-2003 France Telecom R&D - INRIA
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  * Contact: jorm-team@objectweb.org
21  *
22  */

23
24 package org.objectweb.jorm.mapper.rdb.lib;
25
26 import org.objectweb.jorm.api.PException;
27 import org.objectweb.jorm.api.PExceptionIO;
28 import org.objectweb.jorm.mapper.rdb.adapter.api.RdbAdapter;
29 import org.objectweb.jorm.lib.AbstractPMapcluster;
30 import org.objectweb.util.monolog.api.BasicLevel;
31
32 import java.util.ArrayList JavaDoc;
33 import java.util.HashMap JavaDoc;
34 import java.util.Iterator JavaDoc;
35 import java.util.Map JavaDoc;
36 import java.util.HashSet JavaDoc;
37 import java.io.FileWriter JavaDoc;
38 import java.io.IOException JavaDoc;
39 import java.sql.Connection JavaDoc;
40 import java.sql.SQLException JavaDoc;
41 import java.sql.Statement JavaDoc;
42
43 /**
44  * Defines the PMapCluster used to manage relational schema for the RDB
45  * mappers.
46  * @author P. Dechamboux
47  */

48 public class RdbPMapCluster extends AbstractPMapcluster {
49
50     
51     /**
52      * The list of table managed by this PMapCluster. It contains Table instance.
53      */

54     private ArrayList JavaDoc tables;
55     
56     private RdbPMappingStructuresManager manager;
57     private RdbAdapter adapter;
58     /**
59      * Constructs a RdbPMapCluster for an abstract class.
60      * @param jcname The first JORM class name to be assigned to this cluster.
61      * @param man The manager associated to these mapping structures.
62      */

63     RdbPMapCluster(String JavaDoc jcname, RdbPMappingStructuresManager man) {
64         super();
65         manager = man;
66         jcNames = new HashSet JavaDoc(1);
67         unresolvedDependencies.add(jcname);
68         tables = new ArrayList JavaDoc(1);
69         structuresActive = false;
70         if (this.manager.getPMapper() != null) {
71             adapter = ((PMapperRdb) this.manager.getPMapper()).getRdbAdapter();
72         }
73     }
74
75     /**
76      * Constructs a RdbPMapCluster.
77      * @param jcname The first JORM class name to be assigned to this cluster.
78      * @param tname The first table name to be assigned to this cluster.
79      * @param man The manager associated to these mapping structures.
80      */

81     RdbPMapCluster(String JavaDoc jcname, String JavaDoc tname, RdbPMappingStructuresManager man) {
82         this(jcname, man);
83         tables.add(new Table(tname, this));
84     }
85
86
87     /**
88      * Defines a new table column into this map cluster if it does not already
89      * exist. If it exist, it verifies that the redefinition is compatible with
90      * existing information.
91      * @param tname The table name.
92      * @param cname The column name.
93      * @param type The SQL type of this column.
94      * @param notnull The notnull status of this column.
95      * @throws PException Thrown if the column is redefined with incompatible
96      * information.
97      */

98     void addTableColumn(String JavaDoc tname, String JavaDoc cname, String JavaDoc type,
99                         boolean notnull, boolean ispkcol, boolean isMaster) throws PException {
100         Table curt = null;
101         Iterator JavaDoc it = tables.iterator();
102         while (it.hasNext()) {
103             curt = (Table) it.next();
104             if (curt.name.equals(tname)) {
105                 break;
106             }
107             curt = null;
108         }
109         if (curt == null) {
110             // no such table defined yet: create a new one
111
curt = new Table(tname, this);
112             tables.add(curt);
113         }
114         Column c = curt.getColumn(cname);
115         if (c == null) {
116             curt.addColumn(cname, type, notnull, ispkcol, isMaster);
117         } else if (isMaster) {
118             if (c.isMaster) {
119                 if (!c.type.equals(type)) {
120                     if (ispkcol && !c.isPkCol) {
121                         c.notNull = notnull;
122                         c.isPkCol = ispkcol;
123                         c.type = type;
124                     } else if (!ispkcol && c.isPkCol) {
125                         //nothing to do
126
} else {
127                         throw new PException(
128                                 "Incompatible column definition: existing: " + c
129                                 + " asked : Column (name:" + cname
130                                 + ", type:" + type
131                                 + ", notNull:" + notnull
132                                 + ", isMaster:" + isMaster
133                                 + ", isPkCol:" + ispkcol
134                                 + ")");
135                     }
136                 }
137             } else {
138                 c.isMaster = true;
139                 c.notNull = notnull;
140                 c.isPkCol = ispkcol;
141                 c.type = type;
142             }
143         }
144     }
145         
146    
147
148
149
150     /**
151      * Looks for this specified column into this map cluster.
152      * @param tname The table name.
153      * @param cname The column name.
154      * @param type The SQL type of this column.
155      * @param notnull The notnull status of this column.
156      * @throws PException Thrown if the column is redefined with incompatible
157      * information.
158      */

159     boolean containColumn(String JavaDoc tname, String JavaDoc cname, String JavaDoc type,
160                           boolean notnull) throws PException {
161         Table curt = null;
162         Iterator JavaDoc it = tables.iterator();
163         while (it.hasNext()) {
164             curt = (Table) it.next();
165             if (curt.name.equals(tname)) {
166                 break;
167             }
168             curt = null;
169         }
170         if (curt == null) {
171             // no such table defined yet : create a new one
172
return false;
173         }
174         return curt.containColumn(cname, type, notnull);
175     }
176
177     /**
178      * Looks for this table name into this map cluster.
179      * @param tname The table name.
180      * @return true if this table name is already assigned to this cluster.
181      */

182     boolean containTable(String JavaDoc tname) {
183         Iterator JavaDoc it = tables.iterator();
184         while (it.hasNext()) {
185             Table cur = (Table) it.next();
186             if (cur.name.equals(tname))
187                 return true;
188         }
189         return false;
190     }
191
192     /**
193      * Looks for this table name into this map cluster.
194      * @param tname The table name.
195      * @return true if this table name is already assigned to this cluster.
196      */

197     Table getTable(String JavaDoc tname) {
198         Iterator JavaDoc it = tables.iterator();
199         while (it.hasNext()) {
200             Table cur = (Table) it.next();
201             if (cur.name.equals(tname))
202                 return cur;
203         }
204         return null;
205     }
206
207     /**
208      * Merges map cluster passed in parameter with this one. Clusters are merged
209      * either because they share a table name or a JORM class name.
210      * @param cl
211      */

212     void merge(RdbPMapCluster cl) throws PException {
213         jcNames.addAll(cl.jcNames);
214         unresolvedDependencies.addAll(cl.getUnResolvedDependencies());
215         unresolvedDependencies.removeAll(jcNames);
216         for (int i = 0; i < cl.tables.size(); i++) {
217             Table cur = (Table) cl.tables.get(i);
218             Table t = getTable(cur.name);
219             if (t == null) {
220                 tables.add(cur);
221             } else {
222                 t.merge(cur);
223             }
224         }
225     }
226     
227    
228
229
230     // IMPLEMENTATION OF METHODS FROM THE PMapCluster INTERFACE
231

232
233     /**
234      * Creates the mapping structures defined by this map cluster.
235      * @param force If true, the creation of an existing table leads to an exception.
236      * @throws PException Thrown if it cannot be performed (especially
237      * if all or some of these mapping structures already exist.
238      */

239     public void createMappingStructures(boolean force) throws PException {
240         if (structuresActive) {
241             throw new PException("Cannot change mapping structures while they are under use");
242         }
243         if (!isDefined()) {
244             throw new PException("Cannot create hosting struture: the " +
245                                  "following dependencies has not been resolved: "
246                                  + unresolvedDependencies);
247         }
248         if ((manager instanceof RdbScriptWriter)
249                 && ((RdbScriptWriter)manager).isWriteScript()) {
250             // generate create statements
251
Iterator JavaDoc it = tables.iterator();
252             while (it.hasNext()) {
253                 Table table = (Table) it.next();
254                 table.create(null);
255             }
256         } else {
257             Object JavaDoc conn = manager.getConnection();
258             try {
259             
260                 // creates the tables
261
Iterator JavaDoc it = tables.iterator();
262                 while (it.hasNext()) {
263                     Table table = (Table) it.next();
264                     if (table.exist(RdbConnectionWrapper.narrow2SQL(conn), adapter)) {
265                         if (force) {
266                             throw new PException("Cannot create table " + table.name + ": already exist");
267                         }
268                     } else {
269                         table.create(RdbConnectionWrapper.narrow2SQL(conn));
270                     }
271                 }
272             
273             
274             } finally {
275                 manager.closeConnection(conn);
276             }
277         }
278     }
279
280     /**
281      * Deletes the data that have been inserted into the mapping structures
282      * defined by this map cluster.
283      * @throws PException Thrown when the data store cannot perform this
284      * operation.
285      */

286     public void deleteData() throws PException {
287         if (!isDefined()) {
288             throw new PException("Cannot remove data: the " +
289                                  "following dependencies has not been resolved: "
290                                  + unresolvedDependencies);
291         }
292         if ((manager instanceof RdbScriptWriter)
293                 && ((RdbScriptWriter)manager).isWriteScript()) {
294             //generate delete statements
295
Iterator JavaDoc it = tables.iterator();
296             while (it.hasNext()) {
297                 Table table = (Table) it.next();
298                 table.deleteData(null);
299             }
300         } else {
301             Object JavaDoc conn = manager.getConnection();
302             try {
303                 Iterator JavaDoc it = tables.iterator();
304                 while (it.hasNext()) {
305                     Table table = (Table) it.next();
306                     if (table.exist(RdbConnectionWrapper.narrow2SQL(conn), adapter)) {
307                         table.deleteData(RdbConnectionWrapper.narrow2SQL(conn));
308                     } else {
309                         manager.logger.log(BasicLevel.WARN,
310                                        "Impossible to delete the data of the table '"
311                                        + table.name + "': table does not exist.");
312                     }
313                 }
314             } finally {
315                 manager.closeConnection(conn);
316             }
317         }
318     }
319
320     /**
321      * Deletes all or part of the mapping structures defined by this map
322      * cluster when they exist. If they contain some data, they are also
323      * deleted.
324      * @throws PException Thrown when the data store cannot perform this
325      * operation.
326      */

327     public void deleteMappingStructures() throws PException {
328         if (structuresActive) {
329             throw new PException("Cannot change mapping structures while they are under use");
330         }
331         if (!isDefined()) {
332             throw new PException("Cannot delete hosting struture: the " +
333                                  "following dependencies has not been resolved: "
334                                  + unresolvedDependencies);
335         }
336         if ((manager instanceof RdbScriptWriter)
337                 && ((RdbScriptWriter)manager).isWriteScript()) {
338             //generate drop statements
339
Iterator JavaDoc it = tables.iterator();
340             while (it.hasNext()) {
341                 Table table = (Table) it.next();
342                 table.delete(null);
343             }
344         } else {
345             Object JavaDoc conn = manager.getConnection();
346             try {
347                 // deletes tables
348
Iterator JavaDoc it = tables.iterator();
349                 while (it.hasNext()) {
350                     Table table = (Table) it.next();
351                     if (table.exist(RdbConnectionWrapper.narrow2SQL(conn), adapter)) {
352                         table.delete(RdbConnectionWrapper.narrow2SQL(conn));
353                     }
354                 }
355             } finally {
356                 manager.closeConnection(conn);
357             }
358         }
359     }
360
361     public RdbPMappingStructuresManager getManager() {
362         return manager;
363     }
364 }
365
366
367 /**
368  * Describes a table into a map cluster.
369  */

370 class Table {
371     String JavaDoc name;
372     ArrayList JavaDoc columns;
373     RdbPMapCluster cluster;
374
375
376     Table(String JavaDoc tname, RdbPMapCluster cluster) {
377         name = tname;
378         this.cluster = cluster;
379         columns = new ArrayList JavaDoc();
380     }
381
382     void addColumn(String JavaDoc cname, String JavaDoc type, boolean notnull, boolean ispkcol, boolean ismaster)
383             throws PException {
384         Column cur;
385         cur = new Column();
386         cur.name = cname;
387         cur.type = type;
388         cur.notNull = notnull;
389         cur.isPkCol = ispkcol;
390         cur.isMaster = ismaster;
391         columns.add(cur);
392     }
393
394     void merge(Table t) throws PException {
395         for (int i = 0; i < t.columns.size(); i++) {
396             Column cur = (Column) t.columns.get(i);
397             Column c = getColumn(cur.name);
398             if (c == null) {
399                 columns.add(cur);
400             } else {
401                 c.merge(cur);
402             }
403         }
404     }
405
406     boolean containColumn(String JavaDoc cname, String JavaDoc type,
407                           boolean notnull) throws PException {
408         Column cur;
409         Iterator JavaDoc it = columns.iterator();
410         while (it.hasNext()) {
411             cur = (Column) it.next();
412             if (cur.name.equals(cname)) {
413                 return true;
414             }
415         }
416         return false;
417     }
418
419     Column getColumn(String JavaDoc cname) {
420         Column cur;
421         Iterator JavaDoc it = columns.iterator();
422         while (it.hasNext()) {
423             cur = (Column) it.next();
424             if (cur.name.equals(cname)) {
425                 return cur;
426             }
427         }
428         return null;
429     }
430
431     void create(Connection JavaDoc connection) throws PException {
432         Statement JavaDoc stmt = null;
433         StringBuffer JavaDoc sb = new StringBuffer JavaDoc("CREATE TABLE " + name + " (");
434         try {
435             String JavaDoc sep = "";
436             Iterator JavaDoc it = columns.iterator();
437             while (it.hasNext()) {
438                 sb.append(sep);
439                 sep = ", ";
440                 Column col = (Column) it.next();
441                 sb.append(col.name);
442                 sb.append(" ");
443                 sb.append(col.type);
444                 if (col.notNull && col.type.indexOf("NOT NULL") == -1) {
445                     sb.append(" NOT NULL");
446                 }
447             }
448             sep = "";
449             it = columns.iterator();
450             while (it.hasNext()) {
451                 Column col = (Column) it.next();
452                 if (!col.isPkCol) {
453                     continue;
454                 }
455                 if (sep.equals("")) {
456                     sb.append(", PRIMARY KEY (");
457                 }
458                 sb.append(sep);
459                 sep = ", ";
460                 sb.append(col.name);
461             }
462             if (!sep.equals("")) {
463                 sb.append(")");
464             }
465             sb.append(")");
466             
467             //if generate script, then write into a file
468
//else, execute statement on the database
469
if(cluster.getManager() instanceof RdbScriptWriter && ((RdbScriptWriter)cluster.getManager()).isWriteScript()) {
470                 FileWriter JavaDoc writer = new FileWriter JavaDoc(((RdbScriptWriter)cluster.getManager()).getFileName(), true);
471                 writer.write(sb.toString() + ";\n");
472                 writer.close();
473             } else {
474                 stmt = connection.createStatement();
475                 stmt.execute(sb.toString());
476             }
477         } catch (SQLException JavaDoc se) {
478             throw new PExceptionIO(se, "Impossible to create the table '"
479                     + name + "' of the cluster " + cluster.getClusterClasses()
480                     + " : " + sb.toString());
481         } catch(IOException JavaDoc ioe) {
482             throw new PExceptionIO(ioe, "Problem while writting create statement in the sql script file");
483         } finally {
484             if (stmt != null) {
485                 try {
486                     stmt.close();
487                 } catch (SQLException JavaDoc e) {
488                 }
489             }
490         }
491     }
492
493     void deleteData(Connection JavaDoc connection) throws PException {
494         Statement JavaDoc stmt = null;
495         PException resex = null;
496         try {
497             StringBuffer JavaDoc sb = new StringBuffer JavaDoc("DELETE FROM " + name);
498             //if generate script, then write into a file
499
//else, execute statement on the database
500
if(cluster.getManager() instanceof RdbScriptWriter && ((RdbScriptWriter)cluster.getManager()).isWriteScript()) {
501                 FileWriter JavaDoc writer = new FileWriter JavaDoc(((RdbScriptWriter)cluster.getManager()).getFileName(), true);
502                 writer.write(sb.toString() + ";\n");
503                 writer.close();
504             } else {
505                 stmt = connection.createStatement();
506                 stmt.execute(sb.toString());
507             }
508         } catch (SQLException JavaDoc se) {
509             resex = new PExceptionIO(se, "SQL problem while deleting data: class <" + name + ">");
510         } catch(IOException JavaDoc ioe) {
511             throw new PExceptionIO(ioe, "Problem while writting delete statement in the sql script file");
512         } finally {
513             if (stmt != null) {
514                 try {
515                     stmt.close();
516                 } catch (SQLException JavaDoc e) {
517                     if (resex == null) {
518                         resex = new PException(e, "Problem while closing statment.");
519                     }
520                 }
521             }
522             if (resex != null) {
523                 throw resex;
524             }
525         }
526     }
527
528     void delete(Connection JavaDoc connection) throws PException {
529         Statement JavaDoc stmt = null;
530         PException resex = null;
531         try {
532             StringBuffer JavaDoc sb = new StringBuffer JavaDoc("DROP TABLE " + name);
533             //if generate script, then write into a file
534
//else, execute statement on the database
535
if(cluster.getManager() instanceof RdbScriptWriter && ((RdbScriptWriter)cluster.getManager()).isWriteScript()) {
536                 FileWriter JavaDoc writer = new FileWriter JavaDoc(((RdbScriptWriter)cluster.getManager()).getFileName(), true);
537                 writer.write(sb.toString() + ";\n");
538                 writer.close();
539             } else {
540                 stmt = connection.createStatement();
541                 stmt.execute(sb.toString());
542             }
543         } catch (java.sql.SQLException JavaDoc se) {
544             resex = new PExceptionIO(se);
545         } catch(IOException JavaDoc ioe) {
546             throw new PExceptionIO(ioe, "Problem while writting drop table statement in the sql script file");
547         } finally {
548             if (stmt != null) {
549                 try {
550                     stmt.close();
551                 } catch (SQLException JavaDoc e) {
552                     if (resex == null) {
553                         resex = new PException(e, "Problem while closing statment.");
554                     }
555                 }
556             }
557             if (resex != null) {
558                 throw resex;
559             }
560         }
561     }
562
563     boolean exist(Connection JavaDoc connection, RdbAdapter adapter) throws PException {
564         try {
565             return adapter.existTable(connection, name);
566         } catch (SQLException JavaDoc e) {
567             throw new PException(e, "Pb while testing the existence of table " + name);
568         }
569     }
570 }
571
572 /**
573  * Describes a column into a table description into a map cluster.
574  */

575 class Column {
576     String JavaDoc name;
577     String JavaDoc type;
578     boolean notNull;
579     boolean isPkCol;
580     boolean isMaster;
581
582     void merge(Column c) throws PException {
583         if (type != c.type) {
584             throw new PException("Impossible to merge the column " + name
585                                  + ": column type does not match");
586         }
587         if (c.isMaster) {
588             notNull = c.notNull;
589             isPkCol |= c.isPkCol;
590         }
591     }
592
593     public String JavaDoc toString() {
594         return "Column (name:" + name
595                 + ", type:" + type
596                 + ", notNull:" + notNull
597                 + ", isMaster:" + isMaster
598                 + ", isPkCol:" + isPkCol
599                 + ")";
600     }
601 }
602
Popular Tags