Source Code Cross Referenced for SchemaGenerator.java in  » Database-ORM » openjpa » org » apache » openjpa » jdbc » schema » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database ORM » openjpa » org.apache.openjpa.jdbc.schema 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Licensed to the Apache Software Foundation (ASF) under one
003:         * or more contributor license agreements.  See the NOTICE file
004:         * distributed with this work for additional information
005:         * regarding copyright ownership.  The ASF licenses this file
006:         * to you under the Apache License, Version 2.0 (the
007:         * "License"); you may not use this file except in compliance
008:         * with the License.  You may obtain a copy of the License at
009:         *
010:         * http://www.apache.org/licenses/LICENSE-2.0
011:         *
012:         * Unless required by applicable law or agreed to in writing,
013:         * software distributed under the License is distributed on an
014:         * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015:         * KIND, either express or implied.  See the License for the
016:         * specific language governing permissions and limitations
017:         * under the License.    
018:         */
019:        package org.apache.openjpa.jdbc.schema;
020:
021:        import java.sql.Connection;
022:        import java.sql.DatabaseMetaData;
023:        import java.sql.SQLException;
024:        import java.util.Arrays;
025:        import java.util.Collection;
026:        import java.util.Collections;
027:        import java.util.EventObject;
028:        import java.util.HashMap;
029:        import java.util.HashSet;
030:        import java.util.Iterator;
031:        import java.util.LinkedList;
032:        import java.util.List;
033:        import java.util.Map;
034:        import java.util.Set;
035:        import javax.sql.DataSource;
036:
037:        import org.apache.commons.lang.StringUtils;
038:        import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
039:        import org.apache.openjpa.jdbc.sql.DBDictionary;
040:        import org.apache.openjpa.lib.log.Log;
041:        import org.apache.openjpa.lib.util.Localizer;
042:
043:        /**
044:         * The SchemaGenerator creates {@link Schema}s matching the current
045:         * database. All schemas are added to the current {@link SchemaGroup}.
046:         *  Note that tables whose name starts with "OPENJPA_" will be not be added
047:         * to the database schema. This enables the creation of special tables
048:         * that will never be dropped by the {@link SchemaTool}.
049:         *
050:         * @author Abe White
051:         */
052:        public class SchemaGenerator {
053:
054:            private static final Localizer _loc = Localizer
055:                    .forPackage(SchemaGenerator.class);
056:
057:            private final DataSource _ds;
058:            private final DBDictionary _dict;
059:            private final Log _log;
060:            private final Object[][] _allowed;
061:            private boolean _indexes = true;
062:            private boolean _fks = true;
063:            private boolean _pks = true;
064:            private boolean _seqs = true;
065:            private boolean _openjpaTables = true;
066:            private SchemaGroup _group = null;
067:
068:            private List _listeners = null;
069:            private int _schemaObjects = 0;
070:
071:            /**
072:             * Constructor.
073:             *
074:             * @param conf configuration for connecting to the data store
075:             */
076:            public SchemaGenerator(JDBCConfiguration conf) {
077:                // note: we cannot assert developer capabilities in this tool like
078:                // we normally do because this class is also used at runtime
079:
080:                _ds = conf.getDataSource2(null);
081:                _log = conf.getLog(JDBCConfiguration.LOG_SCHEMA);
082:
083:                // cache this now so that if the conn pool only has 1 connection we
084:                // don't conflict later with the open databasemetadata connection
085:                _dict = conf.getDBDictionaryInstance();
086:
087:                // create a table of allowed schema and tables to reflect on
088:                _allowed = parseSchemasList(conf.getSchemasList());
089:            }
090:
091:            /**
092:             * Given a list of schema names and table names (where table names
093:             * are always of the form schema.table, or just .table if the schema is
094:             * unknown), creates a table mapping schema name to table list. Returns
095:             * null if no args are given. If no tables are given for a particular
096:             * schema, maps the schema name to null.
097:             */
098:            private static Object[][] parseSchemasList(String[] args) {
099:                if (args == null || args.length == 0)
100:                    return null;
101:
102:                Map schemas = new HashMap();
103:                String schema, table;
104:                int dotIdx;
105:                Collection tables;
106:                for (int i = 0; i < args.length; i++) {
107:                    dotIdx = args[i].indexOf('.');
108:                    if (dotIdx == -1) {
109:                        schema = args[i];
110:                        table = null;
111:                    } else if (dotIdx == 0) {
112:                        schema = null;
113:                        table = args[i].substring(1);
114:                    } else {
115:                        schema = args[i].substring(0, dotIdx);
116:                        table = args[i].substring(dotIdx + 1);
117:                    }
118:
119:                    // if just a schema name, map schema to null
120:                    if (table == null && !schemas.containsKey(schema))
121:                        schemas.put(schema, null);
122:                    else if (table != null) {
123:                        tables = (Collection) schemas.get(schema);
124:                        if (tables == null) {
125:                            tables = new LinkedList();
126:                            schemas.put(schema, tables);
127:                        }
128:                        tables.add(table);
129:                    }
130:                }
131:
132:                Object[][] parsed = new Object[schemas.size()][2];
133:                Map.Entry entry;
134:                int idx = 0;
135:                for (Iterator itr = schemas.entrySet().iterator(); itr
136:                        .hasNext();) {
137:                    entry = (Map.Entry) itr.next();
138:                    tables = (Collection) entry.getValue();
139:
140:                    parsed[idx][0] = entry.getKey();
141:                    if (tables != null)
142:                        parsed[idx][1] = tables.toArray(new String[tables
143:                                .size()]);
144:                    idx++;
145:                }
146:                return parsed;
147:            }
148:
149:            /**
150:             * Return whether indexes should be generated. Defaults to true.
151:             */
152:            public boolean getIndexes() {
153:                return _indexes;
154:            }
155:
156:            /**
157:             * Set whether indexes should be generated. Defaults to true.
158:             */
159:            public void setIndexes(boolean indexes) {
160:                _indexes = indexes;
161:            }
162:
163:            /**
164:             * Return whether foreign keys should be generated. Defaults to true.
165:             */
166:            public boolean getForeignKeys() {
167:                return _fks;
168:            }
169:
170:            /**
171:             * Set whether foreign keys should be generated. Defaults to true.
172:             */
173:            public void setForeignKeys(boolean fks) {
174:                _fks = fks;
175:            }
176:
177:            /**
178:             * Return whether primary keys should be generated. Defaults to true.
179:             */
180:            public boolean getPrimaryKeys() {
181:                return _pks;
182:            }
183:
184:            /**
185:             * Set whether primary keys should be generated. Defaults to true.
186:             */
187:            public void setPrimaryKeys(boolean pks) {
188:                _pks = pks;
189:            }
190:
191:            /**
192:             * Return whether sequences should be generated. Defaults to true.
193:             */
194:            public boolean getSequences() {
195:                return _seqs;
196:            }
197:
198:            /**
199:             * Set whether sequences should be generated. Defaults to true.
200:             */
201:            public void setSequences(boolean seqs) {
202:                _seqs = seqs;
203:            }
204:
205:            /**
206:             * Whether to generate info on special tables used by OpenJPA components
207:             * for bookkeeping. Defaults to true.
208:             */
209:            public boolean getOpenJPATables() {
210:                return _openjpaTables;
211:            }
212:
213:            /**
214:             * Whether to generate info on special tables used by OpenJPA components
215:             * for bookkeeping. Defaults to true.
216:             */
217:            public void setOpenJPATables(boolean openjpaTables) {
218:                _openjpaTables = openjpaTables;
219:            }
220:
221:            /**
222:             * Return the current schema group.
223:             */
224:            public SchemaGroup getSchemaGroup() {
225:                if (_group == null)
226:                    _group = new SchemaGroup();
227:                return _group;
228:            }
229:
230:            /**
231:             * Set the schema group to add generated schemas to.
232:             */
233:            public void setSchemaGroup(SchemaGroup group) {
234:                _group = group;
235:            }
236:
237:            /**
238:             * Generate all schemas set in the configuration. This method also
239:             * calls {@link #generateIndexes}, {@link #generatePrimaryKeys}, and
240:             * {@link #generateForeignKeys} automatically.
241:             */
242:            public void generateSchemas() throws SQLException {
243:                fireGenerationEvent(_loc.get("generating-schemas"));
244:                generateSchemas(null);
245:            }
246:
247:            /**
248:             * Generate the schemas and/or tables named in the given strings.
249:             * This method calls {@link #generateIndexes},
250:             * {@link #generatePrimaryKeys}, and {@link #generateForeignKeys}
251:             * automatically.
252:             */
253:            public void generateSchemas(String[] schemasAndTables)
254:                    throws SQLException {
255:                fireGenerationEvent(_loc.get("generating-schemas"));
256:
257:                Object[][] schemaMap;
258:                if (schemasAndTables == null || schemasAndTables.length == 0)
259:                    schemaMap = _allowed;
260:                else
261:                    schemaMap = parseSchemasList(schemasAndTables);
262:
263:                if (schemaMap == null) {
264:                    generateSchema(null, null);
265:
266:                    // estimate the number of schema objects we will need to visit
267:                    // in order to estimate progresss total for any listeners
268:                    int numTables = getTables(null).size();
269:                    _schemaObjects += numTables + (_pks ? numTables : 0)
270:                            + (_indexes ? numTables : 0)
271:                            + (_fks ? numTables : 0);
272:
273:                    if (_pks)
274:                        generatePrimaryKeys(null, null);
275:                    if (_indexes)
276:                        generateIndexes(null, null);
277:                    if (_fks)
278:                        generateForeignKeys(null, null);
279:                    return;
280:                }
281:
282:                // generate all schemas and tables
283:                for (int i = 0; i < schemaMap.length; i++)
284:                    generateSchema((String) schemaMap[i][0],
285:                            (String[]) schemaMap[i][1]);
286:
287:                // generate pks, indexes, fks
288:                String schemaName;
289:                String[] tableNames;
290:                for (int i = 0; i < schemaMap.length; i++) {
291:                    schemaName = (String) schemaMap[i][0];
292:                    tableNames = (String[]) schemaMap[i][1];
293:
294:                    // estimate the number of schema objects we will need to visit
295:                    // in order to estimate progresss total for any listeners
296:                    int numTables = (tableNames != null) ? tableNames.length
297:                            : getTables(schemaName).size();
298:                    _schemaObjects += numTables + (_pks ? numTables : 0)
299:                            + (_indexes ? numTables : 0)
300:                            + (_fks ? numTables : 0);
301:
302:                    if (_pks)
303:                        generatePrimaryKeys(schemaName, tableNames);
304:                    if (_indexes)
305:                        generateIndexes(schemaName, tableNames);
306:                    if (_fks)
307:                        generateForeignKeys(schemaName, tableNames);
308:                }
309:            }
310:
311:            /**
312:             * Add a fully-constructed {@link Schema} matching the given database
313:             * schema to the current group. No foreign keys are generated because
314:             * some keys might span schemas. You must call
315:             * {@link #generatePrimaryKeys}, {@link #generateIndexes}, and
316:             * {@link #generateForeignKeys} separately.
317:             *
318:             * @param name the database name of the schema, or null for all schemas
319:             * @param tableNames a list of tables to generate in the schema, or null
320:             * to generate all tables
321:             */
322:            public void generateSchema(String name, String[] tableNames)
323:                    throws SQLException {
324:                fireGenerationEvent(_loc.get("generating-schema", name));
325:
326:                // generate tables, including columns and primary keys
327:                Connection conn = _ds.getConnection();
328:                DatabaseMetaData meta = conn.getMetaData();
329:                try {
330:                    if (tableNames == null)
331:                        generateTables(name, null, conn, meta);
332:                    else
333:                        for (int i = 0; i < tableNames.length; i++)
334:                            generateTables(name, tableNames[i], conn, meta);
335:
336:                    if (_seqs)
337:                        generateSequences(name, null, conn, meta);
338:                } finally {
339:                    // some databases require a commit after metadata to release locks
340:                    try {
341:                        conn.commit();
342:                    } catch (SQLException se) {
343:                    }
344:                    try {
345:                        conn.close();
346:                    } catch (SQLException se) {
347:                    }
348:                }
349:            }
350:
351:            /**
352:             * Generate primary key information for the given schema. This method
353:             * must be called in addition to {@link #generateSchema}. It should
354:             * only be called after all schemas are generated. The schema name and
355:             * tables array can be null to indicate that indexes should be generated
356:             * for all schemas and/or tables.
357:             */
358:            public void generatePrimaryKeys(String schemaName,
359:                    String[] tableNames) throws SQLException {
360:                fireGenerationEvent(_loc.get("generating-all-primaries",
361:                        schemaName));
362:
363:                Connection conn = _ds.getConnection();
364:                DatabaseMetaData meta = conn.getMetaData();
365:                try {
366:                    if (tableNames == null)
367:                        generatePrimaryKeys(schemaName, null, conn, meta);
368:                    else
369:                        for (int i = 0; i < tableNames.length; i++)
370:                            generatePrimaryKeys(schemaName, tableNames[i],
371:                                    conn, meta);
372:                } finally {
373:                    // some databases require a commit after metadata to release locks
374:                    try {
375:                        conn.commit();
376:                    } catch (SQLException se) {
377:                    }
378:                    try {
379:                        conn.close();
380:                    } catch (SQLException se) {
381:                    }
382:                }
383:            }
384:
385:            /**
386:             * Generate index information for the given schema. This method
387:             * must be called in addition to {@link #generateSchema}. It should
388:             * only be called after all schemas are generated. The schema name and
389:             * tables array can be null to indicate that indexes should be generated
390:             * for all schemas and/or tables.
391:             */
392:            public void generateIndexes(String schemaName, String[] tableNames)
393:                    throws SQLException {
394:                fireGenerationEvent(_loc.get("generating-all-indexes",
395:                        schemaName));
396:
397:                Connection conn = _ds.getConnection();
398:                DatabaseMetaData meta = conn.getMetaData();
399:                try {
400:                    if (tableNames == null)
401:                        generateIndexes(schemaName, null, conn, meta);
402:                    else
403:                        for (int i = 0; i < tableNames.length; i++)
404:                            generateIndexes(schemaName, tableNames[i], conn,
405:                                    meta);
406:                } finally {
407:                    // some databases require a commit after metadata to release locks
408:                    try {
409:                        conn.commit();
410:                    } catch (SQLException se) {
411:                    }
412:                    try {
413:                        conn.close();
414:                    } catch (SQLException se) {
415:                    }
416:                }
417:            }
418:
419:            /**
420:             * Generate foreign key information for the given schema. This method
421:             * must be called in addition to {@link #generateSchema}. It should
422:             * only be called after all schemas are generated. The schema name and
423:             * tables array can be null to indicate that indexes should be generated
424:             * for all schemas and/or tables.
425:             */
426:            public void generateForeignKeys(String schemaName,
427:                    String[] tableNames) throws SQLException {
428:                fireGenerationEvent(_loc.get("generating-all-foreigns",
429:                        schemaName));
430:
431:                Connection conn = _ds.getConnection();
432:                DatabaseMetaData meta = conn.getMetaData();
433:                try {
434:                    if (tableNames == null)
435:                        generateForeignKeys(schemaName, null, conn, meta);
436:                    else
437:                        for (int i = 0; i < tableNames.length; i++)
438:                            generateForeignKeys(schemaName, tableNames[i],
439:                                    conn, meta);
440:                } finally {
441:                    // some databases require a commit after metadata to release locks
442:                    try {
443:                        conn.commit();
444:                    } catch (SQLException se) {
445:                    }
446:                    try {
447:                        conn.close();
448:                    } catch (SQLException se) {
449:                    }
450:                }
451:            }
452:
453:            /**
454:             * Adds all tables matching the given name pattern to the schema.
455:             */
456:            public void generateTables(String schemaName, String tableName,
457:                    Connection conn, DatabaseMetaData meta) throws SQLException {
458:                fireGenerationEvent(_loc.get("generating-columns", schemaName,
459:                        tableName));
460:                if (_log.isTraceEnabled())
461:                    _log.trace(_loc.get("gen-tables", schemaName, tableName));
462:
463:                Column[] cols = _dict.getColumns(meta, conn.getCatalog(),
464:                        schemaName, tableName, null, conn);
465:
466:                // when we want to get all the columns for all tables, we need to build
467:                // a list of tables to verify because some databases (e.g., Postgres)
468:                // will include indexes in the list of columns, and there is no way to
469:                // distinguish the indexes from proper columns
470:                Set tableNames = null;
471:                if (tableName == null || "%".equals(tableName)) {
472:                    Table[] tables = _dict.getTables(meta, conn.getCatalog(),
473:                            schemaName, tableName, conn);
474:                    tableNames = new HashSet();
475:                    for (int i = 0; tables != null && i < tables.length; i++) {
476:                        if (cols == null)
477:                            tableNames.add(tables[i].getName());
478:                        else
479:                            tableNames.add(tables[i].getName().toUpperCase());
480:                    }
481:                }
482:
483:                // if database can't handle null table name, recurse on each known name
484:                if (cols == null && tableName == null) {
485:                    for (Iterator itr = tableNames.iterator(); itr.hasNext();)
486:                        generateTables(schemaName, (String) itr.next(), conn,
487:                                meta);
488:                    return;
489:                }
490:
491:                SchemaGroup group = getSchemaGroup();
492:                Schema schema;
493:                Table table;
494:                String tableSchema;
495:                for (int i = 0; cols != null && i < cols.length; i++) {
496:                    tableName = cols[i].getTableName();
497:                    tableSchema = StringUtils.trimToNull(cols[i]
498:                            .getSchemaName());
499:
500:                    // ignore special tables
501:                    if (!_openjpaTables
502:                            && (tableName.toUpperCase().startsWith("OPENJPA_") || tableName
503:                                    .toUpperCase().startsWith("JDO_"))) // legacy
504:                        continue;
505:                    if (_dict.isSystemTable(tableName, tableSchema,
506:                            schemaName != null))
507:                        continue;
508:
509:                    // ignore tables not in list, or not allowed by schemas property
510:                    if (tableNames != null
511:                            && !tableNames.contains(tableName.toUpperCase()))
512:                        continue;
513:                    if (!isAllowedTable(tableSchema, tableName))
514:                        continue;
515:
516:                    schema = group.getSchema(tableSchema);
517:                    if (schema == null)
518:                        schema = group.addSchema(tableSchema);
519:
520:                    table = schema.getTable(tableName);
521:                    if (table == null) {
522:                        table = schema.addTable(tableName);
523:                        if (_log.isTraceEnabled())
524:                            _log.trace(_loc.get("col-table", table));
525:                    }
526:
527:                    if (_log.isTraceEnabled())
528:                        _log.trace(_loc.get("gen-column", cols[i].getName(),
529:                                table));
530:
531:                    if (table.getColumn(cols[i].getName()) == null)
532:                        table.importColumn(cols[i]);
533:                }
534:            }
535:
536:            /**
537:             * Return whether the given table is allowed by the user's schema list.
538:             */
539:            private boolean isAllowedTable(String schema, String table) {
540:                if (_allowed == null)
541:                    return true;
542:
543:                // do case-insensitive comparison on allowed table and schema names
544:                String[] tables;
545:                String[] anySchemaTables = null;
546:                for (int i = 0; i < _allowed.length; i++) {
547:                    if (_allowed[i][0] == null) {
548:                        anySchemaTables = (String[]) _allowed[i][1];
549:                        if (schema == null)
550:                            break;
551:                        continue;
552:                    }
553:                    if (!StringUtils.equalsIgnoreCase(schema,
554:                            (String) _allowed[i][0]))
555:                        continue;
556:
557:                    if (table == null)
558:                        return true;
559:                    tables = (String[]) _allowed[i][1];
560:                    if (tables == null)
561:                        return true;
562:                    for (int j = 0; j < tables.length; j++)
563:                        if (StringUtils.equalsIgnoreCase(table, tables[j]))
564:                            return true;
565:                }
566:
567:                if (anySchemaTables != null) {
568:                    if (table == null)
569:                        return true;
570:                    for (int i = 0; i < anySchemaTables.length; i++)
571:                        if (StringUtils.equalsIgnoreCase(table,
572:                                anySchemaTables[i]))
573:                            return true;
574:                }
575:                return false;
576:            }
577:
578:            /**
579:             * Generates table primary keys.
580:             */
581:            public void generatePrimaryKeys(String schemaName,
582:                    String tableName, Connection conn, DatabaseMetaData meta)
583:                    throws SQLException {
584:                fireGenerationEvent(_loc.get("generating-primary", schemaName,
585:                        tableName));
586:                if (_log.isTraceEnabled())
587:                    _log.trace(_loc.get("gen-pks", schemaName, tableName));
588:
589:                // if looking for a non-existant table, just return
590:                SchemaGroup group = getSchemaGroup();
591:                if (tableName != null && group.findTable(tableName) == null)
592:                    return;
593:
594:                // if the database can't use a table name wildcard, recurse on each
595:                // concrete table in the requested schema(s)
596:                PrimaryKey[] pks = _dict.getPrimaryKeys(meta,
597:                        conn.getCatalog(), schemaName, tableName, conn);
598:                Table table;
599:                if (pks == null && tableName == null) {
600:                    Collection tables = getTables(schemaName);
601:                    for (Iterator itr = tables.iterator(); itr.hasNext();) {
602:                        table = (Table) itr.next();
603:                        generatePrimaryKeys(table.getSchemaName(), table
604:                                .getName(), conn, meta);
605:                    }
606:                    return;
607:                }
608:
609:                Schema schema;
610:                PrimaryKey pk;
611:                String name;
612:                String colName;
613:                for (int i = 0; pks != null && i < pks.length; i++) {
614:                    schemaName = StringUtils.trimToNull(pks[i].getSchemaName());
615:                    schema = group.getSchema(schemaName);
616:                    if (schema == null)
617:                        continue;
618:                    table = schema.getTable(pks[i].getTableName());
619:                    if (table == null)
620:                        continue;
621:
622:                    colName = pks[i].getColumnName();
623:                    name = pks[i].getName();
624:                    if (_log.isTraceEnabled())
625:                        _log.trace(_loc.get("gen-pk", name, table, colName));
626:
627:                    pk = table.getPrimaryKey();
628:                    if (pk == null)
629:                        pk = table.addPrimaryKey(name);
630:                    pk.addColumn(table.getColumn(colName));
631:                }
632:            }
633:
634:            /**
635:             * Generates table indexes.
636:             */
637:            public void generateIndexes(String schemaName, String tableName,
638:                    Connection conn, DatabaseMetaData meta) throws SQLException {
639:                fireGenerationEvent(_loc.get("generating-indexes", schemaName,
640:                        tableName));
641:                if (_log.isTraceEnabled())
642:                    _log.trace(_loc.get("gen-indexes", schemaName, tableName));
643:
644:                // if looking for a non-existant table, just return
645:                SchemaGroup group = getSchemaGroup();
646:                if (tableName != null && group.findTable(tableName) == null)
647:                    return;
648:
649:                // if the database can't use a table name wildcard, recurse on each
650:                // concrete table in the requested schema(s)
651:                Index[] idxs = _dict.getIndexInfo(meta, conn.getCatalog(),
652:                        schemaName, tableName, false, true, conn);
653:                Table table;
654:                if (idxs == null && tableName == null) {
655:                    Collection tables = getTables(schemaName);
656:                    for (Iterator itr = tables.iterator(); itr.hasNext();) {
657:                        table = (Table) itr.next();
658:                        generateIndexes(table.getSchemaName(), table.getName(),
659:                                conn, meta);
660:                    }
661:                    return;
662:                }
663:
664:                Schema schema;
665:                Index idx;
666:                String name;
667:                String colName;
668:                String pkName;
669:                for (int i = 0; idxs != null && i < idxs.length; i++) {
670:                    schemaName = StringUtils
671:                            .trimToNull(idxs[i].getSchemaName());
672:                    schema = group.getSchema(schemaName);
673:                    if (schema == null)
674:                        continue;
675:                    table = schema.getTable(idxs[i].getTableName());
676:                    if (table == null)
677:                        continue;
678:
679:                    if (table.getPrimaryKey() != null)
680:                        pkName = table.getPrimaryKey().getName();
681:                    else
682:                        pkName = null;
683:
684:                    // statistics don't have names; skip them
685:                    name = idxs[i].getName();
686:                    if (StringUtils.isEmpty(name)
687:                            || (pkName != null && name.equalsIgnoreCase(pkName))
688:                            || _dict.isSystemIndex(name, table))
689:                        continue;
690:
691:                    colName = idxs[i].getColumnName();
692:                    if (table.getColumn(colName) == null)
693:                        continue;
694:
695:                    if (_log.isTraceEnabled())
696:                        _log.trace(_loc.get("gen-index", name, table, colName));
697:
698:                    // same index may have multiple rows for multiple cols
699:                    idx = table.getIndex(name);
700:                    if (idx == null) {
701:                        idx = table.addIndex(name);
702:                        idx.setUnique(idxs[i].isUnique());
703:                    }
704:                    idx.addColumn(table.getColumn(colName));
705:                }
706:            }
707:
708:            /**
709:             * Generates table foreign keys.
710:             */
711:            public void generateForeignKeys(String schemaName,
712:                    String tableName, Connection conn, DatabaseMetaData meta)
713:                    throws SQLException {
714:                fireGenerationEvent(_loc.get("generating-foreign", schemaName,
715:                        tableName));
716:                if (_log.isTraceEnabled())
717:                    _log.trace(_loc.get("gen-fks", schemaName, tableName));
718:
719:                // if looking for a non-existant table, just return
720:                SchemaGroup group = getSchemaGroup();
721:                if (tableName != null && group.findTable(tableName) == null)
722:                    return;
723:
724:                // if the database can't use a table name wildcard, recurse on each
725:                // concrete table in the requested schema(s)
726:                ForeignKey[] fks = _dict.getImportedKeys(meta, conn
727:                        .getCatalog(), schemaName, tableName, conn);
728:                Table table;
729:                if (fks == null && tableName == null) {
730:                    Collection tables = getTables(schemaName);
731:                    for (Iterator itr = tables.iterator(); itr.hasNext();) {
732:                        table = (Table) itr.next();
733:                        generateForeignKeys(table.getSchemaName(), table
734:                                .getName(), conn, meta);
735:                    }
736:                    return;
737:                }
738:
739:                Schema schema;
740:                Table pkTable;
741:                ForeignKey fk;
742:                String name;
743:                String pkSchemaName;
744:                String pkTableName;
745:                String pkColName;
746:                String fkColName;
747:                int seq;
748:                boolean seqWas0 = false; // some drivers incorrectly start at 0
749:                Collection invalids = null;
750:                for (int i = 0; fks != null && i < fks.length; i++) {
751:                    schemaName = StringUtils.trimToNull(fks[i].getSchemaName());
752:                    schema = group.getSchema(schemaName);
753:                    if (schema == null)
754:                        continue;
755:                    table = schema.getTable(fks[i].getTableName());
756:                    if (table == null)
757:                        continue;
758:
759:                    name = fks[i].getName();
760:                    fkColName = fks[i].getColumnName();
761:                    pkColName = fks[i].getPrimaryKeyColumnName();
762:                    seq = fks[i].getKeySequence();
763:                    if (seq == 0)
764:                        seqWas0 = true;
765:                    if (seqWas0)
766:                        seq++;
767:
768:                    // find pk table
769:                    pkSchemaName = fks[i].getPrimaryKeySchemaName();
770:                    pkTableName = fks[i].getPrimaryKeyTableName();
771:                    if (_log.isTraceEnabled())
772:                        _log.trace(_loc.get("gen-fk", new Object[] { name,
773:                                table, fkColName, pkTableName, pkColName,
774:                                seq + "" }));
775:
776:                    if (!StringUtils.isEmpty(pkSchemaName))
777:                        pkTableName = pkSchemaName + "." + pkTableName;
778:                    pkTable = group.findTable(pkTableName);
779:                    if (pkTable == null)
780:                        throw new SQLException(_loc.get("gen-nofktable", table,
781:                                pkTableName).getMessage());
782:
783:                    // this sucks, because it is *not* guaranteed to work;
784:                    // the fk resultset is ordered by primary key table, then
785:                    // sequence number within the foreign key (some drivers don't
786:                    // use sequence numbers correctly either); since fk names
787:                    // are allowed to be null, all this adds up to the fact
788:                    // that there is absolutely no way to distinguish between
789:                    // multiple multi-column fks to the same table; we're going
790:                    // to rely on fk name here and hope it works
791:                    fk = table.getForeignKey(name);
792:
793:                    // start a new fk?
794:                    if (seq == 1 || fk == null) {
795:                        fk = table.addForeignKey(name);
796:                        fk.setDeferred(fks[i].isDeferred());
797:                        fk.setDeleteAction(fks[i].getDeleteAction());
798:                    }
799:
800:                    if (invalids == null || !invalids.contains(fk)) {
801:                        try {
802:                            fk.join(table.getColumn(fkColName), pkTable
803:                                    .getColumn(pkColName));
804:                        } catch (IllegalArgumentException iae) {
805:                            if (_log.isWarnEnabled())
806:                                _log.warn(_loc.get("bad-join", iae.toString()));
807:                            if (invalids == null)
808:                                invalids = new HashSet();
809:                            invalids.add(fk);
810:                        }
811:                    }
812:                }
813:
814:                // remove invalid fks
815:                if (invalids != null) {
816:                    for (Iterator itr = invalids.iterator(); itr.hasNext();) {
817:                        fk = (ForeignKey) itr.next();
818:                        fk.getTable().removeForeignKey(fk);
819:                    }
820:                }
821:            }
822:
823:            /**
824:             * Adds all sequences matching the given name pattern to the schema.
825:             */
826:            public void generateSequences(String schemaName,
827:                    String sequenceName, Connection conn, DatabaseMetaData meta)
828:                    throws SQLException {
829:                fireGenerationEvent(_loc
830:                        .get("generating-sequences", schemaName));
831:                if (_log.isTraceEnabled())
832:                    _log.trace(_loc.get("gen-seqs", schemaName, sequenceName));
833:
834:                // since all the sequences are generated under the default schema
835:                // therefore, we can use the null schemaname to search
836:                Sequence[] seqs = _dict.getSequences(meta, conn.getCatalog(),
837:                        null, sequenceName, conn);
838:
839:                SchemaGroup group = getSchemaGroup();
840:                Schema schema;
841:                String sequenceSchema;
842:                for (int i = 0; seqs != null && i < seqs.length; i++) {
843:                    sequenceName = seqs[i].getName();
844:                    sequenceSchema = StringUtils.trimToNull(seqs[i]
845:                            .getSchemaName());
846:
847:                    // ignore special tables
848:                    if (!_openjpaTables
849:                            && (sequenceName.toUpperCase().startsWith(
850:                                    "OPENJPA_") || sequenceName.toUpperCase()
851:                                    .startsWith("JDO_"))) // legacy
852:                        continue;
853:                    if (_dict.isSystemSequence(sequenceName, sequenceSchema,
854:                            schemaName != null))
855:                        continue;
856:                    if (!isAllowedTable(sequenceSchema, null))
857:                        continue;
858:
859:                    schema = group.getSchema(sequenceSchema);
860:                    if (schema == null)
861:                        schema = group.addSchema(sequenceSchema);
862:                    if (schema.getSequence(sequenceName) == null)
863:                        schema.addSequence(sequenceName);
864:                }
865:            }
866:
867:            /**
868:             * Notify any listeners that a schema object was generated. Returns
869:             * true if generation should continue.
870:             */
871:            private void fireGenerationEvent(Object schemaObject)
872:                    throws SQLException {
873:                if (schemaObject == null)
874:                    return;
875:                if (_listeners == null || _listeners.size() == 0)
876:                    return;
877:
878:                Event e = new Event(schemaObject, _schemaObjects);
879:                for (Iterator i = _listeners.iterator(); i.hasNext();) {
880:                    Listener l = (Listener) i.next();
881:                    if (!l.schemaObjectGenerated(e))
882:                        throw new SQLException(_loc.get("refresh-cancelled")
883:                                .getMessage());
884:                }
885:            }
886:
887:            /**
888:             * Adds a listener for schema generation events.
889:             *
890:             * @param l the listener to add
891:             */
892:            public void addListener(Listener l) {
893:                if (_listeners == null)
894:                    _listeners = new LinkedList();
895:                _listeners.add(l);
896:            }
897:
898:            /**
899:             * Removes a schema generation listener for schema events.
900:             *
901:             * @param l the listener to remove
902:             * @return true if it was successfully removed
903:             */
904:            public boolean removeListener(Listener l) {
905:                return _listeners != null && _listeners.remove(l);
906:            }
907:
908:            /**
909:             * Return all tables for the given schema name, or all tables in
910:             * the schema group if null is given.
911:             */
912:            private Collection getTables(String schemaName) {
913:                SchemaGroup group = getSchemaGroup();
914:                if (schemaName != null) {
915:                    Schema schema = group.getSchema(schemaName);
916:                    if (schema == null)
917:                        return Collections.EMPTY_LIST;
918:                    return Arrays.asList(schema.getTables());
919:                }
920:
921:                Schema[] schemas = group.getSchemas();
922:                Collection tables = new LinkedList();
923:                for (int i = 0; i < schemas.length; i++)
924:                    tables.addAll(Arrays.asList(schemas[i].getTables()));
925:                return tables;
926:            }
927:
928:            /**
929:             * A listener for a potentially lengthy schema generation process.
930:             */
931:            public static interface Listener {
932:
933:                boolean schemaObjectGenerated(Event e);
934:            }
935:
936:            /**
937:             * An event corresponding to the generation of a schema object.
938:             */
939:            public class Event extends EventObject {
940:
941:                private final int _total;
942:
943:                public Event(Object ob, int total) {
944:                    super (ob);
945:                    _total = total;
946:                }
947:
948:                public int getTotal() {
949:                    return _total;
950:                }
951:            }
952:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.