From 635b88acc18a17db30d8d281c50d2f54ee2a91d9 Mon Sep 17 00:00:00 2001 From: Chris Jaekl Date: Thu, 27 Aug 2015 22:26:44 +0900 Subject: [PATCH] Bring things to a state where the basic DB schema gets auto-created if it doesn't yet exist. --- go.sh | 8 ++++ prod/cfb.properties | 1 + prod/net/jaekl/cfb/CFB.java | 27 ++++++++---- prod/net/jaekl/cfb/CfbBundle.java | 50 ++++++++++++++++++++++ prod/net/jaekl/cfb/db/CfbSchema.java | 6 +-- prod/net/jaekl/cfb/db/Schema.java | 6 ++- prod/net/jaekl/cfb/db/driver/DbDriver.java | 3 ++ prod/net/jaekl/qd/QDBundleFactory.java | 40 +++++++++++++++++ setcp.sh | 15 +++++++ 9 files changed, 143 insertions(+), 13 deletions(-) create mode 100755 go.sh create mode 100644 prod/cfb.properties create mode 100644 prod/net/jaekl/cfb/CfbBundle.java create mode 100644 prod/net/jaekl/qd/QDBundleFactory.java create mode 100644 setcp.sh diff --git a/go.sh b/go.sh new file mode 100755 index 0000000..b546f3c --- /dev/null +++ b/go.sh @@ -0,0 +1,8 @@ +#!/bin/bash +CFB_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +echo Compiling... +find "${CFB_ROOT}/prod" -name "*.java" | xargs javac -classpath ${CFB_ROOT}/prod:${CLASSPATH} -Xlint:deprecation +cp -r ${CFB_ROOT}/prod/* ${CFB_ROOT}/bin/ +find "${CFB_ROOT}/prod" -name '*.class' -exec rm {} \; +echo Launching... +java -Djsse.enableSNIExtension=false net.jaekl.cfb.CFB $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} ${12} ${13} ${14} ${15} ${16} ${17} ${18} ${19} ${20} diff --git a/prod/cfb.properties b/prod/cfb.properties new file mode 100644 index 0000000..a491bf0 --- /dev/null +++ b/prod/cfb.properties @@ -0,0 +1 @@ +cannot.connect.to.db=Unable to connect to database {2} on {0}:{1} as user {3}. diff --git a/prod/net/jaekl/cfb/CFB.java b/prod/net/jaekl/cfb/CFB.java index d864b6d..4d30011 100644 --- a/prod/net/jaekl/cfb/CFB.java +++ b/prod/net/jaekl/cfb/CFB.java @@ -3,6 +3,12 @@ package net.jaekl.cfb; import java.io.PrintWriter; import java.sql.Connection; import java.sql.SQLException; +import java.text.MessageFormat; +import java.util.Locale; + +import net.jaekl.cfb.db.CfbSchema; +import net.jaekl.cfb.db.driver.DbDriver; +import net.jaekl.cfb.db.driver.PostgresqlDriver; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.GnuParser; @@ -10,13 +16,11 @@ import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; -import net.jaekl.cfb.db.CfbSchema; -import net.jaekl.cfb.db.driver.DbDriver; -import net.jaekl.cfb.db.driver.PostgresqlDriver; - public class CFB { DbDriver m_driver; CfbSchema m_schema; + CfbBundle m_bundle; + Locale m_locale; // Command-line parameters String m_dbName; // db name @@ -25,9 +29,11 @@ public class CFB { String m_user; // db user String m_pass; // db password - CFB() { + CFB(Locale locale) { m_driver = new PostgresqlDriver(); m_schema = new CfbSchema(m_driver); + m_locale = locale; + m_bundle = CfbBundle.getInst(m_locale); m_dbName = "CFB"; m_host = "localhost"; @@ -82,6 +88,10 @@ public class CFB { help.printHelp(pw, 80, getClass().getName(), "", opt, 0, 0, "", true); } + String trans(String key) { + return m_bundle.get(key); + } + void doMain(PrintWriter pw, String[] args) throws SQLException { if ( ! parseArgs(pw, args) ) { return; @@ -89,8 +99,9 @@ public class CFB { try (Connection con = m_driver.connect(m_host, m_port, m_dbName, m_user, m_pass)) { if (null == con) { - // TODO: string table - pw.println("FATAL: Cannot connect to db."); + String cannotConnectFormat = trans(CfbBundle.CANNOT_CONNECT); + String cannotConnect = MessageFormat.format(cannotConnectFormat, m_host, m_port, m_dbName, m_user); + pw.println(cannotConnect); return; } m_schema.ensureDbInitialized(con); @@ -98,7 +109,7 @@ public class CFB { } public static void main(String[] args) { - CFB cfb = new CFB(); + CFB cfb = new CFB(Locale.getDefault()); try (PrintWriter pw = new PrintWriter(System.out)){ cfb.doMain(pw, args); diff --git a/prod/net/jaekl/cfb/CfbBundle.java b/prod/net/jaekl/cfb/CfbBundle.java new file mode 100644 index 0000000..0384851 --- /dev/null +++ b/prod/net/jaekl/cfb/CfbBundle.java @@ -0,0 +1,50 @@ +package net.jaekl.cfb; + +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.concurrent.ConcurrentHashMap; + +import net.jaekl.qd.QDBundleFactory; + +public class CfbBundle { + public static final String CANNOT_CONNECT = "cannot.connect.to.db"; + + final static String BUNDLE_NAME = "cfb"; + + static ConcurrentHashMap m_bundleMap = new ConcurrentHashMap(); + + ResourceBundle m_bundle; + + public static CfbBundle getInst(Locale locale) { + CfbBundle result = m_bundleMap.get(locale); + if (null == result) { + synchronized(CfbBundle.class) { + result = m_bundleMap.get(locale); + if (null == result) { + result = new CfbBundle(locale); + } + m_bundleMap.put(locale, result); + } + } + return result; + } + + private CfbBundle(Locale locale) { + m_bundle = QDBundleFactory.getInst().getBundle(BUNDLE_NAME, locale); + } + + public String get(String key) { + try { + if (null != m_bundle) { + return m_bundle.getString(key); + } + } + catch (MissingResourceException exc) { + // Make it clear that something has gone wrong. + exc.printStackTrace(); + // Fall through to the fallback behaviour below + } + return "[" + key + "]"; + } +} diff --git a/prod/net/jaekl/cfb/db/CfbSchema.java b/prod/net/jaekl/cfb/db/CfbSchema.java index b298f57..52e067b 100644 --- a/prod/net/jaekl/cfb/db/CfbSchema.java +++ b/prod/net/jaekl/cfb/db/CfbSchema.java @@ -45,11 +45,11 @@ public class CfbSchema extends Schema { }, { // Runs of FindBugs, normally one per build version - { "RUNS " }, + { "RUNS" }, { "RUNID", INTEGER, -1, NOT_NULL }, { "VERSION", VARCHAR, 32, NULL }, - { "START", TIMESTAMPTZ, -1, NOT_NULL }, - { "END", TIMESTAMPTZ, -1, NOT_NULL } + { "STARTTIME", TIMESTAMPTZ, -1, NOT_NULL }, + { "ENDTIME", TIMESTAMPTZ, -1, NOT_NULL } } }; diff --git a/prod/net/jaekl/cfb/db/Schema.java b/prod/net/jaekl/cfb/db/Schema.java index bfcfdb8..eef7b8e 100644 --- a/prod/net/jaekl/cfb/db/Schema.java +++ b/prod/net/jaekl/cfb/db/Schema.java @@ -6,6 +6,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashSet; +import java.util.Locale; import net.jaekl.cfb.db.driver.DbDriver; @@ -42,12 +43,13 @@ public class Schema { try (ResultSet rs = dbmd.getTables(null, null, null, new String[]{"TABLE"})) { while (rs.next()) { - extantTables.add(rs.getString(3)); + extantTables.add(rs.getString(3).toUpperCase(Locale.CANADA)); } } for (Table table : m_tables) { - if ( ! extantTables.contains(table.getName()) ) { + String name = table.getName().toUpperCase(Locale.CANADA); + if ( ! extantTables.contains(name) ) { // One or more tables missing return false; } diff --git a/prod/net/jaekl/cfb/db/driver/DbDriver.java b/prod/net/jaekl/cfb/db/driver/DbDriver.java index fa38862..9de7264 100644 --- a/prod/net/jaekl/cfb/db/driver/DbDriver.java +++ b/prod/net/jaekl/cfb/db/driver/DbDriver.java @@ -26,6 +26,9 @@ public abstract class DbDriver { try (PreparedStatement ps = con.prepareStatement(sql)) { ps.executeUpdate(); } + catch (SQLException exc) { + throw new SQLException("Failed to executeUpdate: " + sql, exc); + } return true; } diff --git a/prod/net/jaekl/qd/QDBundleFactory.java b/prod/net/jaekl/qd/QDBundleFactory.java new file mode 100644 index 0000000..e53c878 --- /dev/null +++ b/prod/net/jaekl/qd/QDBundleFactory.java @@ -0,0 +1,40 @@ +// Copyright (C) 2004, 2014 Christian Jaekl + +// Central spot from which to access ResourceBundles. +// This made more sense with earlier versions of Java, where the specification did not +// guarantee that ResourceBundles would be cached. Java 7 and later cache by default, +// but it still seems prudent to centralize accesses to resources here so that we have +// control in case we want to implement our own cache, or override certain behaviours. +// +// Note that we rely on the JVM's caching, to avoid unnecessary overhead. +// See http://java2go.blogspot.ca/2010/03/dont-be-smart-never-implement-resource.html + +package net.jaekl.qd; + +import java.util.Locale; +import java.util.ResourceBundle; + +public class QDBundleFactory { + static volatile QDBundleFactory m_inst; // singleton instance + + private QDBundleFactory() { + // no-op + } + + public static QDBundleFactory getInst() { + QDBundleFactory result = m_inst; + if (null == result) { + synchronized(QDBundleFactory.class) { + if (null == m_inst) { + m_inst = new QDBundleFactory(); + } + result = m_inst; + } + } + return result; + } + + public ResourceBundle getBundle(String baseName, Locale locale) { + return ResourceBundle.getBundle(baseName, locale); + } +} diff --git a/setcp.sh b/setcp.sh new file mode 100644 index 0000000..a27737a --- /dev/null +++ b/setcp.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +export CLASSPATH=${SCRIPT_DIR}/bin + +for x in ${SCRIPT_DIR}/lib/*.jar +do + export CLASSPATH=${x}:${CLASSPATH} +done + +export CLASSPATH=/usr/share/java/commons-cli.jar:${CLASSPATH} +export CLASSPATH=/usr/share/java/junit4.jar:${CLASSPATH} +export CLASSPATH=/usr/share/java/postgresql.jar:${CLASSPATH} +#export CLASSPATH=${SCRIPT_DIR}/jcov/jcov.jar:${CLASSPATH} -- 2.30.2