package org.jblooming.persistence.hibernate; import org.jblooming.scheduler.Executable; import org.jblooming.scheduler.JobLogData; import org.jblooming.tracer.Tracer; import org.jblooming.waf.constants.Fields; import org.jblooming.waf.settings.ApplicationState; import org.jblooming.waf.settings.PersistenceConfiguration; import org.jblooming.PlatformRuntimeException; import org.jblooming.utilities.JSP; import org.jblooming.utilities.StringUtilities; import org.hibernate.mapping.Column; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.MySQLDialect; import java.util.List; import java.util.ArrayList; import java.sql.*; /** * (c) Open Lab - www.open-lab.com * Date: Jul 17, 2008 * Time: 2:36:12 PM * <p/> * To force release launch, put "SETUP_DB_DONE_"+releaseLabel = no in global settings */ public class Release { public boolean needsToBeLaunched; public List<String> beforeHibSql = new ArrayList(); public List<String> postHibSql = new ArrayList(); public List<Executable> execs = new ArrayList(); public List<PropertyWithDefault> pwds = new ArrayList(); public String releaseLabel; public Release(String releaseLabel) { this.releaseLabel = releaseLabel; PlatformSchemaUpdater.releases.add(this); } public PropertyWithDefault addPropertyToCheck(Class clazz, String propertyName, Object defaultValue) { PropertyWithDefault pwd = new PropertyWithDefault(); pwd.clazz = clazz; pwd.propertyName = propertyName; pwd.defaultValue = defaultValue; pwds.add(pwd); return pwd; } public PropertyWithDefault getProperty(Class clazz, String propertyName) { for (PropertyWithDefault propertyWithDefault : pwds) { if (propertyName.equalsIgnoreCase(propertyWithDefault.propertyName) && clazz.equals(propertyWithDefault.clazz)) return propertyWithDefault; } return null; } public void verifyIfUpdateNeeded() { Connection conn = null; try { conn = PersistenceContext.getNewConnection(); conn.setAutoCommit(false); ResultSet ps = null; PreparedStatement pst = null; for (PropertyWithDefault propertyWithDefault : pwds) { try { String tableName = HibernateUtilities.getTableName(propertyWithDefault.clazz); propertyWithDefault.table = tableName; //get column name Column c = HibernateUtilities.getColumn(propertyWithDefault.clazz, propertyWithDefault.propertyName); if (c != null) { propertyWithDefault.column = c.getName(); String sql = "select * from " + tableName; try { Dialect d = (Dialect) PersistenceConfiguration.getDefaultPersistenceConfiguration().dialect.newInstance(); if (d.supportsLimit()) { // MySQLDialect doesn't support next method until MySQL fix Connector/J bug //if (MySQLDialect.class.getName().equals(d.getClass().getName())) { if (d instanceof MySQLDialect) { sql = "select * from " + tableName + " LIMIT 1"; } else { sql = d.getLimitString("select * from " + tableName, 0, 1); } } } catch (Throwable e) { Tracer.platformLogger.error(e); } pst = conn.prepareStatement(sql); int count = StringUtilities.count(sql, '?'); if (count == 1) // if there is a limit string there is also a parameter to set pst.setInt(1, 1); else if (count == 2) { pst.setInt(1, 0); pst.setInt(2, 1); } ps = pst.executeQuery(); ResultSetMetaData metaData = ps.getMetaData(); int cc = metaData.getColumnCount(); boolean existsColumn = false; for (int i = 1; i <= cc; i++) { String columnName = metaData.getColumnName(i); if (c.getName().equalsIgnoreCase(columnName)) { existsColumn = true; break; } } propertyWithDefault.needsToBeUpdated = !existsColumn; if (!needsToBeLaunched) needsToBeLaunched = !existsColumn; ps.close(); pst.close(); conn.commit(); } } catch (SQLException e) { //beautiful hack to cover cases where table itself is missing propertyWithDefault.needsToBeUpdated = true; needsToBeLaunched = true; throw new Exception(e); } catch (Throwable e) { if (ps != null) try { ps.close(); pst.close(); } catch (SQLException e1) { Tracer.platformLogger.warn(e1); } //may fail as schema does not exist //throw new PlatformRuntimeException(e); Tracer.platformLogger.warn("propertyWithDefault.column: " + propertyWithDefault.column, e); } } conn.close(); } catch (Exception e) { try { if (conn != null && !conn.isClosed()) conn.close(); } catch (SQLException e1) { Tracer.platformLogger.warn(e1); } Tracer.platformLogger.warn(e); } if (!needsToBeLaunched) needsToBeLaunched = Fields.FALSE.equals(ApplicationState.applicationSettings.get("SETUP_DB_DONE_" + releaseLabel)); } public void schemaRefinementBeforeHibernateFactory() { PersistenceContext pc = null; try { pc = new PersistenceContext(); Connection conn = pc.session.connection(); for (String sql : beforeHibSql) { PreparedStatement ps = null; try { Tracer.platformLogger.debug("beforeHibSql:" + sql); ps = conn.prepareStatement(sql); ps.execute(); ps.close(); } catch (Throwable e) { if (ps != null) try { ps.close(); } catch (Throwable e1) { Tracer.platformLogger.warn(e); } Tracer.platformLogger.warn(e); } } pc.commitAndClose(); } catch (Exception e) { if (pc != null) pc.rollbackAndClose(); Tracer.platformLogger.warn(e); } } public void propertyFillAfterHibernateFactory() { PersistenceContext pc = null; try { pc = new PersistenceContext(); Connection conn = pc.session.connection(); for (PropertyWithDefault propertyWithDefault : pwds) { if (propertyWithDefault.needsToBeUpdated) { if (propertyWithDefault.defaultValue != null) { PreparedStatement ps = null; try { String sql = "update " + propertyWithDefault.table + " set " + propertyWithDefault.column + " = ?"; ps = conn.prepareStatement(sql); ps.setObject(1, propertyWithDefault.defaultValue); Tracer.platformLogger.debug("defaultValue:" + sql); ps.execute(); } catch (Throwable e) { Tracer.platformLogger.error(e); } finally { if (ps != null) ps.close(); } } } } pc.commitAndClose(); } catch (Throwable e) { if (pc != null) pc.rollbackAndClose(); Tracer.platformLogger.error("Update to release " + releaseLabel + " failed."); throw new PlatformRuntimeException(e); } } public void schemaRefinementAfterHibernateFactory() { PersistenceContext pc = null; try { pc = new PersistenceContext(); Connection conn = pc.session.connection(); for (Executable exe : execs) { try { JobLogData log = new JobLogData(); Tracer.platformLogger.debug("exe:" + exe); exe.run(log); pc.checkPoint(); if (log.notes != null && log.notes.length() > 0) Tracer.platformLogger.info(log.notes); } catch (Throwable e) { Tracer.platformLogger.error(e); } } for (String sql : postHibSql) { PreparedStatement ps = null; try { ps = conn.prepareStatement(sql); Tracer.platformLogger.debug("postSql:" + sql); ps.execute(); ps.close(); pc.checkPoint(); } catch (Throwable t) { if (ps != null) ps.close(); if (t.getMessage() == null || !t.getMessage().toLowerCase().contains("column not found")) Tracer.platformLogger.error(t); } } pc.commitAndClose(); if (Fields.FALSE.equals(ApplicationState.applicationSettings.get("SETUP_DB_DONE_" + releaseLabel))) ApplicationState.applicationSettings.put("SETUP_DB_DONE_" + releaseLabel, Fields.TRUE); Tracer.platformLogger.debug("Update to release " + releaseLabel + " succeeded."); } catch (Throwable e) { if (pc != null) pc.rollbackAndClose(); Tracer.platformLogger.error("Update to release " + releaseLabel + " failed."); throw new PlatformRuntimeException(e); } } }