Source Code Cross Referenced for SchemaTool.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) 


0001:        /*
0002:         * Licensed to the Apache Software Foundation (ASF) under one
0003:         * or more contributor license agreements.  See the NOTICE file
0004:         * distributed with this work for additional information
0005:         * regarding copyright ownership.  The ASF licenses this file
0006:         * to you under the Apache License, Version 2.0 (the
0007:         * "License"); you may not use this file except in compliance
0008:         * with the License.  You may obtain a copy of the License at
0009:         *
0010:         * http://www.apache.org/licenses/LICENSE-2.0
0011:         *
0012:         * Unless required by applicable law or agreed to in writing,
0013:         * software distributed under the License is distributed on an
0014:         * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0015:         * KIND, either express or implied.  See the License for the
0016:         * specific language governing permissions and limitations
0017:         * under the License.    
0018:         */
0019:        package org.apache.openjpa.jdbc.schema;
0020:
0021:        import java.io.File;
0022:        import java.io.IOException;
0023:        import java.io.PrintWriter;
0024:        import java.io.Writer;
0025:        import java.sql.Connection;
0026:        import java.sql.DatabaseMetaData;
0027:        import java.sql.SQLException;
0028:        import java.sql.Statement;
0029:        import java.util.Arrays;
0030:        import java.util.Collection;
0031:        import java.util.HashSet;
0032:        import java.util.Iterator;
0033:        import java.util.LinkedHashSet;
0034:        import java.util.LinkedList;
0035:        import java.util.Set;
0036:        import javax.sql.DataSource;
0037:
0038:        import org.apache.commons.lang.StringUtils;
0039:        import org.apache.openjpa.conf.OpenJPAConfiguration;
0040:        import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
0041:        import org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl;
0042:        import org.apache.openjpa.jdbc.sql.DBDictionary;
0043:        import org.apache.openjpa.jdbc.sql.SQLExceptions;
0044:        import org.apache.openjpa.lib.conf.Configurations;
0045:        import org.apache.openjpa.lib.log.Log;
0046:        import org.apache.openjpa.lib.util.Files;
0047:        import org.apache.openjpa.lib.util.Localizer;
0048:        import org.apache.openjpa.lib.util.Options;
0049:        import org.apache.openjpa.util.InvalidStateException;
0050:
0051:        /**
0052:         * The SchemaTool is used to manage the database schema. Note that the
0053:         * tool never adds or drops unique constraints from existing tables, because
0054:         * JDBC {@link DatabaseMetaData} does not include information on these
0055:         * constraints.
0056:         *
0057:         * @author Abe White
0058:         * @author Patrick Linskey
0059:         */
0060:        public class SchemaTool {
0061:
0062:            public static final String ACTION_ADD = "add";
0063:            public static final String ACTION_DROP = "drop";
0064:            public static final String ACTION_RETAIN = "retain";
0065:            public static final String ACTION_REFRESH = "refresh";
0066:            public static final String ACTION_BUILD = "build";
0067:            public static final String ACTION_REFLECT = "reflect";
0068:            public static final String ACTION_CREATEDB = "createDB";
0069:            public static final String ACTION_DROPDB = "dropDB";
0070:            public static final String ACTION_IMPORT = "import";
0071:            public static final String ACTION_EXPORT = "export";
0072:            public static final String ACTION_DELETE_TABLE_CONTENTS = "deleteTableContents";
0073:
0074:            public static final String[] ACTIONS = new String[] { ACTION_ADD,
0075:                    ACTION_DROP, ACTION_RETAIN, ACTION_REFRESH, ACTION_BUILD,
0076:                    ACTION_REFLECT, ACTION_CREATEDB, ACTION_DROPDB,
0077:                    ACTION_IMPORT, ACTION_EXPORT, ACTION_DELETE_TABLE_CONTENTS, };
0078:
0079:            private static final Localizer _loc = Localizer
0080:                    .forPackage(SchemaTool.class);
0081:
0082:            private final JDBCConfiguration _conf;
0083:            private final DataSource _ds;
0084:            private final Log _log;
0085:            private final DBDictionary _dict;
0086:            private final String _action;
0087:            private boolean _ignoreErrs = false;
0088:            private boolean _openjpaTables = false;
0089:            private boolean _dropTables = true;
0090:            private boolean _dropSeqs = true;
0091:            private boolean _pks = true;
0092:            private boolean _fks = true;
0093:            private boolean _indexes = true;
0094:            private boolean _seqs = true;
0095:            private PrintWriter _writer = null;
0096:            private SchemaGroup _group = null;
0097:            private SchemaGroup _db = null;
0098:            private boolean _fullDB = false;
0099:
0100:            /**
0101:             * Default constructor. Tools constructed this way will not have an
0102:             * action, so the {@link #run()} method will be a no-op.
0103:             */
0104:            public SchemaTool(JDBCConfiguration conf) {
0105:                this (conf, null);
0106:            }
0107:
0108:            /**
0109:             * Construct a tool to perform the given action.
0110:             */
0111:            public SchemaTool(JDBCConfiguration conf, String action) {
0112:                if (action != null && !Arrays.asList(ACTIONS).contains(action))
0113:                    throw new IllegalArgumentException("action == " + action);
0114:
0115:                _conf = conf;
0116:                _action = action;
0117:                _ds = conf.getDataSource2(null);
0118:                _log = conf.getLog(JDBCConfiguration.LOG_SCHEMA);
0119:
0120:                // initialize this up-front; otherwise the dbdictionaryfactory might
0121:                // try to take a connection to initialize when we've already got one:
0122:                // bad news if the max pool is 1
0123:                _dict = _conf.getDBDictionaryInstance();
0124:            }
0125:
0126:            /**
0127:             * The action supplied on construction.
0128:             */
0129:            public String getAction() {
0130:                return _action;
0131:            }
0132:
0133:            /**
0134:             * If true, SQLExceptions thrown during schema manipulation will be
0135:             * printed but ignored.
0136:             */
0137:            public boolean getIgnoreErrors() {
0138:                return _ignoreErrs;
0139:            }
0140:
0141:            /**
0142:             * If true, SQLExceptions thrown during schema manipulation will be
0143:             * printed but ignored.
0144:             */
0145:            public void setIgnoreErrors(boolean ignoreErrs) {
0146:                _ignoreErrs = ignoreErrs;
0147:            }
0148:
0149:            /**
0150:             * Whether to act on special tables used by OpenJPA components
0151:             * for bookkeeping.
0152:             */
0153:            public boolean getOpenJPATables() {
0154:                return _openjpaTables;
0155:            }
0156:
0157:            /**
0158:             * Whether to act on special tables used by OpenJPA components
0159:             * for bookkeeping.
0160:             */
0161:            public void setOpenJPATables(boolean openjpaTables) {
0162:                _openjpaTables = openjpaTables;
0163:            }
0164:
0165:            /**
0166:             * If true, tables that appear to be unused will be dropped. Defaults to
0167:             * true.
0168:             */
0169:            public boolean getDropTables() {
0170:                return _dropTables;
0171:            }
0172:
0173:            /**
0174:             * If true, tables that appear to be unused will be dropped. Defaults to
0175:             * true.
0176:             */
0177:            public void setDropTables(boolean dropTables) {
0178:                _dropTables = dropTables;
0179:            }
0180:
0181:            /**
0182:             * If true, sequences that appear to be unused will be dropped. Defaults
0183:             * to true.
0184:             */
0185:            public boolean getDropSequences() {
0186:                return _dropSeqs;
0187:            }
0188:
0189:            /**
0190:             * If true, sequences that appear to be unused will be dropped. Defaults
0191:             * to true.
0192:             */
0193:            public void setDropSequences(boolean dropSeqs) {
0194:                _dropSeqs = dropSeqs;
0195:                if (dropSeqs)
0196:                    setSequences(true);
0197:            }
0198:
0199:            /**
0200:             * Whether sequences should be manipulated. Defaults to true.
0201:             */
0202:            public boolean getSequences() {
0203:                return _seqs;
0204:            }
0205:
0206:            /**
0207:             * Whether sequences should be manipulated. Defaults to true.
0208:             */
0209:            public void setSequences(boolean seqs) {
0210:                _seqs = seqs;
0211:            }
0212:
0213:            /**
0214:             * Whether indexes on existing tables should be manipulated.
0215:             * Defaults to true.
0216:             */
0217:            public boolean getIndexes() {
0218:                return _indexes;
0219:            }
0220:
0221:            /**
0222:             * Whether indexes on existing tables should be manipulated.
0223:             * Defaults to true.
0224:             */
0225:            public void setIndexes(boolean indexes) {
0226:                _indexes = indexes;
0227:            }
0228:
0229:            /**
0230:             * Whether foreign keys on existing tables should be manipulated.
0231:             * Defaults to true.
0232:             */
0233:            public boolean getForeignKeys() {
0234:                return _fks;
0235:            }
0236:
0237:            /**
0238:             * Whether foreign keys on existing tables should be manipulated.
0239:             * Defaults to true.
0240:             */
0241:            public void setForeignKeys(boolean fks) {
0242:                _fks = fks;
0243:            }
0244:
0245:            /**
0246:             * Whether primary keys on existing tables should be manipulated.
0247:             * Defaults to true.
0248:             */
0249:            public boolean getPrimaryKeys() {
0250:                return _pks;
0251:            }
0252:
0253:            /**
0254:             * Whether primary keys on existing tables should be manipulated.
0255:             * Defaults to true.
0256:             */
0257:            public void setPrimaryKeys(boolean pks) {
0258:                _pks = pks;
0259:            }
0260:
0261:            /**
0262:             * The stream to write to for the creation of SQL scripts. If the
0263:             * stream is non-null, all SQL will be written to this stream rather than
0264:             * executed against the database.
0265:             */
0266:            public Writer getWriter() {
0267:                return _writer;
0268:            }
0269:
0270:            /**
0271:             * The stream to write to for the creation of SQL scripts. If the
0272:             * stream is non-null, all SQL will be written to this stream rather than
0273:             * executed against the database.
0274:             */
0275:            public void setWriter(Writer writer) {
0276:                if (writer == null)
0277:                    _writer = null;
0278:                else if (writer instanceof  PrintWriter)
0279:                    _writer = (PrintWriter) writer;
0280:                else
0281:                    _writer = new PrintWriter(writer);
0282:            }
0283:
0284:            /**
0285:             * Return the schema group the tool will act on.
0286:             */
0287:            public SchemaGroup getSchemaGroup() {
0288:                return _group;
0289:            }
0290:
0291:            /**
0292:             * Set the schema group the tool will act on.
0293:             */
0294:            public void setSchemaGroup(SchemaGroup group) {
0295:                _group = group;
0296:            }
0297:
0298:            ///////////
0299:            // Actions
0300:            ///////////
0301:
0302:            /**
0303:             * Run the tool action.
0304:             */
0305:            public void run() throws SQLException {
0306:                if (_action == null)
0307:                    return;
0308:
0309:                if (ACTION_ADD.equals(_action))
0310:                    add();
0311:                else if (ACTION_DROP.equals(_action))
0312:                    drop();
0313:                else if (ACTION_RETAIN.equals(_action))
0314:                    retain();
0315:                else if (ACTION_REFRESH.equals(_action))
0316:                    refresh();
0317:                else if (ACTION_BUILD.equals(_action))
0318:                    build();
0319:                else if (ACTION_CREATEDB.equals(_action))
0320:                    createDB();
0321:                else if (ACTION_DROPDB.equals(_action))
0322:                    dropDB();
0323:                else if (ACTION_DELETE_TABLE_CONTENTS.equals(_action))
0324:                    deleteTableContents();
0325:            }
0326:
0327:            /**
0328:             * Adds any components present in the schema repository but absent from
0329:             * the database. Package-private for testing.
0330:             */
0331:            void add() throws SQLException {
0332:                add(getDBSchemaGroup(false), assertSchemaGroup());
0333:            }
0334:
0335:            /**
0336:             * Drops all schema components in the schema repository that also exist
0337:             * in the database. Package-private for testing.
0338:             */
0339:            void drop() throws SQLException {
0340:                drop(getDBSchemaGroup(false), assertSchemaGroup());
0341:            }
0342:
0343:            /**
0344:             * Drops database components that are not mentioned in the schema
0345:             * repository. Package-private for testing.
0346:             */
0347:            void retain() throws SQLException {
0348:                retain(getDBSchemaGroup(true), assertSchemaGroup(),
0349:                        getDropTables(), getDropSequences());
0350:            }
0351:
0352:            /**
0353:             * Adds any components present in the schema repository but absent from
0354:             * the database, and drops unused database components.
0355:             * Package-private for testing.
0356:             */
0357:            void refresh() throws SQLException {
0358:                SchemaGroup local = assertSchemaGroup();
0359:                SchemaGroup db = getDBSchemaGroup(true);
0360:                retain(db, local, getDropTables(), getDropSequences());
0361:                add(db, local);
0362:            }
0363:
0364:            /**
0365:             * Re-execute all SQL used for the creation of the current database;
0366:             * this action is usually used when creating SQL scripts.
0367:             * Package-private for testing.
0368:             */
0369:            void createDB() throws SQLException {
0370:                SchemaGroup group = new SchemaGroup();
0371:                group.addSchema();
0372:                add(group, getDBSchemaGroup(true));
0373:            }
0374:
0375:            /**
0376:             * Re-execute all SQL used for the creation of the current database;
0377:             * this action is usually used when creating SQL scripts.
0378:             * Package-private for testing.
0379:             */
0380:            void build() throws SQLException {
0381:                SchemaGroup group = new SchemaGroup();
0382:                group.addSchema();
0383:                add(group, assertSchemaGroup());
0384:            }
0385:
0386:            /**
0387:             * Drop the current database. Package-private for testing.
0388:             */
0389:            void dropDB() throws SQLException {
0390:                retain(getDBSchemaGroup(true), new SchemaGroup(), true, true);
0391:            }
0392:
0393:            /**
0394:             * Issue DELETE statement against all known tables.
0395:             */
0396:            private void deleteTableContents() throws SQLException {
0397:                SchemaGroup group = getSchemaGroup();
0398:                Schema[] schemas = group.getSchemas();
0399:                Collection tables = new LinkedHashSet();
0400:                for (int i = 0; i < schemas.length; i++) {
0401:                    Table[] ts = schemas[i].getTables();
0402:                    for (int j = 0; j < ts.length; j++)
0403:                        tables.add(ts[j]);
0404:                }
0405:                Table[] tableArray = (Table[]) tables.toArray(new Table[tables
0406:                        .size()]);
0407:                String[] sql = _conf.getDBDictionaryInstance()
0408:                        .getDeleteTableContentsSQL(tableArray);
0409:                if (!executeSQL(sql))
0410:                    _log.warn(_loc.get("delete-table-contents"));
0411:            }
0412:
0413:            /**
0414:             * Record the changes made to the DB in the current {@link SchemaFactory}.
0415:             */
0416:            public void record() {
0417:                if (_db != null && _writer == null)
0418:                    _conf.getSchemaFactoryInstance().storeSchema(_db);
0419:            }
0420:
0421:            /**
0422:             * Adds all database components in the repository schema that are not
0423:             * present in the given database schema to the database.
0424:             */
0425:            private void add(SchemaGroup db, SchemaGroup repos)
0426:                    throws SQLException {
0427:                // add sequences
0428:                Schema[] schemas = repos.getSchemas();
0429:                Schema schema;
0430:                if (_seqs) {
0431:                    Sequence[] seqs;
0432:                    for (int i = 0; i < schemas.length; i++) {
0433:                        seqs = schemas[i].getSequences();
0434:                        for (int j = 0; j < seqs.length; j++) {
0435:                            if (db.findSequence(schemas[i], seqs[j]
0436:                                    .getFullName()) != null)
0437:                                continue;
0438:
0439:                            if (createSequence(seqs[j])) {
0440:                                schema = db.getSchema(seqs[j].getSchemaName());
0441:                                if (schema == null)
0442:                                    schema = db.addSchema(seqs[j]
0443:                                            .getSchemaName());
0444:                                schema.importSequence(seqs[j]);
0445:                            } else
0446:                                _log.warn(_loc.get("add-seq", seqs[j]));
0447:                        }
0448:                    }
0449:                }
0450:
0451:                // order is important in this method; start with columns
0452:                Table[] tabs;
0453:                Table dbTable;
0454:                Column[] cols;
0455:                Column col;
0456:                for (int i = 0; i < schemas.length; i++) {
0457:                    tabs = schemas[i].getTables();
0458:                    for (int j = 0; j < tabs.length; j++) {
0459:                        cols = tabs[j].getColumns();
0460:                        dbTable = db.findTable(schemas[i], tabs[j]
0461:                                .getFullName());
0462:                        for (int k = 0; k < cols.length; k++) {
0463:                            if (dbTable != null) {
0464:                                col = dbTable.getColumn(cols[k].getName());
0465:                                if (col == null) {
0466:                                    if (addColumn(cols[k]))
0467:                                        dbTable.importColumn(cols[k]);
0468:                                    else
0469:                                        _log.warn(_loc.get("add-col", cols[k],
0470:                                                tabs[j]));
0471:                                } else if (!cols[k].equalsColumn(col)) {
0472:                                    _log.warn(_loc.get("bad-col", new Object[] {
0473:                                            col, dbTable, col.getDescription(),
0474:                                            cols[k].getDescription() }));
0475:                                }
0476:                            }
0477:                        }
0478:                    }
0479:                }
0480:
0481:                // primary keys
0482:                if (_pks) {
0483:                    PrimaryKey pk;
0484:                    for (int i = 0; i < schemas.length; i++) {
0485:                        tabs = schemas[i].getTables();
0486:                        for (int j = 0; j < tabs.length; j++) {
0487:                            pk = tabs[j].getPrimaryKey();
0488:                            dbTable = db.findTable(schemas[i], tabs[j]
0489:                                    .getFullName());
0490:                            if (pk != null && !pk.isLogical()
0491:                                    && dbTable != null) {
0492:                                if (dbTable.getPrimaryKey() == null
0493:                                        && addPrimaryKey(pk))
0494:                                    dbTable.importPrimaryKey(pk);
0495:                                else if (dbTable.getPrimaryKey() == null)
0496:                                    _log.warn(_loc.get("add-pk", pk, tabs[j]));
0497:                                else if (!pk.equalsPrimaryKey(dbTable
0498:                                        .getPrimaryKey()))
0499:                                    _log.warn(_loc.get("bad-pk", dbTable
0500:                                            .getPrimaryKey(), dbTable));
0501:                            }
0502:                        }
0503:                    }
0504:                }
0505:
0506:                // tables
0507:                Set newTables = new HashSet();
0508:                for (int i = 0; i < schemas.length; i++) {
0509:                    tabs = schemas[i].getTables();
0510:                    for (int j = 0; j < tabs.length; j++) {
0511:                        if (db.findTable(schemas[i], tabs[j].getFullName()) != null)
0512:                            continue;
0513:
0514:                        if (createTable(tabs[j])) {
0515:                            newTables.add(tabs[j]);
0516:                            schema = db.getSchema(tabs[j].getSchemaName());
0517:                            if (schema == null)
0518:                                schema = db.addSchema(tabs[j].getSchemaName());
0519:                            schema.importTable(tabs[j]);
0520:                        } else
0521:                            _log.warn(_loc.get("add-table", tabs[j]));
0522:                    }
0523:                }
0524:
0525:                // indexes
0526:                Index[] idxs;
0527:                Index idx;
0528:                for (int i = 0; i < schemas.length; i++) {
0529:                    tabs = schemas[i].getTables();
0530:                    for (int j = 0; j < tabs.length; j++) {
0531:                        // create indexes on new tables even if indexes
0532:                        // have been turned off
0533:                        if (!_indexes && !newTables.contains(tabs[j]))
0534:                            continue;
0535:
0536:                        idxs = tabs[j].getIndexes();
0537:                        dbTable = db.findTable(schemas[i], tabs[j]
0538:                                .getFullName());
0539:                        for (int k = 0; k < idxs.length; k++) {
0540:                            if (dbTable != null) {
0541:                                idx = findIndex(dbTable, idxs[k]);
0542:                                if (idx == null) {
0543:                                    if (createIndex(idxs[k], dbTable))
0544:                                        dbTable.importIndex(idxs[k]);
0545:                                    else
0546:                                        _log.warn(_loc.get("add-index",
0547:                                                idxs[k], tabs[j]));
0548:                                } else if (!idxs[k].equalsIndex(idx))
0549:                                    _log.warn(_loc.get("bad-index", idx,
0550:                                            dbTable));
0551:                            }
0552:                        }
0553:                    }
0554:                }
0555:
0556:                // Unique Constraints on group of columns
0557:                Unique[] uniques;
0558:                for (int i = 0; i < schemas.length; i++) {
0559:                    tabs = schemas[i].getTables();
0560:                    for (int j = 0; j < tabs.length; j++) {
0561:                        // create unique constraints only on new tables 
0562:                        if (!newTables.contains(tabs[j]))
0563:                            continue;
0564:
0565:                        uniques = tabs[j].getUniques();
0566:                        if (uniques == null || uniques.length == 0)
0567:                            continue;
0568:                        dbTable = db.findTable(tabs[j]);
0569:                        if (dbTable == null)
0570:                            continue;
0571:                        for (int k = 0; k < uniques.length; k++) {
0572:                            dbTable.importUnique(uniques[k]);
0573:                        }
0574:                    }
0575:                }
0576:
0577:                // foreign keys
0578:                ForeignKey[] fks;
0579:                ForeignKey fk;
0580:                for (int i = 0; i < schemas.length; i++) {
0581:                    tabs = schemas[i].getTables();
0582:                    for (int j = 0; j < tabs.length; j++) {
0583:                        // create foreign keys on new tables even if fks
0584:                        // have been turned off
0585:                        if (!_fks && !newTables.contains(tabs[j]))
0586:                            continue;
0587:
0588:                        fks = tabs[j].getForeignKeys();
0589:                        dbTable = db.findTable(schemas[i], tabs[j]
0590:                                .getFullName());
0591:                        for (int k = 0; k < fks.length; k++) {
0592:                            if (!fks[k].isLogical() && dbTable != null) {
0593:                                fk = findForeignKey(dbTable, fks[k]);
0594:                                if (fk == null) {
0595:                                    if (addForeignKey(fks[k]))
0596:                                        dbTable.importForeignKey(fks[k]);
0597:                                    else
0598:                                        _log.warn(_loc.get("add-fk", fks[k],
0599:                                                tabs[j]));
0600:                                } else if (!fks[k].equalsForeignKey(fk))
0601:                                    _log.warn(_loc.get("bad-fk", fk, dbTable));
0602:                            }
0603:                        }
0604:                    }
0605:                }
0606:            }
0607:
0608:            /**
0609:             * Drops all database components that are in the given database schema
0610:             * but not in the repository schema.
0611:             */
0612:            private void retain(SchemaGroup db, SchemaGroup repos,
0613:                    boolean tables, boolean sequences) throws SQLException {
0614:                Schema[] schemas = db.getSchemas();
0615:                if (_seqs && sequences) {
0616:                    Sequence[] seqs;
0617:                    for (int i = 0; i < schemas.length; i++) {
0618:                        seqs = schemas[i].getSequences();
0619:                        for (int j = 0; j < seqs.length; j++) {
0620:                            if (!isDroppable(seqs[j]))
0621:                                continue;
0622:                            if (repos.findSequence(seqs[j]) == null) {
0623:                                if (dropSequence(seqs[j]))
0624:                                    schemas[i].removeSequence(seqs[j]);
0625:                                else
0626:                                    _log.warn(_loc.get("drop-seq", seqs[j]));
0627:                            }
0628:                        }
0629:                    }
0630:                }
0631:
0632:                // order is important in this method; start with foreign keys
0633:                Table[] tabs;
0634:                Table reposTable;
0635:                if (_fks) {
0636:                    ForeignKey[] fks;
0637:                    ForeignKey fk;
0638:                    for (int i = 0; i < schemas.length; i++) {
0639:                        tabs = schemas[i].getTables();
0640:                        for (int j = 0; j < tabs.length; j++) {
0641:                            if (!isDroppable(tabs[j]))
0642:                                continue;
0643:                            fks = tabs[j].getForeignKeys();
0644:                            reposTable = repos.findTable(tabs[j]);
0645:                            if (!tables && reposTable == null)
0646:                                continue;
0647:
0648:                            for (int k = 0; k < fks.length; k++) {
0649:                                if (fks[k].isLogical())
0650:                                    continue;
0651:
0652:                                fk = null;
0653:                                if (reposTable != null)
0654:                                    fk = findForeignKey(reposTable, fks[k]);
0655:                                if (reposTable == null || fk == null
0656:                                        || !fks[k].equalsForeignKey(fk)) {
0657:                                    if (dropForeignKey(fks[k]))
0658:                                        tabs[j].removeForeignKey(fks[k]);
0659:                                    else
0660:                                        _log.warn(_loc.get("drop-fk", fks[k],
0661:                                                tabs[j]));
0662:                                }
0663:                            }
0664:                        }
0665:                    }
0666:                }
0667:
0668:                // primary keys
0669:                if (_pks) {
0670:                    PrimaryKey pk;
0671:                    for (int i = 0; i < schemas.length; i++) {
0672:                        tabs = schemas[i].getTables();
0673:                        for (int j = 0; j < tabs.length; j++) {
0674:                            if (!isDroppable(tabs[j]))
0675:                                continue;
0676:                            pk = tabs[j].getPrimaryKey();
0677:                            if (pk != null && pk.isLogical())
0678:                                continue;
0679:
0680:                            reposTable = repos.findTable(tabs[j]);
0681:                            if (pk != null
0682:                                    && reposTable != null
0683:                                    && (reposTable.getPrimaryKey() == null || !pk
0684:                                            .equalsPrimaryKey(reposTable
0685:                                                    .getPrimaryKey()))) {
0686:                                if (dropPrimaryKey(pk))
0687:                                    tabs[j].removePrimaryKey();
0688:                                else
0689:                                    _log.warn(_loc.get("drop-pk", pk, tabs[j]));
0690:                            }
0691:                        }
0692:                    }
0693:                }
0694:
0695:                // columns
0696:                Column[] cols;
0697:                Column col;
0698:                Collection drops = new LinkedList();
0699:                for (int i = 0; i < schemas.length; i++) {
0700:                    tabs = schemas[i].getTables();
0701:                    for (int j = 0; j < tabs.length; j++) {
0702:                        if (!isDroppable(tabs[j]))
0703:                            continue;
0704:                        cols = tabs[j].getColumns();
0705:                        reposTable = repos.findTable(tabs[j]);
0706:                        if (reposTable != null) {
0707:                            for (int k = 0; k < cols.length; k++) {
0708:                                col = reposTable.getColumn(cols[k].getName());
0709:                                if (col == null || !cols[k].equalsColumn(col)) {
0710:                                    if (tabs[j].getColumns().length == 1)
0711:                                        drops.add(tabs[j]);
0712:                                    else if (dropColumn(cols[k]))
0713:                                        tabs[j].removeColumn(cols[k]);
0714:                                    else
0715:                                        _log.warn(_loc.get("drop-col", cols[k],
0716:                                                tabs[j]));
0717:                                }
0718:                            }
0719:                        }
0720:                    }
0721:                }
0722:
0723:                // now tables
0724:                if (tables) {
0725:                    for (int i = 0; i < schemas.length; i++) {
0726:                        tabs = schemas[i].getTables();
0727:                        for (int j = 0; j < tabs.length; j++)
0728:                            if (!!isDroppable(tabs[j])
0729:                                    && repos.findTable(tabs[j]) == null)
0730:                                drops.add(tabs[j]);
0731:                    }
0732:                }
0733:                dropTables(drops, db);
0734:            }
0735:
0736:            /**
0737:             * Drops all database components in the given repository schema.
0738:             */
0739:            private void drop(SchemaGroup db, SchemaGroup repos)
0740:                    throws SQLException {
0741:                // drop sequences
0742:                Schema[] schemas = repos.getSchemas();
0743:                if (_seqs) {
0744:                    Sequence[] seqs;
0745:                    Sequence dbSeq;
0746:                    for (int i = 0; i < schemas.length; i++) {
0747:                        seqs = schemas[i].getSequences();
0748:                        for (int j = 0; j < seqs.length; j++) {
0749:                            if (!isDroppable(seqs[j]))
0750:                                continue;
0751:                            dbSeq = db.findSequence(seqs[j]);
0752:                            if (dbSeq != null) {
0753:                                if (dropSequence(seqs[j]))
0754:                                    dbSeq.getSchema().removeSequence(dbSeq);
0755:                                else
0756:                                    _log.warn(_loc.get("drop-seq", seqs[j]));
0757:                            }
0758:                        }
0759:                    }
0760:                }
0761:
0762:                // calculate tables to drop; we can only drop tables if we're sure
0763:                // the user listed the entire table definition in the stuff they want
0764:                // dropped; else they might just want to drop a few columns
0765:                Collection drops = new LinkedList();
0766:                Table[] tabs;
0767:                Table dbTable;
0768:                Column[] dbCols;
0769:                for (int i = 0; i < schemas.length; i++) {
0770:                    tabs = schemas[i].getTables();
0771:                    tables: for (int j = 0; j < tabs.length; j++) {
0772:                        if (!isDroppable(tabs[j]))
0773:                            continue;
0774:                        dbTable = db.findTable(tabs[j]);
0775:                        if (dbTable == null)
0776:                            continue;
0777:
0778:                        dbCols = dbTable.getColumns();
0779:                        for (int k = 0; k < dbCols.length; k++)
0780:                            if (tabs[j].getColumn(dbCols[k].getName()) == null)
0781:                                continue tables;
0782:
0783:                        drops.add(tabs[j]);
0784:                    }
0785:                }
0786:
0787:                // order is important in this method; start with foreign keys mentioned
0788:                // in the drop schema
0789:                if (_fks) {
0790:                    ForeignKey[] fks;
0791:                    ForeignKey fk;
0792:                    for (int i = 0; i < schemas.length; i++) {
0793:                        tabs = schemas[i].getTables();
0794:                        for (int j = 0; j < tabs.length; j++) {
0795:                            if (!isDroppable(tabs[j]))
0796:                                continue;
0797:                            fks = tabs[j].getForeignKeys();
0798:                            dbTable = db.findTable(tabs[j]);
0799:                            for (int k = 0; k < fks.length; k++) {
0800:                                if (fks[k].isLogical())
0801:                                    continue;
0802:
0803:                                fk = null;
0804:                                if (dbTable != null)
0805:                                    fk = findForeignKey(dbTable, fks[k]);
0806:                                if (dbTable == null || fk == null)
0807:                                    continue;
0808:
0809:                                if (dropForeignKey(fks[k]))
0810:                                    if (dbTable != null)
0811:                                        dbTable.removeForeignKey(fk);
0812:                                    else
0813:                                        _log.warn(_loc.get("drop-fk", fks[k],
0814:                                                tabs[j]));
0815:                            }
0816:                        }
0817:                    }
0818:
0819:                    // also drop imported foreign keys for tables that will be dropped
0820:                    Table tab;
0821:                    for (Iterator itr = drops.iterator(); itr.hasNext();) {
0822:                        tab = (Table) itr.next();
0823:                        dbTable = db.findTable(tab);
0824:                        if (dbTable == null)
0825:                            continue;
0826:
0827:                        fks = db.findExportedForeignKeys(dbTable
0828:                                .getPrimaryKey());
0829:                        for (int i = 0; i < fks.length; i++) {
0830:                            if (dropForeignKey(fks[i]))
0831:                                dbTable.removeForeignKey(fks[i]);
0832:                            else
0833:                                _log.warn(_loc.get("drop-fk", fks[i], dbTable));
0834:                        }
0835:                    }
0836:                }
0837:
0838:                // drop the tables we calculated above
0839:                dropTables(drops, db);
0840:
0841:                // columns
0842:                Column[] cols;
0843:                Column col;
0844:                for (int i = 0; i < schemas.length; i++) {
0845:                    tabs = schemas[i].getTables();
0846:                    for (int j = 0; j < tabs.length; j++) {
0847:                        if (!isDroppable(tabs[j]))
0848:                            continue;
0849:                        cols = tabs[j].getColumns();
0850:                        dbTable = db.findTable(tabs[j]);
0851:                        for (int k = 0; k < cols.length; k++) {
0852:                            col = null;
0853:                            if (dbTable != null)
0854:                                col = dbTable.getColumn(cols[k].getName());
0855:                            if (dbTable == null || col == null)
0856:                                continue;
0857:
0858:                            if (dropColumn(cols[k])) {
0859:                                if (dbTable != null)
0860:                                    dbTable.removeColumn(col);
0861:                                else
0862:                                    _log.warn(_loc.get("drop-col", cols[k],
0863:                                            tabs[j]));
0864:                            }
0865:                        }
0866:                    }
0867:                }
0868:            }
0869:
0870:            /**
0871:             * Return true if the table is droppable.
0872:             */
0873:            private boolean isDroppable(Table table) {
0874:                return _openjpaTables
0875:                        || (!table.getName().toUpperCase().startsWith(
0876:                                "OPENJPA_") && !table.getName().toUpperCase()
0877:                                .startsWith("JDO_")); // legacy
0878:            }
0879:
0880:            /**
0881:             * Return true if the sequence is droppable.
0882:             */
0883:            private boolean isDroppable(Sequence seq) {
0884:                return _openjpaTables
0885:                        || (!seq.getName().toUpperCase().startsWith("OPENJPA_") && !seq
0886:                                .getName().toUpperCase().startsWith("JDO_")); // legacy
0887:            }
0888:
0889:            /**
0890:             * Find an index in the given table that matches the given one.
0891:             */
0892:            private Index findIndex(Table dbTable, Index idx) {
0893:                Index[] idxs = dbTable.getIndexes();
0894:                for (int i = 0; i < idxs.length; i++)
0895:                    if (idx.columnsMatch(idxs[i].getColumns()))
0896:                        return idxs[i];
0897:                return null;
0898:            }
0899:
0900:            /**
0901:             * Find a foreign key in the given table that matches the given one.
0902:             */
0903:            private ForeignKey findForeignKey(Table dbTable, ForeignKey fk) {
0904:                if (fk.getConstantColumns().length > 0
0905:                        || fk.getConstantPrimaryKeyColumns().length > 0)
0906:                    return null;
0907:                ForeignKey[] fks = dbTable.getForeignKeys();
0908:                for (int i = 0; i < fks.length; i++)
0909:                    if (fk.columnsMatch(fks[i].getColumns(), fks[i]
0910:                            .getPrimaryKeyColumns()))
0911:                        return fks[i];
0912:                return null;
0913:            }
0914:
0915:            /**
0916:             * Remove the given collection of tables from the database schema. Orders
0917:             * the removals according to foreign key constraints on the tables.
0918:             */
0919:            private void dropTables(Collection tables, SchemaGroup change)
0920:                    throws SQLException {
0921:                if (tables.isEmpty())
0922:                    return;
0923:
0924:                Table table;
0925:                Table changeTable;
0926:                for (Iterator itr = tables.iterator(); itr.hasNext();) {
0927:                    table = (Table) itr.next();
0928:                    if (dropTable(table)) {
0929:                        changeTable = change.findTable(table);
0930:                        if (changeTable != null)
0931:                            changeTable.getSchema().removeTable(changeTable);
0932:                    } else
0933:                        _log.warn(_loc.get("drop-table", table));
0934:                }
0935:            }
0936:
0937:            /**
0938:             * Add the given table to the database schema.
0939:             *
0940:             * @return true if the operation was successful, false otherwise
0941:             */
0942:            public boolean createTable(Table table) throws SQLException {
0943:                return executeSQL(_dict.getCreateTableSQL(table));
0944:            }
0945:
0946:            /**
0947:             * Drop the given table from the database schema.
0948:             *
0949:             * @return true if the operation was successful, false otherwise
0950:             */
0951:            public boolean dropTable(Table table) throws SQLException {
0952:                return executeSQL(_dict.getDropTableSQL(table));
0953:            }
0954:
0955:            /**
0956:             * Add the given sequence to the database schema.
0957:             *
0958:             * @return true if the operation was successful, false otherwise
0959:             */
0960:            public boolean createSequence(Sequence seq) throws SQLException {
0961:                return executeSQL(_dict.getCreateSequenceSQL(seq));
0962:            }
0963:
0964:            /**
0965:             * Drop the given sequence from the database schema.
0966:             *
0967:             * @return true if the operation was successful, false otherwise
0968:             */
0969:            public boolean dropSequence(Sequence seq) throws SQLException {
0970:                return executeSQL(_dict.getDropSequenceSQL(seq));
0971:            }
0972:
0973:            /**
0974:             * Add the given index to the database schema.
0975:             *
0976:             * @return true if the operation was successful, false otherwise
0977:             */
0978:            public boolean createIndex(Index idx, Table table)
0979:                    throws SQLException {
0980:                int max = _dict.maxIndexesPerTable;
0981:
0982:                int len = table.getIndexes().length;
0983:                if (table.getPrimaryKey() != null)
0984:                    len += table.getPrimaryKey().getColumns().length;
0985:
0986:                if (len >= max) {
0987:                    _log.warn(_loc
0988:                            .get("too-many-indexes", idx, table, max + ""));
0989:                    return false;
0990:                }
0991:
0992:                return executeSQL(_dict.getCreateIndexSQL(idx));
0993:            }
0994:
0995:            /**
0996:             * Drop the given index from the database schema.
0997:             *
0998:             * @return true if the operation was successful, false otherwise
0999:             */
1000:            public boolean dropIndex(Index idx) throws SQLException {
1001:                return executeSQL(_dict.getDropIndexSQL(idx));
1002:            }
1003:
1004:            /**
1005:             * Add the given column to the database schema.
1006:             *
1007:             * @return true if the operation was successful, false otherwise
1008:             */
1009:            public boolean addColumn(Column col) throws SQLException {
1010:                return executeSQL(_dict.getAddColumnSQL(col));
1011:            }
1012:
1013:            /**
1014:             * Drop the given column from the database schema.
1015:             *
1016:             * @return true if the operation was successful, false otherwise
1017:             */
1018:            public boolean dropColumn(Column col) throws SQLException {
1019:                return executeSQL(_dict.getDropColumnSQL(col));
1020:            }
1021:
1022:            /**
1023:             * Add the given primary key to the database schema.
1024:             *
1025:             * @return true if the operation was successful, false otherwise
1026:             */
1027:            public boolean addPrimaryKey(PrimaryKey pk) throws SQLException {
1028:                return executeSQL(_dict.getAddPrimaryKeySQL(pk));
1029:            }
1030:
1031:            /**
1032:             * Drop the given primary key from the database schema.
1033:             *
1034:             * @return true if the operation was successful, false otherwise
1035:             */
1036:            public boolean dropPrimaryKey(PrimaryKey pk) throws SQLException {
1037:                return executeSQL(_dict.getDropPrimaryKeySQL(pk));
1038:            }
1039:
1040:            /**
1041:             * Add the given foreign key to the database schema.
1042:             *
1043:             * @return true if the operation was successful, false otherwise
1044:             */
1045:            public boolean addForeignKey(ForeignKey fk) throws SQLException {
1046:                return executeSQL(_dict.getAddForeignKeySQL(fk));
1047:            }
1048:
1049:            /**
1050:             * Drop the given foreign key from the database schema.
1051:             *
1052:             * @return true if the operation was successful, false otherwise
1053:             */
1054:            public boolean dropForeignKey(ForeignKey fk) throws SQLException {
1055:                return executeSQL(_dict.getDropForeignKeySQL(fk));
1056:            }
1057:
1058:            /**
1059:             * Return the database schema.
1060:             */
1061:            public SchemaGroup getDBSchemaGroup() {
1062:                try {
1063:                    return getDBSchemaGroup(true);
1064:                } catch (SQLException se) {
1065:                    throw SQLExceptions.getStore(se, _dict);
1066:                }
1067:            }
1068:
1069:            /**
1070:             * Set the database schema.
1071:             */
1072:            public void setDBSchemaGroup(SchemaGroup db) {
1073:                _db = db;
1074:                if (db != null)
1075:                    _fullDB = true;
1076:            }
1077:
1078:            /**
1079:             * Return the database schema.
1080:             *
1081:             * @param full if false, only the tables named in the set schema
1082:             * repository will be generated
1083:             */
1084:            private SchemaGroup getDBSchemaGroup(boolean full)
1085:                    throws SQLException {
1086:                if (_db == null || (full && !_fullDB)) {
1087:                    SchemaGenerator gen = new SchemaGenerator(_conf);
1088:                    gen.setPrimaryKeys(_pks);
1089:                    gen.setForeignKeys(_fks);
1090:                    gen.setIndexes(_indexes);
1091:                    if (full)
1092:                        gen.generateSchemas();
1093:                    else {
1094:                        // generate only the tables in the given repository
1095:                        // group; some may not exist yet, which is OK; we just need
1096:                        // to make sure we can detect the changes to the ones that
1097:                        // do exist
1098:                        Collection tables = new LinkedList();
1099:                        SchemaGroup group = assertSchemaGroup();
1100:                        Schema[] schemas = group.getSchemas();
1101:                        Table[] tabs;
1102:                        for (int i = 0; i < schemas.length; i++) {
1103:                            tabs = schemas[i].getTables();
1104:                            for (int j = 0; j < tabs.length; j++) {
1105:                                if (tabs[j].getSchemaName() == null)
1106:                                    tables.add("." + tabs[j].getName());
1107:                                else
1108:                                    tables.add(tabs[j].getFullName());
1109:                            }
1110:                        }
1111:                        if (!tables.isEmpty())
1112:                            gen.generateSchemas((String[]) tables
1113:                                    .toArray(new String[tables.size()]));
1114:                    }
1115:                    _db = gen.getSchemaGroup();
1116:                }
1117:                return _db;
1118:            }
1119:
1120:            private SchemaGroup assertSchemaGroup() {
1121:                SchemaGroup local = getSchemaGroup();
1122:                if (local == null)
1123:                    throw new InvalidStateException(_loc.get("tool-norepos"));
1124:                return local;
1125:            }
1126:
1127:            /////////////
1128:            // Utilities
1129:            /////////////
1130:
1131:            /**
1132:             * Executes the given array of non-selecting SQL statements, correctly
1133:             * logging the SQL calls and optionally ignoring errors.
1134:             *
1135:             * @return true if there was SQL to execute and the calls were
1136:             * successful, false otherwise
1137:             */
1138:            private boolean executeSQL(String[] sql) throws SQLException {
1139:                // if no sql, probably b/c dictionary doesn't support operation
1140:                if (sql.length == 0)
1141:                    return false;
1142:
1143:                boolean err = false;
1144:                if (_writer == null) {
1145:                    // this is outside the try-catch because a failure here is
1146:                    // really bad, and should not be ignored.
1147:                    Connection conn = _ds.getConnection();
1148:                    Statement statement = null;
1149:                    boolean wasAuto = true;
1150:                    try {
1151:                        wasAuto = conn.getAutoCommit();
1152:                        if (!wasAuto)
1153:                            conn.setAutoCommit(true);
1154:                        for (int i = 0; i < sql.length; i++) {
1155:                            try {
1156:                                // some connections require that rollback be
1157:                                // called on the connection before any DDL statements
1158:                                // can be run on it, even when autocommit is on.
1159:                                // This is sometimes because the connection does not
1160:                                // allow DDL statements when there are multiple
1161:                                // commands issued on the connection, and the
1162:                                // connection pool may have issued some validation SQL.
1163:                                try {
1164:                                    conn.rollback();
1165:                                } catch (Exception e) {
1166:                                }
1167:
1168:                                statement = conn.createStatement();
1169:                                statement.executeUpdate(sql[i]);
1170:
1171:                                // some connections seem to require an explicit
1172:                                // commit for DDL statements, even when autocommit
1173:                                // is on. The DataDirect drivers seem to suffer from
1174:                                // this limitation.
1175:                                try {
1176:                                    conn.commit();
1177:                                } catch (Exception e) {
1178:                                }
1179:                            } catch (SQLException se) {
1180:                                err = true;
1181:                                handleException(se);
1182:                            } finally {
1183:                                if (statement != null)
1184:                                    try {
1185:                                        statement.close();
1186:                                    } catch (SQLException se) {
1187:                                    }
1188:                            }
1189:                        }
1190:                    } finally {
1191:                        if (!wasAuto)
1192:                            conn.setAutoCommit(false);
1193:                        try {
1194:                            conn.close();
1195:                        } catch (SQLException se) {
1196:                        }
1197:                    }
1198:                } else {
1199:                    for (int i = 0; i < sql.length; i++)
1200:                        _writer.println(sql[i] + ";");
1201:                    _writer.flush();
1202:                }
1203:
1204:                return !err;
1205:            }
1206:
1207:            /**
1208:             * Handle the given exception, logging it and optionally ignoring it,
1209:             * depending on the flags this SchemaTool was created with.
1210:             */
1211:            private void handleException(SQLException sql) throws SQLException {
1212:                if (!_ignoreErrs)
1213:                    throw sql;
1214:                _log.warn(sql.getMessage(), sql);
1215:            }
1216:
1217:            ////////
1218:            // Main
1219:            ////////
1220:
1221:            /**
1222:             * Usage: java org.apache.openjpa.jdbc.schema.SchemaTool [option]*
1223:             * [-action/-a &lt;add | retain | drop | refresh | createDB | dropDB
1224:             * | build | reflect | import | export&gt;]
1225:             * &lt;.schema file or resource&gt;*
1226:             *  Where the following options are recognized.
1227:             * <ul>
1228:             * <li><i>-properties/-p &lt;properties file or resource&gt;</i>: The
1229:             * path or resource name of a OpenJPA properties file containing
1230:             * information such as the license key	and connection data as
1231:             * outlined in {@link JDBCConfiguration}. Optional.</li>
1232:             * <li><i>-&lt;property name&gt; &lt;property value&gt;</i>: All bean
1233:             * properties of the OpenJPA {@link JDBCConfiguration} can be set by
1234:             * using their	names and supplying a value. For example:
1235:             * <code>-licenseKey adslfja83r3lkadf</code></li>
1236:             * <li><i>-ignoreErrors/-i &lt;true/t | false/f&gt;</i>: If false, an
1237:             * exception will will be thrown if the tool encounters any database
1238:             * exceptions; defaults to <code>false</code>.</li>
1239:             * <li><i>-file/-f &lt;stdout | output file or resource&gt;</i>: Use this
1240:             * option to write a SQL script for the planned schema modifications,
1241:             * rather than committing them to the database. This option also
1242:             * applies to the <code>export</code> and <code>reflect</code> actions.</li>
1243:             * <li><i>-openjpaTables/-kt &lt;true/t | false/f&gt;</i>: Under the
1244:             * <code>reflect</code> action, whether to reflect on tables with
1245:             * the name <code>OPENJPA_*</code>. Under other actions, whether to
1246:             * drop such tables. Defaults to <code>false</code>.</li>
1247:             * <li><i>-dropTables/-dt &lt;true/t | false/f&gt;</i>: Set this option to
1248:             * true to drop tables that appear to be unused during
1249:             * <code>retain</code>	and <code>refresh</code> actions. Defaults to
1250:             * <code>true</code>.</li>
1251:             * <li><i>-dropSequences/-dsq &lt;true/t | false/f&gt;</i>: Set this option
1252:             * to true to drop sequences that appear to be unused during
1253:             * <code>retain</code>	and <code>refresh</code> actions. Defaults to
1254:             * <code>true</code>.</li>
1255:             * <li><i>-primaryKeys/-pk &lt;true/t | false/f&gt;</i>: Whether primary
1256:             * keys on existing tables are manipulated. Defaults to true.</li>
1257:             * <li><i>-foreignKeys/-fk &lt;true/t | false/f&gt;</i>: Whether foreign
1258:             * keys on existing tables are manipulated. Defaults to true.</li>
1259:             * <li><i>-indexes/-ix &lt;true/t | false/f&gt;</i>: Whether indexes
1260:             * on existing tables are manipulated. Defaults to true.</li>
1261:             * <li><i>-sequences/-sq &lt;true/t | false/f&gt;</i>: Whether to
1262:             * manipulate sequences. Defaults to true.</li>
1263:             * <li><i>-record/-r &lt;true/t | false/f&gt;</i>: Set this option to
1264:             * <code>false</code> to prevent writing the schema changes to the
1265:             * current {@link SchemaFactory}.</li>
1266:             * </ul>
1267:             *  Actions can be composed in a comma-separated list. The various actions 
1268:             *  are as follows.
1269:             * <ul>
1270:             * <li><i>add</i>: Bring the schema up-to-date with the latest
1271:             * changes to the schema XML data by adding tables, columns,
1272:             * indexes, etc. This action never drops any data. This is the
1273:             * default action.</li>
1274:             * <li><i>retain</i>: Keep all schema components in the schema XML, but
1275:             * drop the rest from the database. This action never adds any data.</li>
1276:             * <li><i>drop</i>: Drop all the schema components in the schema XML.</li>
1277:             * <li><i>refresh</i>: Equivalent to retain, then add.</li>
1278:             * <li><i>createDB</i>: Execute SQL to re-create the current database.
1279:             * This action is typically used in conjuction with the
1280:             * <code>file</code> option.</li>
1281:             * <li><i>build</i>: Execute SQL to build the schema defined in the XML.
1282:             * Because it doesn't take the current database schema into account,
1283:             * this action is typically used in conjuction with the
1284:             * <code>file</code> option.</li>
1285:             * <li><i>reflect</i>: Reflect on the current database schema. Write the
1286:             * schema's XML representation to the file specified with the
1287:             * <code>file</code> option, or to stdout if no file is given.</li>
1288:             * <li><i>dropDB</i>: Execute SQL to drop the current database. This
1289:             * action implies <code>dropTables</code>.</li>
1290:             * <li><i>deleteTableContents</i>: Execute SQL to delete all rows from 
1291:             * all tables that OpenJPA knows about.</li>
1292:             * <li><i>import</i>: Import the given XML schema definition into the
1293:             * current {@link SchemaFactory}.</li>
1294:             * <li><i>export</i>: Export the current {@link SchemaFactory}'s recorded
1295:             * schema to an XML schema definition file.</li>
1296:             * </ul>
1297:             *  Examples:
1298:             * <ul>
1299:             * <li>Write a script to stdout to re-create the current database
1300:             * schema:<br />
1301:             * <code>java org.apache.openjpa.jdbc.schema.SchemaTool -f stdout 
1302:             * -a createDB</code></li>
1303:             * <li>Drop the current database schema:<br />
1304:             * <code>java org.apache.openjpa.jdbc.schema.SchemaTool 
1305:             * -a dropDB</code></li>
1306:             * <li>Refresh the schema and delete all records in all tables:<br />
1307:             * <code>java org.apache.openjpa.jdbc.schema.SchemaTool 
1308:             * -a refresh,deleteTableContents</code></li>
1309:             * <li>Create a schema based on an XML schema definition file:<br />
1310:             * <code>java org.apache.openjpa.jdbc.schema.SchemaTool 
1311:             * myschema.xml</code></li>
1312:             * </ul>
1313:             */
1314:            public static void main(String[] args) throws IOException,
1315:                    SQLException {
1316:                Options opts = new Options();
1317:                final String[] arguments = opts.setFromCmdLine(args);
1318:                boolean ret = Configurations.runAgainstAllAnchors(opts,
1319:                        new Configurations.Runnable() {
1320:                            public boolean run(Options opts) throws Exception {
1321:                                JDBCConfiguration conf = new JDBCConfigurationImpl();
1322:                                try {
1323:                                    return SchemaTool
1324:                                            .run(conf, arguments, opts);
1325:                                } finally {
1326:                                    conf.close();
1327:                                }
1328:                            }
1329:                        });
1330:                if (!ret)
1331:                    System.out.println(_loc.get("tool-usage"));
1332:            }
1333:
1334:            /**
1335:             * Run the tool. Returns false if any invalid options were given.
1336:             *
1337:             * @see #main
1338:             */
1339:            public static boolean run(JDBCConfiguration conf, String[] args,
1340:                    Options opts) throws IOException, SQLException {
1341:                Flags flags = new Flags();
1342:                flags.dropTables = opts.removeBooleanProperty("dropTables",
1343:                        "dt", flags.dropTables);
1344:                flags.dropSequences = opts.removeBooleanProperty(
1345:                        "dropSequences", "dsq", flags.dropSequences);
1346:                flags.ignoreErrors = opts.removeBooleanProperty("ignoreErrors",
1347:                        "i", flags.ignoreErrors);
1348:                flags.openjpaTables = opts.removeBooleanProperty(
1349:                        "openjpaTables", "ot", flags.openjpaTables);
1350:                flags.primaryKeys = opts.removeBooleanProperty("primaryKeys",
1351:                        "pk", flags.primaryKeys);
1352:                flags.foreignKeys = opts.removeBooleanProperty("foreignKeys",
1353:                        "fks", flags.foreignKeys);
1354:                flags.indexes = opts.removeBooleanProperty("indexes", "ix",
1355:                        flags.indexes);
1356:                flags.sequences = opts.removeBooleanProperty("sequences", "sq",
1357:                        flags.sequences);
1358:                flags.record = opts.removeBooleanProperty("record", "r",
1359:                        flags.record);
1360:                String fileName = opts.removeProperty("file", "f", null);
1361:                String schemas = opts.removeProperty("s");
1362:                if (schemas != null)
1363:                    opts.setProperty("schemas", schemas);
1364:
1365:                String[] actions = opts.removeProperty("action", "a",
1366:                        flags.action).split(",");
1367:
1368:                // setup a configuration instance with cmd-line info
1369:                Configurations.populateConfiguration(conf, opts);
1370:
1371:                // create script writer
1372:                ClassLoader loader = conf.getClassResolverInstance()
1373:                        .getClassLoader(SchemaTool.class, null);
1374:                flags.writer = Files.getWriter(fileName, loader);
1375:
1376:                boolean returnValue = true;
1377:                for (int i = 0; i < actions.length; i++) {
1378:                    flags.action = actions[i];
1379:                    returnValue &= run(conf, args, flags, loader);
1380:                }
1381:
1382:                return returnValue;
1383:            }
1384:
1385:            /**
1386:             * Run the tool. Return false if invalid options were given.
1387:             */
1388:            public static boolean run(JDBCConfiguration conf, String[] args,
1389:                    Flags flags, ClassLoader loader) throws IOException,
1390:                    SQLException {
1391:                Log log = conf.getLog(OpenJPAConfiguration.LOG_TOOL);
1392:                if (ACTION_REFLECT.equals(flags.action)) {
1393:                    if (args.length > 0)
1394:                        return false;
1395:                    if (flags.writer == null)
1396:                        flags.writer = new PrintWriter(System.out);
1397:
1398:                    SchemaGenerator gen = new SchemaGenerator(conf);
1399:                    gen.setPrimaryKeys(flags.primaryKeys);
1400:                    gen.setIndexes(flags.indexes);
1401:                    gen.setForeignKeys(flags.foreignKeys);
1402:                    gen.setSequences(flags.sequences);
1403:                    gen.setOpenJPATables(flags.openjpaTables);
1404:
1405:                    String schemas = conf.getSchemas();
1406:                    if (StringUtils.isEmpty(schemas))
1407:                        schemas = "all";
1408:                    log.info(_loc.get("sch-reflect", schemas));
1409:                    gen.generateSchemas();
1410:
1411:                    // record the schema
1412:                    log.info(_loc.get("sch-reflect-write"));
1413:                    SchemaSerializer ser = new XMLSchemaSerializer(conf);
1414:                    ser.addAll(gen.getSchemaGroup());
1415:                    ser.serialize(flags.writer, ser.PRETTY);
1416:                    return true;
1417:                }
1418:
1419:                if (args.length == 0 && !ACTION_CREATEDB.equals(flags.action)
1420:                        && !ACTION_DROPDB.equals(flags.action)
1421:                        && !ACTION_EXPORT.equals(flags.action)
1422:                        && !ACTION_DELETE_TABLE_CONTENTS.equals(flags.action))
1423:                    return false;
1424:
1425:                // parse in the arguments
1426:                SchemaParser parser = new XMLSchemaParser(conf);
1427:                parser.setDelayConstraintResolve(true);
1428:                File file;
1429:                for (int i = 0; i < args.length; i++) {
1430:                    file = Files.getFile(args[i], loader);
1431:                    log.info(_loc.get("tool-running", file));
1432:                    parser.parse(file);
1433:                }
1434:                parser.resolveConstraints();
1435:
1436:                if (ACTION_IMPORT.equals(flags.action)) {
1437:                    log.info(_loc.get("tool-import-store"));
1438:                    SchemaGroup schema = parser.getSchemaGroup();
1439:                    conf.getSchemaFactoryInstance().storeSchema(schema);
1440:                    return true;
1441:                }
1442:                if (ACTION_EXPORT.equals(flags.action)) {
1443:                    if (flags.writer == null)
1444:                        flags.writer = new PrintWriter(System.out);
1445:
1446:                    log.info(_loc.get("tool-export-gen"));
1447:                    SchemaGroup schema = conf.getSchemaFactoryInstance()
1448:                            .readSchema();
1449:
1450:                    log.info(_loc.get("tool-export-write"));
1451:                    SchemaSerializer ser = new XMLSchemaSerializer(conf);
1452:                    ser.addAll(schema);
1453:                    ser.serialize(flags.writer, ser.PRETTY);
1454:                    return true;
1455:                }
1456:
1457:                SchemaTool tool = new SchemaTool(conf, flags.action);
1458:                tool.setIgnoreErrors(flags.ignoreErrors);
1459:                tool.setDropTables(flags.dropTables);
1460:                tool.setSequences(flags.sequences); // set before dropseqs
1461:                tool.setDropSequences(flags.dropSequences);
1462:                tool.setPrimaryKeys(flags.primaryKeys);
1463:                tool.setForeignKeys(flags.foreignKeys);
1464:                tool.setIndexes(flags.indexes);
1465:                tool.setOpenJPATables(flags.openjpaTables);
1466:                if (args.length > 0)
1467:                    tool.setSchemaGroup(parser.getSchemaGroup());
1468:                if (flags.writer != null)
1469:                    tool.setWriter(flags.writer);
1470:
1471:                log.info(_loc.get("tool-action", flags.action));
1472:                try {
1473:                    tool.run();
1474:                } finally {
1475:                    if (flags.record) {
1476:                        log.info(_loc.get("tool-record"));
1477:                        tool.record();
1478:                    }
1479:                }
1480:                if (flags.writer != null)
1481:                    flags.writer.flush();
1482:
1483:                return true;
1484:            }
1485:
1486:            /**
1487:             * Run flags.
1488:             */
1489:            public static class Flags {
1490:
1491:                public String action = ACTION_ADD;
1492:                public Writer writer = null;
1493:                public boolean dropTables = true;
1494:                public boolean dropSequences = true;
1495:                public boolean ignoreErrors = false;
1496:                public boolean openjpaTables = false;
1497:                public boolean primaryKeys = true;
1498:                public boolean foreignKeys = true;
1499:                public boolean indexes = true;
1500:                public boolean sequences = true;
1501:                public boolean record = true;
1502:            }
1503:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.