Coverage Report - net.sourceforge.addam.ddlrun.ServletContainerUpgrader
 
Classes in this File Line Coverage Branch Coverage Complexity
ServletContainerUpgrader
0%
0/98
0%
0/11
3.778
ServletContainerUpgrader$PropertiesMessageFormat
0%
0/22
0%
0/4
3.778
 
 1  
 /*
 2  
  * Copyright (c) 2004 International Decision Systems, Inc.  All Rights Reserved.
 3  
  *
 4  
  * By using this Software, You acknowledge that the Software is a valuable asset
 5  
  * and trade secret of either International Decision Systems, Inc. ("IDSI") or a
 6  
  * third party supplier of IDSI and constitutes confidential and proprietary
 7  
  * information.
 8  
  *
 9  
  * NEITHER IDSI NOR ANY AGENT OR PERSON ACTING FOR OR WITH IDSI HAS MADE OR DOES
 10  
  * MAKE ANY STATEMENTS, AFFIRMATIONS, REPRESENTATIONS OR WARRANTIES WHATSOEVER
 11  
  * TO YOU, WHETHER EXPRESS OR IMPLIED, AS TO THE SOFTWARE, THE QUALITY OR
 12  
  * CONDITION OF THE SOFTWARE, OR THE OPERATING CHARACTERISTICS OR RELIABILITY OF
 13  
  * THE SOFTWARE, OR ITS SUITABILITY FOR ANY GENERAL OR PARTICULAR PURPOSE, OR AS
 14  
  * TO ANY OTHER MATTER WHATSOEVER; ANY AND ALL OTHER WARRANTIES INCLUDING
 15  
  * WITHOUT LIMITATION ANY WARRANTIES IMPLIED BY LAW, SUCH AS THE IMPLIED
 16  
  * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND TITLE,
 17  
  * USE AND NON-INFRINGEMENT; ARE HEREBY EXPRESSLY DISCLAIMED AND EXCLUDED.
 18  
 */
 19  
 package net.sourceforge.addam.ddlrun;
 20  
 
 21  
 
 22  
 import javax.naming.InitialContext;
 23  
 import javax.servlet.ServletContext;
 24  
 import javax.servlet.ServletContextEvent;
 25  
 import javax.servlet.ServletContextListener;
 26  
 import javax.sql.DataSource;
 27  
 
 28  
 import net.sourceforge.addam.ddlrun.custom.IDSCompletedScriptRetriever;
 29  
 import net.sourceforge.addam.ddlrun.custom.IDSRunLogger;
 30  
 import net.sourceforge.addam.ddlrun.custom.IDSStartFolderRetriever;
 31  
 import net.sourceforge.addam.ddlrun.grammars.ScriptGrammar;
 32  
 import net.sourceforge.addam.ddlrun.grammars.ScriptGrammarManager;
 33  
 import net.sourceforge.addam.ddlrun.runners.DeploymentRunner;
 34  
 import net.sourceforge.addam.ddlrun.runners.DeploymentRunnerFactory;
 35  
 import net.sourceforge.addam.ddlrun.utils.ClassLoaderReaderFactory;
 36  
 import net.sourceforge.addam.ddlrun.utils.ResourceReaderFactory;
 37  
 import net.sourceforge.addam.ddlrun.utils.RunLogger;
 38  
 
 39  
 import java.io.File;
 40  
 import java.io.FileWriter;
 41  
 import java.io.IOException;
 42  
 import java.sql.Connection;
 43  
 import java.sql.SQLException;
 44  
 import java.text.MessageFormat;
 45  
 import java.util.ArrayList;
 46  
 import java.util.Date;
 47  
 import java.util.Properties;
 48  
 import java.util.regex.Matcher;
 49  
 import java.util.regex.Pattern;
 50  
 
 51  
 /**
 52  
  * @author TIM3
 53  
  * @since Mar 25, 2005
 54  
  */
 55  0
 public class ServletContainerUpgrader implements ServletContextListener, RunLogger {
 56  
 
 57  0
     ServletContext sCtx = null;
 58  0
     FileWriter errorLog = null;
 59  0
     private int scriptsExecuted = 0;
 60  0
     protected String dbversion = null;
 61  
 
 62  
     /**
 63  
      * kicks off an UpgradeRunner - requires a configured DataSource and a
 64  
      * configured upgrade folder and upgrade script
 65  
      */
 66  
     public void contextInitialized(final ServletContextEvent event) {
 67  0
         sCtx = event.getServletContext();
 68  0
         errorLog = getErrorLogFileWriter(sCtx);
 69  0
         Connection connection = null;
 70  
         try {
 71  0
             InitialContext iCtx = new InitialContext();
 72  0
             DataSource dataSource = null;
 73  
             try {
 74  0
                 dataSource = (DataSource) iCtx.lookup("java:comp/env/jdbc/AutoUpgradeDS");
 75  0
             } catch (Exception e) {
 76  
                 // autoupgrade data source not configured
 77  0
                 String logMessage = "unable to locate DataSource, skipping autoupgrade";
 78  0
                 log(sCtx, logMessage, errorLog, null);
 79  0
                 return;
 80  0
             }
 81  
             try {
 82  0
                 connection = dataSource.getConnection();
 83  0
                 if (connection != null) {
 84  
                     // needed due to weblogic bug
 85  0
                     connection.setAutoCommit(false);
 86  
                 }
 87  0
             } catch (Exception e) {
 88  
                 // data source not configured correctly
 89  0
                 String logMessage = "unable to create connection, skipping autoupgrade";
 90  0
                 log(sCtx, logMessage, errorLog, e);
 91  0
                 return;
 92  0
             }
 93  0
             ScriptGrammar grammar = new ScriptGrammarManager().getGrammar(connection);
 94  0
             ResourceReaderFactory factory = new ClassLoaderReaderFactory("database/upgrade/" + grammar.name());
 95  0
             if (grammar == null) {
 96  0
                 String logMessage = "" + connection + " does not use a supported database driver";
 97  0
                 log(sCtx, logMessage, errorLog, null);
 98  0
                 throw new RuntimeException(logMessage);
 99  
             }
 100  0
             DeploymentRunner runner = DeploymentRunnerFactory.getInstance().getUpgradeRunner(factory,
 101  0
                     connection,
 102  0
                     grammar,
 103  0
                     new IDSStartFolderRetriever(connection),
 104  0
                     new IDSCompletedScriptRetriever(connection));
 105  0
             runner.addRunLogger(new IDSRunLogger(connection, dbversion));
 106  0
             runner.addRunLogger(this);
 107  0
             runner.run("upgrade.drv");
 108  0
             if (scriptsExecuted == 0) {
 109  0
                 log(sCtx, "no upgrades necessary", errorLog, null);
 110  0
             } else {
 111  0
                 log(sCtx, "executed " + scriptsExecuted + " scripts", errorLog, null);
 112  
             }
 113  
 
 114  0
         } catch (Exception e) {
 115  0
             if (errorLog != null) {
 116  
                 try {
 117  0
                     String logMessage = "unable to execute upgrade: " + e.getMessage();
 118  0
                     log(sCtx, logMessage, errorLog, null);
 119  0
                 } catch (IOException ignored) {
 120  
                     // what are you gonna do... can't log the first error, can't log this one
 121  0
                 }
 122  
             }
 123  0
             throw new RuntimeException(e);
 124  0
         } finally {
 125  0
             if (connection != null) {
 126  
                 try {
 127  0
                     connection.close();
 128  0
                 } catch (SQLException e) {
 129  
                     // ignore
 130  0
                 }
 131  
             }
 132  0
             if (errorLog != null) {
 133  
                 try {
 134  0
                     errorLog.close();
 135  0
                 } catch (IOException e) {
 136  
                     // ignore
 137  0
                 }
 138  0
             }
 139  0
         }
 140  0
     }
 141  
 
 142  
     public void logRunScript(String script, long time) throws Exception {
 143  0
         String logMessage = "executed " + script + " (" + time + "ms)";
 144  0
         log(sCtx, logMessage, errorLog, null);
 145  0
         scriptsExecuted++;
 146  0
     }
 147  
 
 148  
     public void logRunComplete(String group, long time) throws Exception {
 149  0
         String logMessage = "completed execution of available scripts in " + group + " (" + time + "ms)";
 150  0
         log(sCtx, logMessage, errorLog, null);
 151  0
     }
 152  
 
 153  
     public void logRunFailure(String group, String script, Exception e) throws Exception {
 154  0
         String logMessage = "failed to execute " + group + "/" + script;
 155  0
         log(sCtx, logMessage, errorLog, e);
 156  0
         throw new RuntimeException(logMessage, e);
 157  
     }
 158  
 
 159  
     private void log(final ServletContext sCtx, String message, final FileWriter errorLog, Exception e) throws IOException {
 160  0
         Throwable t = (e == null) ? null : e.fillInStackTrace();
 161  0
         if (t != null) {
 162  0
             sCtx.log(message, t);
 163  0
         } else {
 164  0
             sCtx.log(message);
 165  
         }
 166  0
         if (errorLog != null) {
 167  0
             if (t != null) {
 168  0
                 errorLog.write(message + "\n" + t.toString() + "\n");
 169  0
             } else {
 170  0
                 errorLog.write(message + "\n");
 171  
             }
 172  0
             errorLog.flush();
 173  
         }
 174  0
     }
 175  
 
 176  
     /**
 177  
      * 
 178  
      * @param sCtx
 179  
      * @return
 180  
      * @todo defer creation of file until actual writing error
 181  
      */
 182  
     private FileWriter getErrorLogFileWriter(ServletContext sCtx) {
 183  0
         FileWriter errorLog = null;
 184  0
         String errorLogFormat = sCtx.getInitParameter("error.log");
 185  0
         if (errorLogFormat == null) {
 186  0
             sCtx.log("dbupgrade log file undefined, using servlet context log only");
 187  0
         } else {
 188  
             try {  // todo defer creation of file until actual writing error
 189  0
                 String fileName = PropertiesMessageFormat.format(errorLogFormat, System.getProperties());
 190  0
                 File file = new File(fileName);
 191  0
                 file.getParentFile().mkdirs();
 192  0
                 errorLog = new FileWriter(file, true); //append
 193  0
             } catch (Exception e) {
 194  0
                 sCtx.log("unable to create log file from " + errorLogFormat, e);
 195  0
             }
 196  
         }
 197  0
         return errorLog;
 198  
     }
 199  
 
 200  
     /**
 201  
      * does nothing; required for ServletContextListener implementation
 202  
      */
 203  
     public void contextDestroyed(ServletContextEvent event) {
 204  0
     }
 205  
 
 206  
 
 207  0
     static class PropertiesMessageFormat {
 208  
         static String format(String format, Properties properties) {
 209  0
             Pattern p = Pattern.compile("\\{([^\\{\\}\\,]*)[\\}|\\,]");
 210  0
             Matcher m = p.matcher(format);
 211  0
             StringBuffer buf = new StringBuffer();
 212  0
             ArrayList args = new ArrayList();
 213  0
             while (m.find()) {
 214  0
                 int location = args.size(); // MessageFormat is zero-based so start here
 215  0
                 String match = m.group(0);
 216  0
                 String variable = m.group(1);
 217  0
                 String replacement = "{" + location + (match.endsWith(",") ? "," : "}");
 218  0
                 args.add(getReplacement(variable, properties));
 219  0
                 m.appendReplacement(buf, replacement);
 220  0
             }
 221  0
             m.appendTail(buf);
 222  0
             return MessageFormat.format(buf.toString(), args.toArray());
 223  
         }
 224  
 
 225  
         static Object getReplacement(String variable, Properties properties) {
 226  0
             Object replacement = properties.getProperty(variable);
 227  0
             if (replacement == null) {
 228  0
                 if (variable.equals("current.time")) {
 229  0
                     replacement = new Date();
 230  0
                 } else {
 231  0
                     replacement = "{" + variable + "}";
 232  
                 }
 233  
             }
 234  0
             return replacement;
 235  
         }
 236  
     }
 237  
 
 238  
 }