KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ws > jaxme > sqls > impl > SQLFactoryImpl


1 /*
2  * Copyright 2003, 2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15
16  */

17 package org.apache.ws.jaxme.sqls.impl;
18
19 import java.io.Serializable JavaDoc;
20 import java.sql.Connection JavaDoc;
21 import java.sql.DatabaseMetaData JavaDoc;
22 import java.sql.ResultSet JavaDoc;
23 import java.sql.SQLException JavaDoc;
24 import java.sql.Types JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.List JavaDoc;
28
29 import org.apache.ws.jaxme.logging.Logger;
30 import org.apache.ws.jaxme.logging.LoggerAccess;
31 import org.apache.ws.jaxme.sqls.BinaryColumn;
32 import org.apache.ws.jaxme.sqls.Column;
33 import org.apache.ws.jaxme.sqls.DeleteStatement;
34 import org.apache.ws.jaxme.sqls.ForeignKey;
35 import org.apache.ws.jaxme.sqls.Index;
36 import org.apache.ws.jaxme.sqls.InsertStatement;
37 import org.apache.ws.jaxme.sqls.ObjectFactory;
38 import org.apache.ws.jaxme.sqls.SQLFactory;
39 import org.apache.ws.jaxme.sqls.SQLGenerator;
40 import org.apache.ws.jaxme.sqls.Schema;
41 import org.apache.ws.jaxme.sqls.SelectStatement;
42 import org.apache.ws.jaxme.sqls.StringColumn;
43 import org.apache.ws.jaxme.sqls.Table;
44 import org.apache.ws.jaxme.sqls.UpdateStatement;
45
46
47 /** <p>Default implementation of an SQLFactory.</p>
48  *
49  * @author <a HREF="mailto:joe@ispsoft.de">Jochen Wiedmann</a>
50  */

