/* * $Id$ * * Authors: * Jeff Buchbinder <jeff@freemedsoftware.org> * * REMITT Electronic Medical Information Translation and Transmission * Copyright (C) 1999-2014 FreeMED Software Foundation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.remitt.datastore; import java.io.File; import java.io.FileNotFoundException; import java.io.FilenameFilter; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Arrays; import java.util.Scanner; import org.apache.commons.io.FilenameUtils; import org.apache.log4j.Logger; import org.remitt.server.Configuration; import org.remitt.server.DbUtil; public class DbPatch { static final Logger log = Logger.getLogger(DbPatch.class); /** * Attempt to run a database patch. * * @param patchFilename * @return Success. */ public static boolean applyPatch(String patchFilename) { Connection c = Configuration.getConnection(); String patch = null; Scanner scanner; try { scanner = new Scanner(new File(patchFilename)).useDelimiter("\\Z"); patch = scanner.next(); scanner.close(); } catch (FileNotFoundException ex) { log.error(ex); return false; } PreparedStatement cStmt = null; boolean status = false; try { log.debug("Using patch length = " + patch.length()); cStmt = c.prepareStatement(patch); cStmt.execute(); log.info("Patch succeeded"); status = true; } catch (NullPointerException npe) { log.error("Caught NullPointerException", npe); } catch (Throwable e) { log.error(e.toString()); } finally { DbUtil.closeSafely(cStmt); DbUtil.closeSafely(c); } return status; } /** * Determine if a patch has been applied yet. * * @param patchName * @return Success. */ public static boolean isPatchApplied(String patchName) { Connection c = Configuration.getConnection(); int found = 0; PreparedStatement cStmt = null; try { cStmt = c.prepareStatement("SELECT COUNT(*) FROM tPatch " + " WHERE patchName = ? " + ";"); cStmt.setString(1, patchName); boolean hadResults = cStmt.execute(); if (hadResults) { ResultSet rs = cStmt.getResultSet(); rs.next(); found = rs.getInt(1); rs.close(); } } catch (NullPointerException npe) { log.error("Caught NullPointerException", npe); } catch (Throwable e) { } finally { DbUtil.closeSafely(cStmt); DbUtil.closeSafely(c); } return (boolean) (found > 0); } /** * Record record of patch into tPatch table so that patches only run once. * * @param patchName * @return Success. */ public static boolean recordPatch(String patchName) { Connection c = Configuration.getConnection(); boolean status = false; PreparedStatement cStmt = null; try { cStmt = c.prepareStatement("INSERT INTO tPatch " + " ( patchName, stamp ) " + " VALUES ( ?, NOW() ) " + ";"); cStmt.setString(1, patchName); cStmt.execute(); status = true; } catch (NullPointerException npe) { log.error("Caught NullPointerException", npe); } catch (SQLException sq) { log.error("Caught SQLException", sq); } catch (Throwable e) { } finally { DbUtil.closeSafely(cStmt); DbUtil.closeSafely(c); } return status; } public static void dbPatcher(String patchLocation) { log.info("Database patching started for " + patchLocation); File patchDirectoryObject = new File(patchLocation); String[] children = patchDirectoryObject.list(new FilenameFilter() { @Override public boolean accept(File file, String name) { if (name.startsWith(".")) { log.debug("Skipping " + name + " (dot file)"); return false; } return true; } }); if (children != null) { // Sort all patches into name order. Arrays.sort(children); // Process patches log.info("Found " + children.length + " patches to process"); for (String patchFilename : children) { String patchName = FilenameUtils.getBaseName(patchFilename); if (DbPatch.isPatchApplied(patchName)) { log.info("Patch " + patchName + " already applied."); continue; } else { log.info("Applying patch " + patchName + ", source file = " + patchFilename); boolean success = DbPatch.applyPatch(patchDirectoryObject .getAbsolutePath() + File.separatorChar + patchFilename); if (success) { DbPatch.recordPatch(patchName); } else { log.error("Failed to apply " + patchName + ", stopping patch sequence."); return; } } } } log.info("Database patching completed"); } }