001: /*
002: * JBoss, Home of Professional Open Source
003: * Copyright 2005, JBoss Inc., and individual contributors as indicated
004: * by the @authors tag. See the copyright.txt in the distribution for a
005: * full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jbpm.identity.hibernate;
023:
024: import java.io.*;
025: import java.lang.reflect.*;
026: import java.sql.*;
027: import java.util.*;
028: import java.util.List;
029:
030: import org.apache.commons.logging.*;
031: import org.hibernate.cfg.*;
032: import org.hibernate.connection.*;
033: import org.hibernate.dialect.*;
034: import org.hibernate.engine.*;
035: import org.hibernate.mapping.*;
036: import org.hibernate.tool.hbm2ddl.*;
037: import org.hibernate.util.*;
038:
039: public class IdentitySchema {
040:
041: private static final String IDENTITY_TABLE_PREFIX = "JBPM_ID_";
042:
043: Configuration configuration = null;
044: Properties properties = null;
045: Dialect dialect = null;
046: Mapping mapping = null;
047: String[] createSql = null;
048: String[] dropSql = null;
049: String[] cleanSql = null;
050:
051: ConnectionProvider connectionProvider = null;
052: Connection connection = null;
053: Statement statement = null;
054:
055: public IdentitySchema(Configuration configuration) {
056: this .configuration = configuration;
057: this .properties = configuration.getProperties();
058: this .dialect = Dialect.getDialect(properties);
059: try {
060: // get the mapping field via reflection :-(
061: Field mappingField = Configuration.class
062: .getDeclaredField("mapping");
063: mappingField.setAccessible(true);
064: this .mapping = (Mapping) mappingField.get(configuration);
065: } catch (Exception e) {
066: throw new RuntimeException(
067: "couldn't get the hibernate mapping", e);
068: }
069: }
070:
071: // scripts lazy initializations /////////////////////////////////////////////
072:
073: public String[] getCreateSql() {
074: if (createSql == null) {
075: createSql = configuration
076: .generateSchemaCreationScript(dialect);
077: }
078: return createSql;
079: }
080:
081: public String[] getDropSql() {
082: if (dropSql == null) {
083: dropSql = configuration.generateDropSchemaScript(dialect);
084: }
085: return dropSql;
086: }
087:
088: public String[] getCleanSql() {
089: if (cleanSql == null) {
090: // loop over all foreign key constraints
091: List dropForeignKeysSql = new ArrayList();
092: List createForeignKeysSql = new ArrayList();
093: Iterator iter = configuration.getTableMappings();
094: while (iter.hasNext()) {
095: Table table = (Table) iter.next();
096: if (table.isPhysicalTable()) {
097: Iterator subIter = table.getForeignKeyIterator();
098: while (subIter.hasNext()) {
099: ForeignKey fk = (ForeignKey) subIter.next();
100: if (fk.isPhysicalConstraint()) {
101: // collect the drop key constraint
102: dropForeignKeysSql
103: .add(fk
104: .sqlDropString(
105: dialect,
106: properties
107: .getProperty(Environment.DEFAULT_CATALOG),
108: properties
109: .getProperty(Environment.DEFAULT_SCHEMA)));
110: createForeignKeysSql
111: .add(fk
112: .sqlCreateString(
113: dialect,
114: mapping,
115: properties
116: .getProperty(Environment.DEFAULT_CATALOG),
117: properties
118: .getProperty(Environment.DEFAULT_SCHEMA)));
119: }
120: }
121: }
122: }
123:
124: List deleteSql = new ArrayList();
125: iter = configuration.getTableMappings();
126: while (iter.hasNext()) {
127: Table table = (Table) iter.next();
128: deleteSql.add("delete from " + table.getName());
129: }
130:
131: List cleanSqlList = new ArrayList();
132: cleanSqlList.addAll(dropForeignKeysSql);
133: cleanSqlList.addAll(deleteSql);
134: cleanSqlList.addAll(createForeignKeysSql);
135:
136: cleanSql = (String[]) cleanSqlList
137: .toArray(new String[cleanSqlList.size()]);
138: }
139: return cleanSql;
140: }
141:
142: // runtime table detection //////////////////////////////////////////////////
143:
144: public boolean hasIdentityTables() {
145: return (getIdentityTables().size() > 0);
146: }
147:
148: public List getIdentityTables() {
149: // delete all the data in the jbpm tables
150: List jbpmTableNames = new ArrayList();
151: try {
152: createConnection();
153: ResultSet resultSet = connection.getMetaData().getTables(
154: "", "", null, null);
155: while (resultSet.next()) {
156: String tableName = resultSet.getString("TABLE_NAME");
157: if ((tableName != null)
158: && (tableName.length() > 5)
159: && (IDENTITY_TABLE_PREFIX
160: .equalsIgnoreCase(tableName.substring(
161: 0, 5)))) {
162: jbpmTableNames.add(tableName);
163: }
164: }
165: } catch (SQLException e) {
166: throw new RuntimeException(
167: "couldn't get the jbpm table names");
168: } finally {
169: closeConnection();
170: }
171: return jbpmTableNames;
172: }
173:
174: // script execution methods /////////////////////////////////////////////////
175:
176: public void dropSchema() {
177: execute(getDropSql());
178: }
179:
180: public void createSchema() {
181: execute(getCreateSql());
182: }
183:
184: public void cleanSchema() {
185: execute(getCleanSql());
186: }
187:
188: public void saveSqlScripts(String dir, String prefix) {
189: try {
190: new File(dir).mkdirs();
191: saveSqlScript(dir + "/" + prefix + ".drop.sql",
192: getDropSql());
193: saveSqlScript(dir + "/" + prefix + ".create.sql",
194: getCreateSql());
195: saveSqlScript(dir + "/" + prefix + ".clean.sql",
196: getCleanSql());
197: new SchemaExport(configuration).setDelimiter(
198: getSqlDelimiter()).setOutputFile(
199: dir + "/" + prefix + ".drop.create.sql").create(
200: true, false);
201: } catch (Exception e) {
202: throw new RuntimeException("couldn't generate scripts", e);
203: }
204: }
205:
206: // main /////////////////////////////////////////////////////////////////////
207:
208: public static void main(String[] args) {
209: try {
210: if ((args != null) && (args.length == 1)
211: && ("create".equalsIgnoreCase(args[0]))) {
212: new IdentitySchema(IdentitySessionFactory
213: .createConfiguration()).createSchema();
214: } else if ((args != null) && (args.length == 1)
215: && ("drop".equalsIgnoreCase(args[0]))) {
216: new IdentitySchema(IdentitySessionFactory
217: .createConfiguration()).dropSchema();
218: } else if ((args != null) && (args.length == 1)
219: && ("clean".equalsIgnoreCase(args[0]))) {
220: new IdentitySchema(IdentitySessionFactory
221: .createConfiguration()).cleanSchema();
222: } else if ((args != null) && (args.length == 3)
223: && ("scripts".equalsIgnoreCase(args[0]))) {
224: new IdentitySchema(IdentitySessionFactory
225: .createConfiguration()).saveSqlScripts(args[1],
226: args[2]);
227: } else {
228: System.err.println("syntax: JbpmSchema create");
229: System.err.println("syntax: JbpmSchema drop");
230: System.err.println("syntax: JbpmSchema clean");
231: System.err
232: .println("syntax: JbpmSchema scripts <dir> <prefix>");
233: }
234: } catch (Exception e) {
235: e.printStackTrace();
236: throw new RuntimeException(e);
237: }
238: }
239:
240: private void saveSqlScript(String fileName, String[] sql)
241: throws FileNotFoundException {
242: FileOutputStream fileOutputStream = new FileOutputStream(
243: fileName);
244: PrintStream printStream = new PrintStream(fileOutputStream);
245: for (int i = 0; i < sql.length; i++) {
246: printStream.println(sql[i] + getSqlDelimiter());
247: }
248: }
249:
250: // sql script execution /////////////////////////////////////////////////////
251:
252: public void execute(String[] sqls) {
253: String sql = null;
254: String showSqlText = properties
255: .getProperty("hibernate.show_sql");
256: boolean showSql = ("true".equalsIgnoreCase(showSqlText));
257:
258: try {
259: createConnection();
260: statement = connection.createStatement();
261:
262: for (int i = 0; i < sqls.length; i++) {
263: sql = sqls[i];
264: String delimitedSql = sql + getSqlDelimiter();
265:
266: if (showSql)
267: log.debug(delimitedSql);
268: statement.executeUpdate(delimitedSql);
269: }
270:
271: } catch (SQLException e) {
272: e.printStackTrace();
273: throw new RuntimeException("couldn't execute sql '" + sql
274: + "'", e);
275: } finally {
276: closeConnection();
277: }
278: }
279:
280: private void closeConnection() {
281: try {
282: if (statement != null)
283: statement.close();
284: if (connection != null) {
285: JDBCExceptionReporter.logWarnings(connection
286: .getWarnings());
287: connection.clearWarnings();
288: connectionProvider.closeConnection(connection);
289: connectionProvider.close();
290: }
291: } catch (Exception e) {
292: System.err.println("Could not close connection");
293: e.printStackTrace();
294: }
295: }
296:
297: private void createConnection() throws SQLException {
298: connectionProvider = ConnectionProviderFactory
299: .newConnectionProvider(properties);
300: connection = connectionProvider.getConnection();
301: if (!connection.getAutoCommit()) {
302: connection.commit();
303: connection.setAutoCommit(true);
304: }
305: }
306:
307: public Properties getProperties() {
308: return properties;
309: }
310:
311: // sql delimiter ////////////////////////////////////////////////////////////
312:
313: private static String sqlDelimiter = null;
314:
315: private synchronized String getSqlDelimiter() {
316: if (sqlDelimiter == null) {
317: sqlDelimiter = properties.getProperty("jbpm.sql.delimiter",
318: ";");
319: }
320: return sqlDelimiter;
321: }
322:
323: // logger ///////////////////////////////////////////////////////////////////
324:
325: private static final Log log = LogFactory
326: .getLog(IdentitySchema.class);
327: }
|