51 public class SQLFactoryImpl implements SQLFactory {
52   private static final Logger logger = LoggerAccess.getLogger(SQLFactoryImpl.class);
53
54   /** Base class for deriving identifiers.
55    */

56   public static class IdentImpl implements SQLFactory.Ident, Serializable JavaDoc {
57     private String JavaDoc name;
58
59     protected IdentImpl(String JavaDoc pName) {
60       if (pName == null) {
61         throw new NullPointerException JavaDoc("An ident's string representation must not be null.");
62       }
63       name = pName;
64     }
65
66     public String JavaDoc getName() {
67       return name;
68     }
69
70     public String JavaDoc toString() {
71       return name;
72     }
73
74     public boolean equals(Object JavaDoc o) {
75       if (o == null || !(o instanceof SQLFactory.Ident)) {
76         return false;
77       }
78       return name.equalsIgnoreCase(((SQLFactory.Ident) o).getName());
79     }
80     public int hashCode() {
81       return name.hashCode();
82     }
83   }
84
85   private List JavaDoc schemas = new ArrayList JavaDoc();
86   private Integer JavaDoc maxTableNameLength, maxSchemaNameLength, maxColumnNameLength;
87   private boolean tableNameCaseSensitive, schemaNameCaseSensitive, columnNameCaseSensitive;
88   private Schema defaultSchema;
89   private ObjectFactory objectFactory = newObjectFactory();
90
91   /** <p>Creates a new instance of SQLFactoryImpl.</p>
92    */

93   public SQLFactoryImpl() {
94   }
95
96   protected ObjectFactory newObjectFactory() {
97     return new ObjectFactoryImpl();
98   }
99
100   public ObjectFactory getObjectFactory() {
101     return objectFactory;
102   }
103
104   protected void setObjectFactory(ObjectFactory pFactory) {
105     objectFactory = pFactory;
106   }
107
108   /** <p>Sets the maximum length of a table name.</p>
109    * @param pMaxLength The maximum length or null to disable checks for
110    * valid table name length.
111    */

112   public void setMaxTableNameLength(Integer JavaDoc pMaxLength) {
113     maxTableNameLength = pMaxLength;
114   }
115
116   public Integer JavaDoc getMaxTableNameLength() {
117     return maxTableNameLength;
118   }
119
120   /** <p>Sets whether table names are case sensitive or not. Defaults
121    * to false.</p>
122    * @see SQLFactory#isTableNameCaseSensitive()
123    */

124   public void setTableNameCaseSensitive(boolean pTableNameCaseSensitive) {
125     tableNameCaseSensitive = pTableNameCaseSensitive;
126   }
127
128   public boolean isTableNameCaseSensitive() {
129     return tableNameCaseSensitive;
130   }
131
132   /** <p>Sets the maximum length of a column name.</p>
133    * @param pMaxLength The maximum length or null to disable checks for
134    * valid column name length.
135    */

136   public void setMaxColumnNameLength(Integer JavaDoc pMaxLength) {
137     maxColumnNameLength = pMaxLength;
138   }
139
140   public Integer JavaDoc getMaxColumnNameLength() {
141     return maxColumnNameLength;
142   }
143
144   /** <p>Sets whether column names are case sensitive or not. Defaults
145    * to false.</p>
146    * @see SQLFactory#isColumnNameCaseSensitive()
147    */

148   public void setColumnNameCaseSensitive(boolean pColumnNameCaseSensitive) {
149     columnNameCaseSensitive = pColumnNameCaseSensitive;
150   }
151  
152   public boolean isColumnNameCaseSensitive() {
153     return columnNameCaseSensitive;
154   }
155
156   /** <p>Sets whether schema names are case sensitive or not. Defaults
157    * to false.</p>
158    * @see SQLFactory#isSchemaNameCaseSensitive()
159    */

160   public void setSchemaNameCaseSensitive(boolean pSchemaNameCaseSensitive) {
161     schemaNameCaseSensitive = pSchemaNameCaseSensitive;
162   }
163
164   public boolean isSchemaNameCaseSensitive() {
165     return schemaNameCaseSensitive;
166   }
167
168   /** <p>Sets the maximum length of a schema name.</p>
169    * @param pMaxLength The maximum length or null to disable checks for
170    * valid schema name length.
171    */

172   public void setMaxSchemaNameLength(Integer JavaDoc pMaxLength) {
173     maxSchemaNameLength = pMaxLength;
174   }
175
176   public Integer JavaDoc getMaxSchemaNameLength() {
177     return maxSchemaNameLength;
178   }
179
180   /** Converths the given string into an SQL identifier.
181    */

182   public SQLFactory.Ident newIdent(String JavaDoc pName) {
183     if (pName == null) {
184       throw new NullPointerException JavaDoc("An SQL identifier must not be null.");
185     }
186     if (pName.length() == 0) {
187       throw new IllegalArgumentException JavaDoc("An SQL identifier must not be empty.");
188     }
189     char c = pName.charAt(0);
190     if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z')) {
191       throw new IllegalArgumentException JavaDoc("An SQL identifiers first character must be A..Z");
192     }
193     for (int i = 1; i < pName.length(); i++) {
194       c = pName.charAt(i);
195       if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c > '9')) {
196         throw new IllegalArgumentException JavaDoc("An SQL identifier must not contain the character " +
197                       c + ", only A..Z, a..z, or 0..9 are allowed.");
198       }
199     }
200     return new IdentImpl(pName);
201   }
202
203   public Schema newSchema(String JavaDoc pName) {
204     if (pName == null) {
205       throw new NullPointerException JavaDoc("A schema name must not be null.");
206     }
207     return newSchema(new SchemaImpl.NameImpl(pName));
208   }
209
210   public Schema newSchema(Schema.Name pName) {
211     if (pName == null) {
212       throw new NullPointerException JavaDoc("A schema name must not be null.");
213     }
214     Integer JavaDoc maxLength = getMaxSchemaNameLength();
215     if (maxLength != null &&
216     pName.getName().length() > maxLength.intValue()) {
217       throw new IllegalArgumentException JavaDoc("The length of the schema name " + pName +
218                      " exceeds the valid maximum of " + maxLength);
219     }
220     Schema schema = getSchema(pName);
221     if (schema != null) {
222       throw new IllegalStateException JavaDoc("A schema named " + schema.getName() + " already exists.");
223     }
224     schema = newSchemaImpl(pName);
225     schemas.add(schema);
226     return schema;
227   }
228
229   public Schema getDefaultSchema() {
230     if (defaultSchema == null) {
231       defaultSchema = newSchemaImpl(null);
232       schemas.add(defaultSchema);
233     }
234     return defaultSchema;
235    }
236
237   public Schema getSchema(String JavaDoc pName) {
238     return getSchema(new SchemaImpl.NameImpl(pName));
239   }
240
241   public Schema getSchema(Schema.Name pName) {
242     if (pName == null) {
243       throw new NullPointerException JavaDoc("A schema name must not be null.");
244     }
245     for (Iterator JavaDoc iter = getSchemas(); iter.hasNext();) {
246       Schema schema = (Schema) iter.next();
247       if (isSchemaNameCaseSensitive()) {
248         if (pName.getName().equalsIgnoreCase(schema.getName().getName())) {
249           return schema;
250         }
251       } else {
252         if (pName.equals(schema.getName())) {
253           return schema;
254         }
255       }
256     }
257     return null;
258   }
259
260   public Iterator JavaDoc getSchemas() {
261     return schemas.iterator();
262   }
263
264   public SelectStatement newSelectStatement() {
265     return new SelectStatementImpl(this);
266   }
267
268   public InsertStatement newInsertStatement() {
269     return new InsertStatementImpl(this);
270   }
271
272   public UpdateStatement newUpdateStatement() {
273     return new UpdateStatementImpl(this);
274   }
275
276   public DeleteStatement newDeleteStatement() {
277     return new DeleteStatementImpl(this);
278   }
279
280   protected Schema newSchemaImpl(Schema.Name pName) {
281     return new SchemaImpl(this, pName);
282   }
283
284   protected Table newTableImpl(Schema pSchema, Table.Name pName) {
285     return new TableImpl(pSchema, pName);
286   }
287
288   protected Column newColumnImpl(Table pTable, Column.Name pName, Column.Type pType) {
289     return new ColumnImpl(pTable, pName, pType);
290   }
291
292   public SQLGenerator newSQLGenerator() {
293     return new SQLGeneratorImpl();
294   }
295
296   public Schema getSchema(Connection JavaDoc pConn, String JavaDoc pName) throws SQLException JavaDoc {
297      return getSchema(pConn, pName == null ? null : new SchemaImpl.NameImpl(pName));
298   }
299
300   private class JDBCTable {
301     private final String JavaDoc catalogName, schemaName, tableName, tableType;
302     private final String JavaDoc toStringValue;
303     private Table table;
304     /** Creates a new instance loading data from the given catalog, schema
305      * and table.
306      */

307     public JDBCTable(String JavaDoc pCatalogName, String JavaDoc pSchemaName, String JavaDoc pTableName,
308                      String JavaDoc pTableType) {
309       catalogName = pCatalogName;
310       schemaName = pSchemaName;
311       tableName = pTableName;
312       tableType = pTableType;
313       String JavaDoc s = tableName;
314       if ((schemaName != null && schemaName.length() > 0) ||
315           (catalogName != null && catalogName.length() > 0)) {
316         s = catalogName + "." + schemaName + "." + tableName;
317         
318       }
319       toStringValue = s;
320     }
321     /** Returns the catalog name.
322      */

323     public String JavaDoc getCatalogName() { return catalogName; }
324     /** Returns the schema name.
325      */

326     public String JavaDoc getSchemaName() { return schemaName; }
327     /** Returns the table name.
328      */

329     public String JavaDoc getTableName() { return tableName; }
330     /** Returns the table type.
331      */

332     public String JavaDoc getTableType() { return tableType; }
333     public String JavaDoc toString() { return toStringValue; }
334     /** Sets the associated instance of {@link Table}.
335      */

336     public void setTable(Table pTable) { table = pTable; }
337     /** Returns the associated instance of {@link Table}.
338      */

339     public Table getTable() { return table; }
340
341     public int hashCode() {
342       int result = 0;
343       if (catalogName != null) result += catalogName.hashCode();
344       if (schemaName != null) result += schemaName.hashCode();
345       if (tableName != null) result += tableName.hashCode();
346       return result;
347     }
348     public boolean equals(Object JavaDoc o) {
349       if (o == null || !(o instanceof JDBCTable)) return false;
350       JDBCTable t = (JDBCTable) o;
351       if (catalogName == null) {
352         if (t.catalogName != null) return false;
353       } else {
354         if (!catalogName.equals(t.catalogName)) return false;
355       }
356       if (schemaName == null) {
357         if (t.schemaName != null) return false;
358       } else {
359         if (!schemaName.equals(t.schemaName)) return false;
360       }
361       if (tableName == null) {
362         return t.tableName == null;
363       } else {
364         return tableName.equals(t.tableName);
365       }
366     }
367   }
368
369   protected Schema makeSchema(Schema.Name pName) {
370     Schema schema;
371     if (pName == null) {
372        schema = getDefaultSchema();
373     } else {
374        schema = getSchema(pName);
375        if (schema == null) {
376           schema = newSchema(pName);
377        }
378     }
379     return schema;
380   }
381
382   protected JDBCTable[] readTables(DatabaseMetaData JavaDoc pData, Schema.Name pSchema, Table.Name pTable) throws SQLException JavaDoc {
383     final String JavaDoc mName = "readTables";
384     List JavaDoc tables = new ArrayList JavaDoc();
385     {
386       ResultSet JavaDoc rs = pData.getTables(null, pSchema == null ? null : pSchema.getName(),
387                                      pTable == null ? null : pTable.getName(), null);
388       boolean isRsClosed = false;
389       try {
390         while (rs.next()) {
391           JDBCTable table = new JDBCTable(rs.getString(1), rs.getString(2),
392                                           rs.getString(3), rs.getString(4));
393           if (!"TABLE".equals(table.getTableType())) {
394             continue;
395           }
396    
397           if (pSchema != null) {
398             if (!table.getSchemaName().equals(pSchema.toString())) {
399               continue;
400             }
401           }
402           logger.finest(mName, "Found table " + table);
403           tables.add(table);
404         }
405         isRsClosed = true;
406         rs.close();
407       } finally {
408         if (!isRsClosed) { try { rs.close(); } catch (Throwable JavaDoc ignore) {} }
409       }
410     }
411     return (JDBCTable[]) tables.toArray(new JDBCTable[tables.size()]);
412   }
413
414   protected Column readColumn(Table pTable, String JavaDoc pColumnName, int pDataType, String JavaDoc pTypeName,
415                                long pColumnSize, int pDecimalDigits, int pNullable) {
416                                Column.Type type;
417     final String JavaDoc mName = "readColumn";
418     switch (pDataType) {
419       case Types.BIGINT: type = Column.Type.BIGINT; break;
420       case Types.BINARY: type = Column.Type.BINARY; break;
421       case Types.BIT: type = Column.Type.BIT; break;
422       case Types.BLOB: type = Column.Type.BLOB; break;
423       case 16: /* Types.BOOLEAN, introduced in Java 1.4 */
424                                 type = Column.Type.BIT; break;
425       case Types.CHAR: type = Column.Type.CHAR; break;
426       case Types.CLOB: type = Column.Type.CLOB; break;
427       case Types.DATE: type = Column.Type.DATE; break;
428       case Types.DOUBLE: type = Column.Type.DOUBLE; break;
429       case Types.FLOAT: type = Column.Type.FLOAT; break;
430       case Types.REAL: type = Column.Type.DOUBLE; break;
431       case Types.INTEGER: type = Column.Type.INTEGER; break;
432       case Types.LONGVARBINARY: type = Column.Type.VARBINARY; break;
433       case Types.LONGVARCHAR: type = Column.Type.VARCHAR; break;
434       case Types.OTHER: type = Column.Type.OTHER; break;
435       case Types.SMALLINT: type = Column.Type.SMALLINT; break;
436       case Types.TIMESTAMP: type = Column.Type.TIMESTAMP; break;
437       case Types.TIME: type = Column.Type.TIME; break;
438       case Types.TINYINT: type = Column.Type.TINYINT; break;
439       case Types.VARBINARY: type = Column.Type.VARBINARY; break;
440       case Types.VARCHAR: type = Column.Type.VARCHAR; break;
441       default: throw new IllegalArgumentException JavaDoc("Column " + pColumnName +
442                                                     " in table " + pTable.getQName() +
443                                                     " has unknown JDBC data type " +
444                                                     pDataType);
445     }
446     Column column = pTable.newColumn(pColumnName, type);
447     logger.finest(mName, "Found column " + pColumnName);
448     if (column instanceof StringColumn) {
449       ((StringColumn) column).setLength(pColumnSize);
450     } else if (column instanceof BinaryColumn) {
451       ((BinaryColumn) column).setLength(pColumnSize);
452     }
453     if (pNullable == DatabaseMetaData.columnNullable) {
454       column.setNullable(true);
455     }
456     return column;
457   }
458
459   protected Table readTable(DatabaseMetaData JavaDoc pData, Schema pSchema, JDBCTable pTable)
460       throws SQLException JavaDoc {
461     final String JavaDoc mName = "readTable";
462     ResultSet JavaDoc rs = pData.getColumns(pTable.getCatalogName(), pTable.getSchemaName(),
463                                     pTable.getTableName(), null);
464     boolean isRsClosed = false;
465     try {
466       Table sqlTable = pSchema.newTable(pTable.getTableName());
467       logger.finest(mName, "Looking for columns of " + pTable + "=" + sqlTable.getQName());
468       while (rs.next()) {
469         String JavaDoc columnName = rs.getString(4);
470         int dataType = rs.getInt(5);
471         String JavaDoc typeName = rs.getString(6);
472         long columnSize = rs.getLong(7);
473         int decimalDigits = rs.getInt(9);
474         int isNullable = rs.getInt(11);
475         readColumn(sqlTable, columnName, dataType, typeName, columnSize, decimalDigits, isNullable);
476       }
477       pTable.setTable(sqlTable);
478
479       isRsClosed = true;
480       rs.close();
481       return sqlTable;
482     } finally {
483       if (!isRsClosed) { try { rs.close(); } catch (Throwable JavaDoc ignore) {} }
484     }
485   }
486
487   protected Index readPrimaryKey(DatabaseMetaData JavaDoc pData, JDBCTable pTable) throws SQLException JavaDoc {
488     final String JavaDoc mName = "readPrimaryKey";
489     logger.finest(mName, "Looking for primary keys of " + pTable + "=" + pTable.getTable().getQName());
490     ResultSet JavaDoc rs = pData.getPrimaryKeys(pTable.getCatalogName(),
491                                         pTable.getSchemaName(),
492                                         pTable.getTableName());
493     Index primaryKey = null;
494     boolean isRsClosed = false;
495     try {
496       while (rs.next()) {
497         if (primaryKey == null) {
498           primaryKey = pTable.getTable().newPrimaryKey();
499         }
500
501         String JavaDoc columnName = rs.getString(4);
502         logger.finest(mName, "Found column " + columnName);
503         primaryKey.addColumn(columnName);
504       }
505
506       isRsClosed = true;
507       rs.close();
508     } finally {
509       if (!isRsClosed) { try { rs.close(); } catch (Throwable JavaDoc ignore) {} }
510     }
511     return primaryKey;
512   }
513
514   protected ForeignKey[] readForeignKeys(DatabaseMetaData JavaDoc pData, JDBCTable pTable, JDBCTable[] pTables)
515       throws SQLException JavaDoc {
516     final String JavaDoc mName = "readForeignKeys";
517     logger.finest(mName, "Looking for foreign keys of " + pTable + "=" + pTable.getTable().getQName());
518     List JavaDoc result = new ArrayList JavaDoc();
519     ResultSet JavaDoc rs = pData.getImportedKeys(pTable.getCatalogName(),
520                                          pTable.getSchemaName(),
521                                          pTable.getTableName());
522     ForeignKey foreignKey = null;
523     boolean isRsClosed = false;
524     try {
525       while (rs.next()) {
526         JDBCTable referencedTable = new JDBCTable(rs.getString(1), rs.getString(2),
527                                                   rs.getString(3), "TABLE");
528         String JavaDoc referencedColumnName = rs.getString(4);
529         String JavaDoc localColumnName = rs.getString(8);
530         logger.finest(mName, "Found column " + localColumnName + " referencing " +
531                       referencedColumnName + " in " + referencedTable);
532         for (int i = 0; i < pTables.length; i++) {
533           JDBCTable refIterTable = pTables[i];
534           if (refIterTable.equals(referencedTable)) {
535             referencedTable.setTable(refIterTable.getTable());
536             break;
537           }
538         }
539         if (referencedTable.getTable() == null) {
540           logger.finest(mName, "Unknown table, ignoring");
541           continue;
542         }
543
544         short seq = rs.getShort(9);
545         if (seq == 1) {
546           foreignKey = pTable.getTable().newForeignKey(referencedTable.getTable());
547           result.add(foreignKey);
548         }
549         foreignKey.addColumnLink(localColumnName, referencedColumnName);
550       }
551
552       isRsClosed = true;
553       rs.close();
554     } finally {
555       if (!isRsClosed) { try { rs.close(); } catch (Throwable JavaDoc ignore) {} }
556     }
557     return (ForeignKey[]) result.toArray(new ForeignKey[result.size()]);
558   }
559
560   public Schema getSchema(Connection JavaDoc pConn, Schema.Name pName) throws SQLException JavaDoc {
561     final String JavaDoc mName = "getSchema(Connection,Schema.Name)";
562     logger.finest(mName, "->", new Object JavaDoc[]{pConn, pName});
563
564     Schema schema = makeSchema(pName);
565     DatabaseMetaData JavaDoc metaData = pConn.getMetaData();
566     JDBCTable[] tables = readTables(metaData, pName, null);
567     for (int i = 0; i < tables.length; i++) {
568       readTable(metaData, schema, tables[i]);
569       readPrimaryKey(metaData, tables[i]);
570     }
571
572     for (int i = 0; i < tables.length; i++) {
573       readForeignKeys(metaData, tables[i], tables);
574     }
575
576     logger.finest(mName, "<-", schema);
577     return schema;
578   }
579
580   public Table getTable(Connection JavaDoc pConnection, Schema.Name pSchema, Table.Name pTable) throws SQLException JavaDoc {
581     final String JavaDoc mName = "getSchema(Connection,Schema.Name)";
582     logger.finest(mName, "->", new Object JavaDoc[]{pConnection, pSchema, pTable});
583
584     Schema schema = makeSchema(pSchema);
585     DatabaseMetaData JavaDoc metaData = pConnection.getMetaData();
586     JDBCTable[] tables = readTables(metaData, pSchema, pTable);
587     JDBCTable jdbcTable;
588     if (tables.length == 0) {
589       String JavaDoc tableName = pTable.toString();
590       String JavaDoc schemaName = pSchema == null ? null : pSchema.toString();
591       String JavaDoc ucTableName = tableName.toUpperCase();
592       String JavaDoc ucSchemaName = schemaName == null ? null : schemaName.toUpperCase();
593       if (tableName.equals(ucTableName) &&
594           (schemaName == null || schemaName.equals(ucSchemaName))) {
595         throw new IllegalStateException JavaDoc("No table named " + pTable + " found in schema " + pSchema);
596       }
597       return getTable(pConnection, ucSchemaName, ucTableName);
598     } else if (tables.length == 1) {
599       jdbcTable = tables[0];
600     } else {
601       throw new IllegalStateException JavaDoc("Multiple tables named " + pTable + " found in schema " + pSchema);
602     }
603     Table result = readTable(metaData, schema, jdbcTable);
604     readPrimaryKey(metaData, jdbcTable);
605     return result;
606   }
607
608   public Table getTable(Connection JavaDoc pConnection, String JavaDoc pSchema, String JavaDoc pTable) throws SQLException JavaDoc {
609     return getTable(pConnection, pSchema == null ? null : new SchemaImpl.NameImpl(pSchema), new TableImpl.NameImpl(pTable));
610   }
611 }
612
Popular Tags