/* * Copyright 2013 The Skfiy Open Association. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package org.skfiy.typhon.deploy; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.skfiy.typhon.ConnectionProvider; import org.skfiy.typhon.Constants; import org.skfiy.typhon.Lifecycle; import org.skfiy.typhon.LifecycleEvent; import org.skfiy.typhon.LifecycleListener; import org.skfiy.typhon.TyphonException; import org.skfiy.typhon.Typhons; import org.skfiy.typhon.Version; import org.skfiy.typhon.database.DatabaseSchema; import org.skfiy.typhon.database.SimpleConnectionProvider; import org.skfiy.typhon.util.DbUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author Kevin Zou <kevinz@skfiy.org> */ public class DatabaseDeployListener implements LifecycleListener { private static final Logger LOG = LoggerFactory.getLogger(DatabaseDeployListener.class); @Override public void execute(LifecycleEvent event) { // if (!Typhons.getBoolean(Constants.AUTO_UPGRADE_DATABASE)) { // LOG.debug("No enabled auto upgrade database."); // return; // } if (Lifecycle.START_EVENT.equals(event.getEvent())) { // 部署数据库 SimpleConnectionProvider scp = new SimpleConnectionProvider(); scp.init(); Version dbVersion = findVersion(scp); if (dbVersion == null) { dbVersion = new Version(0, 0, 0, null); saveVersion(scp, dbVersion); } int ct = Version.currentVersion().compareTo(dbVersion); // update database schema if (ct > 0) { upgrade(scp, dbVersion); } scp.destroy(); } } private void upgrade(ConnectionProvider connectionProvider, Version dbVersion) { DatabaseSchema dbSchema = new DatabaseSchema(); Connection conn = null; try { conn = connectionProvider.getConnection(); } catch (SQLException ex) { throw new TyphonException(ex); } for (Upgrade upg : loadUpgrades()) { // 当前升级脚本的版本号,大于当前应用版本号 if (upg.getVersion().compareTo(Version.currentVersion()) > 0) { break; } // 当前升级脚本的版本号与小于等于数据库版本号时 if (upg.getVersion().compareTo(dbVersion) <= 0) { continue; } for (File sqlFile : upg.getSqlFiles()) { InputStream in = null; try { in = new FileInputStream(sqlFile); dbSchema.executeSQLScript(conn, in); } catch (SQLException | IOException ex) { LOG.error(sqlFile.getAbsolutePath(), ex); DbUtils.rollbackQuietly(conn); throw new TyphonException(ex); } finally { if (in != null) { try { in.close(); } catch (IOException ex) { // nothing } } } } } DbUtils.commitAndCloseQuietly(conn); // 更新数据库版本号 updateVersion(connectionProvider, Version.currentVersion()); } private List<Upgrade> loadUpgrades() { File upgradeDir = new File(Typhons.getProperty(Constants.DATABASE_SCRIPTS_DIR), "upgrade"); File[] subDirs = upgradeDir.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { return pathname.isDirectory(); } }); List<Upgrade> upgrades = new ArrayList<>(); for (File subDir : subDirs) { upgrades.add(new Upgrade(subDir)); } Collections.sort(upgrades); return upgrades; } private void saveVersion(ConnectionProvider connectionProvider, Version version) { Connection conn = null; PreparedStatement ps = null; try { conn = connectionProvider.getConnection(); ps = conn.prepareStatement("insert into version(major,minor,incremental,qualifier) values(?,?,?,?)"); int i = 1; ps.setInt(i++, version.getMajor()); ps.setInt(i++, version.getMinor()); ps.setInt(i++, version.getIncremental()); ps.setString(i++, version.getQualifier()); if (ps.executeUpdate() <= 0) { throw new SQLException("没有数据被更新"); } } catch (SQLException e) { LOG.error("如果数据库没有版本记录,添加最低版本", e); throw new TyphonException("添加最低版本号失败", e); } finally { DbUtils.closeQuietly(ps); DbUtils.commitAndCloseQuietly(conn); } } private void updateVersion(ConnectionProvider connectionProvider, Version version) { Connection conn = null; PreparedStatement ps = null; try { conn = connectionProvider.getConnection(); ps = conn.prepareStatement("update version set major=?,minor=?,incremental=?,qualifier=?"); ps.setInt(1, version.getMajor()); ps.setInt(2, version.getMinor()); ps.setInt(3, version.getIncremental()); ps.setString(4, version.getQualifier()); if (ps.executeUpdate() <= 0) { throw new SQLException("没有数据被更新"); } } catch (SQLException ex) { LOG.error("更新数据库Version失败", ex); throw new TyphonException("更新数据库Version失败", ex); } finally { DbUtils.closeQuietly(ps); DbUtils.commitAndCloseQuietly(conn); } } private Version findVersion(ConnectionProvider connectionProvider) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; Version version = null; try { conn = connectionProvider.getConnection(); ps = conn.prepareStatement("select major,minor,incremental,qualifier from version"); rs = ps.executeQuery(); if (rs.next()) { version = new Version(rs.getInt("major"), rs.getInt("minor"), rs.getInt("incremental"), rs.getString("qualifier")); } } catch (SQLException ex) { LOG.error("查询数据库Version失败", ex); throw new TyphonException("查询数据库Version失败", ex); } finally { DbUtils.closeQuietly(conn, ps, rs); } return version; } }