KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > extractor > metadata > Loader


1 /*
2  * This file belongs to the XQuark distribution.
3  * Copyright (C) 2003 Universite de Versailles Saint-Quentin.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307.
18  * You can also get it at http://www.gnu.org/licenses/lgpl.html
19  *
20  * For more information on this software, see http://www.xquark.org.
21  */

22
23 package org.xquark.extractor.metadata;
24
25 import java.sql.*;
26 import java.util.*;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.xquark.extractor.common.MessageLibrary;
31 import org.xquark.extractor.common.MetaDataException;
32 import org.xquark.extractor.runtime.Selection;
33 import org.xquark.jdbc.typing.ColumnMetaData;
34 import org.xquark.jdbc.typing.DBMSInfo;
35 import org.xquark.jdbc.typing.JDBCProperties;
36
37 /**
38  * Base class for metadata path tree building from JDBC metadata applying
39  * filters defined in the configuration file. This class will be derived for
40  * every RDBMS supported.
41  */

42 public abstract class Loader {
43
44     private static final String JavaDoc RCSRevision = "$Revision: 1.24 $";
45     private static final String JavaDoc RCSName = "$Name: $";
46
47     private static Log log = LogFactory.getLog(Loader.class);
48
49     /* Maintains a map from XML names to DBMS name for table and columns */
50     public Properties _tableMap = new Properties();
51
52     protected Connection _connection;
53     protected DatabaseMetaData _databaseMetaData;
54     protected DBMSInfo _dbmsInfo;
55     protected HashSet _nameSpaces = new HashSet();
56     protected QNameEncoder _encoder = null;
57
58     public Loader(Connection connection, DBMSInfo dbmsInfo, QNameEncoder encoder) throws SQLException {
59         _connection = connection;
60         _databaseMetaData = connection.getMetaData();
61         _dbmsInfo = dbmsInfo;
62         _encoder = encoder;
63     }
64
65     /**
66      * Main entry point performing path tree construction. Browse JDBC catalogs
67      * calling sub-procedure for schemas if matching the selection.
68      * @param selection A user-defined filter used for catalogs.
69      * @return The root metadata node created for the source (Site).
70      * @throws MetaDataException
71      * @see org.xquark.extractor.metadata.NamedNode
72      */

73     public Site loadSite(Selection selection, JDBCProperties JDBCprop) throws MetaDataException {
74
75         Site retVal = new Site(null);
76         List children = new ArrayList();
77         List subSelections = new ArrayList();
78         ResultSet resultSet = null;
79         String JavaDoc name = null;
80
81         _nameSpaces.clear();
82
83         try {
84             String JavaDoc defCatalog = getDefaultCatalog();
85
86             if (null == selection) {
87                 selection = new Selection(null, null, Selection.INCLUDES, new HashMap());
88             }
89             
90              if (selection.noSubElementDef()) {
91                 Selection catalogSel = new Selection(defCatalog, null, Selection.INCLUDES, new HashMap());
92                 selection.addToMap(defCatalog, catalogSel);
93             }
94
95             /* JDBC catalog browsing */
96             resultSet = _databaseMetaData.getCatalogs();
97             Selection subSelection = null;
98             while (resultSet.next()) {
99                 name = resultSet.getString("TABLE_CAT");
100                 subSelection = selection.includesSubElement(name);
101                 if (subSelection != null) {
102                     // TODO : No indications left by YS on this...
103
// if (CASE_TOLOWER == _nameCase ) name = name.toLowerCase();
104
// else if (CASE_TOUPPER== _nameCase) name = name.toUpperCase();
105
children.add(name);
106                     subSelections.add(subSelection);
107                 }
108             }
109             resultSet.close();
110
111             /* Case where the catalog name is unspecified */
112             subSelection = selection.includesSubElement(null);
113             if (subSelection != null) {
114                 if (defCatalog == null) {
115                     children.add(null);
116                     subSelections.add(subSelection);
117                 } else {
118                     children.add(defCatalog);
119                     subSelection.setNameForDefault(defCatalog);
120                     subSelections.add(subSelection);
121                 }
122             }
123
124             if (children.isEmpty()) {
125                 throw new MetaDataException("Wrong catalog configuration specification. Check your configuration file.");
126             }
127
128             /* Browse filtered catalogs for building */
129             for (int i = 0; i < children.size(); i++) {
130                 String JavaDoc child = (String JavaDoc) children.get(i);
131                 subSelection = (Selection) subSelections.get(i);
132                 retVal.addChild(loadCatalog(child, subSelection, JDBCprop));
133             }
134
135         } catch (SQLException ex) {
136             throw new MetaDataException(ex.getMessage(), ex);
137         }
138         return retVal;
139     }
140
141     /**
142      * Create the Catalog metadata node for a specific catalog. Browse JDBC
143      * schemas calling sub-procedure for schemas if matching the selection.
144      * @param catalogName The catalog browsed.
145      * @param selection A user-defined filter used for schemas.
146      * @return the {@link org.xquark.extractor.metadata.Catalog Catalog} node
147      * built.
148      * @throws MetaDataException
149      */

150     protected Catalog loadCatalog(String JavaDoc catalogName, Selection selection, JDBCProperties JDBCprop) throws MetaDataException {
151         //Trace.enter(this, "loadCatalog(String name, Selection selection)", catalogName);
152

153         List children = new ArrayList();
154         List subSelections = new ArrayList();
155         ResultSet resultSet = null;
156         String JavaDoc name = null;
157
158         /* Catalog node creation */
159         Catalog retVal = null;
160         if (catalogName == null || catalogName.length() == 0)
161             retVal = new Catalog(null);
162         else
163             retVal = new Catalog(catalogName);
164
165         /* JDBC schema browsing */
166         try {
167             String JavaDoc defSchema = getDefaultSchema();
168
169             if (selection.noSubElementDef()) {
170                 Selection schemaSel = new Selection(defSchema, null, Selection.INCLUDES, new HashMap());
171                 selection.addToMap(defSchema, schemaSel);
172             }
173
174             resultSet = _databaseMetaData.getSchemas();
175             Selection subSelection = null;
176             while (resultSet.next()) {
177                 name = resultSet.getString("TABLE_SCHEM");
178                 subSelection = selection.includesSubElement(name);
179                 if (subSelection != null) {
180                     String JavaDoc targetNameSpace = subSelection.getTargetNamespace();
181                     // if (targetNameSpace == null) targetNameSpace = "";
182
if (_nameSpaces.contains(targetNameSpace))
183                         throw new MetaDataException("Same target namespace : [" + targetNameSpace + "] used twice");
184                     _nameSpaces.add(targetNameSpace);
185                     children.add(name);
186                     subSelections.add(subSelection);
187                 }
188             }
189             resultSet.close();
190
191             /* Case where the catalog name is unspecified */
192             subSelection = selection.includesSubElement(null);
193             if (subSelection != null) {
194                 if (defSchema == null) {
195                     children.add(null);
196                     subSelections.add(subSelection);
197                 } else {
198                     children.add(defSchema);
199                     subSelection.setNameForDefault(defSchema);
200                     subSelections.add(subSelection);
201                 }
202             }
203
204             if (children.isEmpty()) {
205                 throw new MetaDataException("Wrong schema configuration specification. Check your configuration file.");
206             }
207
208             /* Browse filtered schema for building */
209             for (int i = 0; i < children.size(); i++) {
210                 String JavaDoc child = (String JavaDoc) children.get(i);
211                 subSelection = (Selection) subSelections.get(i);
212                 retVal.addChild(loadSchema(catalogName, child, subSelection, JDBCprop));
213             }
214         } catch (SQLException ex) {
215             throw new MetaDataException(ex.getMessage(), ex);
216         }
217
218         //Trace.exit(this, "loadCatalog(String name, Selection selection)", catalogName);
219
return retVal;
220
221     }
222
223     /**
224      * Create the Schema metadata node for a specific schema. Browse JDBC
225      * tables encoding names if demanded by user and calling sub-procedures if
226      * table is matching the selection for both tables and keys.
227      * @param catalogName The catalog that contains the schema.
228      * @param schemaName The schema browsed.
229      * @param selection A user-defined filter used for tables.
230      * @return the {@link org.xquark.extractor.metadata.Schema Schema} node
231      * built.
232      * @throws MetaDataException
233      */

234     protected Schema loadSchema(String JavaDoc catalogName, String JavaDoc schemaName, Selection selection, JDBCProperties JDBCprop) throws MetaDataException {
235         //Trace.enter(this, "loadSchema ( String catalogName, String schemaName, Selection selection )", schemaName);
236

237         List children = new ArrayList();
238         List subSelections = new ArrayList();
239         NamedNode catalog = null;
240         ResultSet resultSet = null;
241         String JavaDoc name = null;
242         _nameSpaces.clear();
243         String JavaDoc alias = null;
244
245         /* Schema node creation */
246         Schema retVal = new Schema(schemaName);
247         if (selection != null) {
248             retVal.setTargetNamespace(selection.getTargetNamespace());
249             retVal.setElementFormDefault(selection.getElementFormDefault());
250         }
251
252         /* JDBC tables browsing */
253         try {
254             String JavaDoc[] tableTypes = { "TABLE", "VIEW", "SYNONYM" };
255             String JavaDoc tableType = null;
256             resultSet = _databaseMetaData.getTables(catalogName, schemaName, null, tableTypes);
257
258             if (selection == null || selection.noSubElementDef()) {
259                 /* not indications of which tables to be loaded, so all tables will be loaded */
260                 while (resultSet.next()) {
261                     tableType = resultSet.getString("TABLE_TYPE");
262                     name = resultSet.getString("TABLE_NAME");
263                     alias = _encoder.encode(name);
264                     if (!Selection.verifyName(alias)) {
265                         log.warn(MessageLibrary.getMessage("C_INV_NCNAME", alias));
266                         log.warn(MessageLibrary.getMessage("M_OBJ_N_LOADED", tableType + " " + schemaName + "." + name));
267                         continue; // out of selection
268
}
269
270                     if (tableType.equalsIgnoreCase("TABLE")) {
271                         children.add(new Relation(name, alias, Table.TABLE));
272                         subSelections.add(null);
273                     } else if (tableType.equalsIgnoreCase("VIEW")) {
274                         children.add(new Relation(name, alias, Table.VIEW));
275                         subSelections.add(null);
276                     } else if (tableType.equalsIgnoreCase("SYNONYM")) {
277                         children.add(new Relation(name, alias, Table.SYNONYM));
278                         subSelections.add(null);
279                     } else {
280                         log.warn(MessageLibrary.getMessage("M_OBJ_N_LOADED", tableType + " " + schemaName + "." + name));
281                     }
282                 }
283                 resultSet.close();
284             } else {
285                 /* */
286                 Selection subSelection = null;
287                 while (resultSet.next()) {
288                     name = resultSet.getString("TABLE_NAME");
289                     subSelection = selection.includesSubElement(name);
290                     if (subSelection != null) {
291                         tableType = resultSet.getString("TABLE_TYPE");
292                         alias = subSelection.getAlias();
293                         if (alias == null) {
294                             alias = _encoder.encode(name);
295                             if (!Selection.verifyName(alias)) {
296                                 log.warn(MessageLibrary.getMessage("C_INV_NCNAME", alias));
297                                 log.warn(MessageLibrary.getMessage("M_OBJ_N_LOADED", tableType + " " + schemaName + "." + name));
298                                 continue; // out of selection
299
}
300                         }
301
302                         if (tableType.equalsIgnoreCase("TABLE")) {
303                             children.add(new Relation(name, alias, Table.TABLE));
304                             subSelections.add(subSelection);
305                         } else if (tableType.equalsIgnoreCase("VIEW")) {
306                             children.add(new Relation(name, alias, Table.VIEW));
307                             subSelections.add(subSelection);
308                         } else if (tableType.equalsIgnoreCase("SYNONYM")) {
309                             children.add(new Relation(name, alias, Table.SYNONYM));
310                             subSelections.add(subSelection);
311                         } else {
312                             log.warn(MessageLibrary.getMessage("M_OBJ_N_LOADED", tableType + " " + schemaName + "." + name));
313                         }
314                     }
315                 }
316                 resultSet.close();
317             }
318
319             // TODO : temporary code (written by YS)
320
String JavaDoc path = null; /* the prefix of key in _tableMap Properties */
321             if (null != catalogName)
322                 path = catalogName;
323             if (schemaName != null)
324                 if (path == null)
325                     path = schemaName;
326                 else
327                     path += '.' + schemaName;
328
329             String JavaDoc encodedName = null;
330
331             /* browse "relation" objects for table and key loading */
332             for (int i = 0; i < children.size(); i++) {
333                 Relation child = ((Relation) children.get(i));
334                 Selection subSelection = (Selection) subSelections.get(i);
335
336                 putTable(path, child.alias, child.name); // register table
337

338                 NamedNode childNode = null;
339                 if (Table.TABLE == child.type) {
340                     childNode = loadTable(catalogName, schemaName, child.name, child.alias, subSelection, JDBCprop);
341                     if (childNode != null) {
342                         loadKeys(catalogName, schemaName, (Table) childNode, subSelection);
343                     }
344                 } else {
345                     childNode = loadTable(catalogName, schemaName, child.name, child.alias, subSelection, JDBCprop);
346                 }
347                 if (childNode != null) {
348                     retVal.addChild(childNode);
349                 }
350             }
351         } catch (SQLException ex) {
352             throw new MetaDataException(ex.getMessage(), ex);
353         }
354
355         //Trace.exit(this, "loadSchema ( String catalogName, String schemaName, Selection selection )", schemaName);
356
return retVal;
357     }
358
359     /**
360      * Create the table and columns metadata nodes for a specific table. Browse
361      * JDBC {@link java.sql.ResultSetMetaData ResultSetMetaData} for column
362      * information encoding names if demanded by user.
363      * @param catalogName
364      * @param schemaName
365      * @param origTableName
366      * @param tableName
367      * @param selection
368      * @return
369      * @throws MetaDataException
370      */

371     protected Table loadTable(String JavaDoc catalogName, String JavaDoc schemaName, String JavaDoc origTableName, String JavaDoc tableName, Selection selection, JDBCProperties JDBCprop) throws MetaDataException {
372         //Trace.enter(this, "loadTable(String catalogName, String schemaName, String origTableName, String tableName, Selection selection)", origTableName);
373

374         /* Table node creation */
375         Table retTable = new Table(origTableName, tableName);
376         retTable.setType(Table.TABLE);
377
378         /* Get dummy SQL query string to explore resultset metadata (columns) */
379         List columnsMeta = null;
380         try {
381             columnsMeta = _dbmsInfo.getTableMetadata(catalogName, schemaName, origTableName, _connection, JDBCprop);
382         } catch (SQLException ex) {
383             log.error(ex);
384             log.warn(MessageLibrary.getMessage("M_OBJ_N_LOADED", "Table : " + schemaName + "." + origTableName));
385             //Trace.exit(this, "loadTable(String catalogName, String schemaName, String origTableName, String tableName, Selection selection)", origTableName);
386
return null;
387         }
388
389         /* Browse result set metadata */
390         Attribute attribute = null;
391         ColumnMetaData column = null;
392         Selection subSelection = null;
393         String JavaDoc alias = null;
394         List pkAttributes = new ArrayList();
395         // list of column nodes forming PK
396
boolean currentColumnIsInPK = false;
397
398         //Trace.message(this, "loadTable(...)", "Loading columns...");
399

400         String JavaDoc path = null; /* the prefix of key in _tableMap Properties */
401         if (null != catalogName)
402             path = catalogName + '.' + schemaName + '.' + tableName;
403         else
404             path = schemaName + '.' + tableName;
405
406         for (int i = 0; i < columnsMeta.size(); i++) {
407             column = (ColumnMetaData) columnsMeta.get(i);
408
409             currentColumnIsInPK = false;
410             alias = null;
411
412             if (selection == null || selection.noSubElementDef()) {
413                 alias = _encoder.encode(column.getColumnName());
414                 if (!Selection.verifyName(alias)) {
415                     log.warn(MessageLibrary.getMessage("C_INV_NCNAME", alias));
416                     log.warn(MessageLibrary.getMessage("M_OBJ_N_LOADED", schemaName + "." + origTableName + "." + column.getColumnName()));
417                     continue; // out of selection
418
}
419             } else {
420                 subSelection = selection.includesSubElement(column.getColumnName());
421                 if (subSelection == null) {
422                     continue; // out of selection
423
} else {
424                     alias = subSelection.getAlias();
425                     if (alias == null) {
426                         alias = _encoder.encode(column.getColumnName());
427                         if (!Selection.verifyName(alias)) {
428                             log.warn(MessageLibrary.getMessage("C_INV_NCNAME", alias));
429                             log.warn(MessageLibrary.getMessage("M_OBJ_N_LOADED", schemaName + "." + origTableName + "." + column.getColumnName()));
430                             continue;
431                         }
432                     }
433                     if (subSelection.getPKColumn()) {
434                         currentColumnIsInPK = true;
435                     }
436                 }
437             }
438             putAttribute(path, alias, column.getColumnName()); // register column
439

440             /* Attribute (column) node creation */
441             ExtractorMappingInfo mappingInfo = null;
442             try {
443                 mappingInfo = new ExtractorMappingInfo(column, _dbmsInfo.getTypeMap());
444             } catch (MetaDataException e) {
445                 MessageLibrary.getMessage("M_SUP_DATATYPE", new String JavaDoc[] { column.getType().getNativeType(), column.getTableName(), column.getColumnName()});
446                 continue;
447             }
448
449             attribute = new Attribute(column.getColumnName(), alias);
450             attribute.setMappingInfo(mappingInfo);
451             attribute.setNullable(column.isNullable());
452
453             /* Add column to metadata tree */
454             retTable.addChild(attribute);
455
456             /*
457              * Add column metadata node to Table node PK list as defined by
458              * user in configuration file.
459              */

460             // QUESTION : the user PK is the first so used in priority
461
if (currentColumnIsInPK) {
462                 pkAttributes.add(attribute);
463             }
464         }
465
466         /* Add PK column metadata node list to Table node */
467         if (!pkAttributes.isEmpty()) {
468             retTable.addKey(pkAttributes);
469         }
470
471         //Trace.exit(this, "loadTable(String catalogName, String schemaName, String origTableName, String tableName, Selection selection)", origTableName);
472
return retTable;
473     }
474
475     /**
476      * Add the real Primary Key to Table metadata node basing on JDBC metadata.
477      * @param catalogName
478      * @param schemaName
479      * @param table
480      * @param selection
481      * @throws MetaDataException
482      */

483     protected void loadKeys(String JavaDoc catalogName, String JavaDoc schemaName, Table table, Selection selection) throws MetaDataException {
484         //Trace.enter(this, "loadKeys(String catalogName, String schemaName, Table table, Selection selection)", table.getName());
485

486         try {
487             // /* load Primary Keys for this table */
488
// Trace.message( this,"loadTable(...)", "creating pseudoAttribute column...");
489
String JavaDoc column_name = null;
490             String JavaDoc alias = null;
491             Selection subSelection = null;
492             Attribute attribute = null;
493             List key = new ArrayList();
494
495             ResultSet resultSet = _databaseMetaData.getPrimaryKeys(catalogName, schemaName, table.getName());
496
497             String JavaDoc path = null; /* the prefix of key in _tableMap Properties */
498             if (null != catalogName) {
499                 path = catalogName + '.' + schemaName + '.' + table.getName();
500             } else {
501                 path = schemaName + '.' + table.getName();
502             }
503
504             /* Loop on columns of the PK for the specified table */
505             while (resultSet.next()) {
506                 column_name = resultSet.getString("COLUMN_NAME");
507
508                 /* generate and verify alias*/
509                 alias = null;
510                 if (selection == null || selection.noSubElementDef()) {
511                     alias = _encoder.encode(column_name);
512                 } else {
513                     subSelection = selection.includesSubElement(column_name);
514                     if (subSelection == null) {
515                         alias = _encoder.encode(column_name);
516                     } else {
517                         alias = subSelection.getAlias();
518                         if (null == alias) {
519                             alias = _encoder.encode(column_name);
520                         }
521                     }
522                 }
523
524                 //Trace.message(this, "loadKeys(String catalogName, String schemaName, Table table, Selection selection)", column_name + "--" + alias);
525

526                 attribute = (Attribute) table.findChild(column_name);
527                 if (attribute == null) {
528                     putAttribute(path, alias, column_name);
529                     attribute = new Attribute(column_name, alias);
530                 }
531                 key.add(attribute);
532             }
533             resultSet.close();
534
535             /* Add PK to Table metadata node */
536             if (!key.isEmpty()) {
537                 table.addKey(key);
538             }
539         } catch (SQLException ex) {
540             throw new MetaDataException(ex.getMessage());
541         }
542         //Trace.exit(this, "loadKeys(String catalogName, String schemaName, Table table, Selection selection)", table.getName());
543
}
544
545     /**
546      * Add the table to map between XML names and native DBMS names.
547      * @param path
548      * @param encodedTableName
549      * @param originalName
550      * @throws MetaDataException
551      */

552     protected void putTable(String JavaDoc path, String JavaDoc encodedTableName, String JavaDoc originalName) throws MetaDataException {
553         String JavaDoc key = null;
554         key = path + '.' + encodedTableName;
555
556         Object JavaDoc value = null;
557         value = _tableMap.getProperty(key);
558         if (null == value) {
559             _tableMap.setProperty(key, originalName);
560         } else {
561             throw new MetaDataException(MessageLibrary.getMessage("M_NAME_CONF", key, originalName));
562         }
563     }
564
565     /**
566      * Add the column to map between XML names and native DBMS names.
567      * @param path
568      * @param encodedAttributeName
569      * @param originalName
570      * @throws MetaDataException
571      */

572     protected void putAttribute(String JavaDoc path, String JavaDoc encodedAttributeName, String JavaDoc originalName) throws MetaDataException {
573         String JavaDoc key = null;
574         key = path + '.' + encodedAttributeName;
575
576         Object JavaDoc value = null;
577         value = _tableMap.getProperty(key);
578         if (null == value) {
579             _tableMap.setProperty(key, originalName);
580         } else {
581             throw new MetaDataException(MessageLibrary.getMessage("M_NAME_CONF", key, originalName));
582         }
583     }
584     
585     /**
586      * Returns the current catalog for a connection
587      * @return the current catalog name, or null if there is none
588      * @throws SQLException
589      */

590     protected String JavaDoc getDefaultCatalog() throws SQLException {
591         return _connection.getCatalog();
592     }
593     
594     /**
595      * Returns the current schema for a connection
596      * @return the current schema name, or null if there is none
597      * @throws SQLException
598      */

599     protected String JavaDoc getDefaultSchema() throws SQLException {
600         return _databaseMetaData.getUserName();
601     }
602     
603     /**
604      * Struct-like data class.
605      */

606     class Relation {
607
608         public String JavaDoc name;
609         public String JavaDoc alias;
610         public int type;
611
612         public Relation(String JavaDoc name, String JavaDoc alias, int type) {
613             this.name = name;
614             this.alias = alias;
615             this.type = type;
616         }
617
618         public Relation(String JavaDoc name, int type) {
619             this.name = name;
620             this.type = type;
621             this.alias = name;
622         }
623     }
624 }
625
Popular Tags