Issue #1960 Generalize and fix the data delivery DbInit process for Postgres 9

Change-Id: I4b7ca6e23993dbecad284e8dc434918bc5f55678

Former-commit-id: 83a015b556 [formerly 4ed0e3f954e5abf420d9e9c2dc4d197c1613f046]
Former-commit-id: 87829b4cf1
This commit is contained in:
Dustin Johnson 2013-04-30 15:47:32 -05:00
parent 6b1f4a69c1
commit b6c7f2d6c6
11 changed files with 479 additions and 575 deletions

View file

@ -26,6 +26,7 @@ Export-Package: com.raytheon.uf.edex.database,
com.raytheon.uf.edex.database.cluster.handler,
com.raytheon.uf.edex.database.dao,
com.raytheon.uf.edex.database.handlers,
com.raytheon.uf.edex.database.init,
com.raytheon.uf.edex.database.plugin,
com.raytheon.uf.edex.database.purge,
com.raytheon.uf.edex.database.query,

View file

@ -0,0 +1,345 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.edex.database.init;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.dialect.Dialect;
import org.hibernate.jdbc.Work;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
/**
* The DbInit class is responsible for ensuring that the appropriate tables are
* present in the database implementation for the session factory.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 30, 2013 1960 djohnson Extracted and generalized from the registry DbInit.
* </pre>
*
* @author djohnson
*/
public abstract class DbInit {
/** The logger */
private static final IUFStatusHandler statusHandler = UFStatus
.getHandler(DbInit.class);
/** Constant used for table regeneration */
private static final Pattern DROP_TABLE_PATTERN = Pattern
.compile("^drop\\stable\\s");
/** Constant used for table regeneration */
private static final Pattern DROP_SEQUENCE_PATTERN = Pattern
.compile("^drop\\ssequence\\s");
/** Constant used for table regeneration */
private static final Pattern CASCADE_PATTERN = Pattern
.compile("\\scascade$");
/** Constant used for table regeneration */
private static final String DROP_TABLE = "drop table ";
/** Constant used for table regeneration */
private static final String DROP_SEQUENCE = "drop sequence ";
/** Constant used for table regeneration */
private static final String IF_EXISTS = "if exists ";
/** Constant used for table regeneration */
private static final String DROP_TABLE_IF_EXISTS = DROP_TABLE + IF_EXISTS;
/** Constant used for table regeneration */
private static final String DROP_SEQUENCE_IF_EXISTS = DROP_SEQUENCE
+ IF_EXISTS;
/** Constant used for table regeneration */
private static final String CASCADE = " cascade";
/** The logging application db name **/
private final String application;
/**
* Constructor.
*
* @param application
* the application component the database is used in support of
*/
protected DbInit(String application) {
this.application = application;
}
/**
* Initializes the database. This method compares the existing tables in the
* database to verify that they match the tables that Hibernate is aware of.
* If the existing tables in the database do not match the tables Hibernate
* is expecting, the tables are regenerated. During the regeneration
* process, the minimum database objects are reloaded into the database.
*
* @throws Exception
* on error initializing the database
*/
public final void initDb() throws Exception {
/*
* Create a new configuration object which holds all the classes that
* this Hibernate SessionFactory is aware of
*/
AnnotationConfiguration aConfig = getAnnotationConfiguration();
/*
* Check to see if the database is valid.
*/
boolean dbIsValid = isDbValid(aConfig);
if (dbIsValid) {
// Database is valid.
statusHandler.info("Database for application [" + application
+ "] is up to date!");
} else {
// Database is not valid. Drop and regenerate the tables defined by
// Hibernate
statusHandler
.info("Database for application ["
+ application
+ "] is out of sync with defined java classes. Regenerating default database tables...");
statusHandler.info("Dropping existing tables...");
dropTables(aConfig);
statusHandler.info("Recreating tables...");
createTables(aConfig);
statusHandler.info("Executing additional SQL...");
executeAdditionalSql();
statusHandler.info("Database tables for application [" + application
+ "] have been successfully regenerated!");
}
}
/**
* Hook method to execute any additional setup required.
*
* @throws Exception
* any exceptions may be thrown
*/
protected void executeAdditionalSql() throws Exception {
}
/**
* Creates the database tables based on the Class metadata that Hibernate is
* aware of
*
* @param aConfig
* The Hibernate annotation configuration holding the metadata
* for all Hibernate-aware classes
* @throws SQLException
* If the drop sql strings cannot be executed
* @throws EbxmlRegistryException
*/
private void createTables(final AnnotationConfiguration aConfig)
throws SQLException {
final String[] createSqls = aConfig
.generateSchemaCreationScript(getDialect());
final Work work = new Work() {
@Override
public void execute(Connection connection) throws SQLException {
Statement stmt = connection.createStatement();
for (String sql : createSqls) {
stmt.execute(sql);
connection.commit();
}
}
};
executeWork(work);
}
/**
* Checks to see if the database is valid. The RegRep database is considered
* to be valid if the set of tables defined by Hibernate contains the set of
* tables already in existance in the database
*
* @param aConfig
* The Hibernate annotation configuration holding the metadata
* for all Hibernate-aware classes
* @return True if the database is valid, else false
* @throws SQLException
* If the drop sql strings cannot be executed
* @throws EbxmlRegistryException
*/
private boolean isDbValid(AnnotationConfiguration aConfig)
throws SQLException {
statusHandler.info("Verifying the database for application ["
+ application + "] against entity classes...");
final List<String> existingTables = new ArrayList<String>();
List<String> definedTables = new ArrayList<String>();
final Work work = new Work() {
@Override
public void execute(Connection connection) throws SQLException {
Statement stmt = connection.createStatement();
ResultSet results = stmt.executeQuery(getTableCheckQuery());
while (results.next()) {
existingTables.add(results.getString(1));
}
}
};
executeWork(work);
final String[] dropSqls = aConfig
.generateDropSchemaScript(getDialect());
for (String sql : dropSqls) {
Matcher matcher = DROP_TABLE_PATTERN.matcher(sql);
if (matcher.find()) {
// Drop the table names to all lower case since this is the form
// the database expects
sql = matcher.replaceFirst("").toLowerCase();
// Replace any trailing cascades
Matcher cascadeMatcher = CASCADE_PATTERN.matcher(sql);
if (cascadeMatcher.find()) {
sql = cascadeMatcher.replaceFirst("");
}
definedTables.add(sql);
}
}
// Check if the table set defined by Hibernate matches the table set
// defined in the database already
if (existingTables.size() != definedTables.size()
|| !existingTables.containsAll(definedTables)) {
return false;
}
return true;
}
/**
* Drops the union set of tables defined by Hibernate and exist in the
* database.
*
* @param aConfig
* The Hibernate annotation configuration holding the metadata
* for all Hibernate-aware classes
* @throws SQLException
* If the drop sql strings cannot be executed
* @throws EbxmlRegistryException
*/
private void dropTables(final AnnotationConfiguration aConfig)
throws SQLException {
final Work work = new Work() {
@Override
public void execute(Connection connection) throws SQLException {
final String[] dropSqls = aConfig
.generateDropSchemaScript(getDialect());
Statement stmt = connection.createStatement();
for (String sql : dropSqls) {
Matcher dropTableMatcher = DROP_TABLE_PATTERN.matcher(sql);
if (dropTableMatcher.find()) {
executeDropSql(sql, dropTableMatcher,
DROP_TABLE_IF_EXISTS, stmt, connection);
} else {
Matcher dropSequenceMatcher = DROP_SEQUENCE_PATTERN
.matcher(sql);
if (dropSequenceMatcher.find()) {
executeDropSql(sql, dropSequenceMatcher,
DROP_SEQUENCE_IF_EXISTS, stmt, connection);
}
}
}
}
};
executeWork(work);
}
/**
* Convenience method to execute drop sql with parameters.
*
* @param sql
* @param dropTextMatcher
* @param replacementText
* @param stmt
* @param connection
* @throws SQLException
*/
private void executeDropSql(String sql, Matcher dropTextMatcher,
String replacementText, Statement stmt, Connection connection)
throws SQLException {
// Modify the drop string to add the 'if exists'
// and 'cascade' clauses to avoid any errors if
// the tables do not exist already
sql = dropTextMatcher.replaceFirst(replacementText);
if (!sql.endsWith(CASCADE)) {
sql += CASCADE;
}
stmt.execute(sql);
connection.commit();
}
/**
* Get the query that will return the list of current table names used for
* this db init.
*
* @return the query
*/
protected abstract String getTableCheckQuery();
/**
* Get the dialect.
*
* @return
*/
protected abstract Dialect getDialect();
/**
* Execute the work.
*
* @param work
* the work
*/
protected abstract void executeWork(Work work);
/**
* Get the {@link AnnotationConfiguration} to use.
*
* @return
*/
protected abstract AnnotationConfiguration getAnnotationConfiguration();
}

View file

@ -16,7 +16,7 @@
factory-method="getBandwidthDao" />
<bean id="bandwidthDbInit" factory-bean="bandwidthContextFactory"
factory-method="getBandwidthDbInit" init-method="init" />
factory-method="getBandwidthDbInit" />
<bean id="bandwidthManagerInitializer" factory-bean="bandwidthContextFactory"
factory-method="getBandwidthInitializer" depends-on="registryManagerInstanceInitializer">

View file

@ -19,10 +19,6 @@
**/
package com.raytheon.uf.edex.datadelivery.bandwidth;
import java.sql.SQLException;
import org.hibernate.cfg.AnnotationConfiguration;
import com.raytheon.uf.edex.datadelivery.bandwidth.dao.IBandwidthDbInit;
/**
@ -36,6 +32,7 @@ import com.raytheon.uf.edex.datadelivery.bandwidth.dao.IBandwidthDbInit;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 24, 2012 1286 djohnson Initial creation
* Apr 30, 2013 1960 djohnson Remove unnecessary methods.
*
* </pre>
*
@ -51,22 +48,4 @@ class InMemoryBandwidthDbInit implements IBandwidthDbInit {
public void init() {
// Nothing required
}
/**
* {@inheritDoc}
*/
@Override
public void dropTables(AnnotationConfiguration aConfig) throws SQLException {
// Nothing required
}
/**
* {@inheritDoc}
*/
@Override
public void createTables(AnnotationConfiguration aConfig)
throws SQLException {
// Nothing required
}
}

View file

@ -19,10 +19,6 @@
**/
package com.raytheon.uf.edex.datadelivery.bandwidth.dao;
import java.sql.SQLException;
import org.hibernate.cfg.AnnotationConfiguration;
/**
* Performs any required database initialization.
*
@ -33,6 +29,7 @@ import org.hibernate.cfg.AnnotationConfiguration;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 24, 2012 1286 djohnson Separated from the implementation
* Apr 30, 2013 1960 djohnson Remove unnecessary methods.
*
* </pre>
*
@ -44,27 +41,8 @@ public interface IBandwidthDbInit {
/**
* Initializes the database.
*
* @throws Exception
*/
void init();
/**
* Drop tables.
*
* @param aConfig
* the annotation configuration
*
* @throws SQLException
*/
void dropTables(AnnotationConfiguration aConfig)
throws java.sql.SQLException;
/**
* Create the tables.
*
* @param aConfig
*
* @throws SQLException
*/
void createTables(AnnotationConfiguration aConfig)
throws java.sql.SQLException;;
}
void init() throws Exception;
}

View file

@ -20,18 +20,11 @@
package com.raytheon.uf.edex.datadelivery.bandwidth.hibernate;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.dialect.Dialect;
import org.hibernate.jdbc.Work;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.edex.database.init.DbInit;
import com.raytheon.uf.edex.datadelivery.bandwidth.dao.IBandwidthDbInit;
/**
@ -46,31 +39,14 @@ import com.raytheon.uf.edex.datadelivery.bandwidth.dao.IBandwidthDbInit;
* ------------ ---------- ----------- --------------------------
* Jul 31, 2012 726 jspinks Copied and refactored from ebxml registry DbInit
* Oct 26, 2012 1286 djohnson Renamed to Hibernate specific.
* Apr 30, 2013 1960 djohnson Extend the generalized DbInit.
* </pre>
*
* @author jspinks
* @version 1
*/
public class HibernateBandwidthDbInit implements IBandwidthDbInit {
/** The logger */
private static final IUFStatusHandler statusHandler = UFStatus
.getHandler(HibernateBandwidthDbInit.class);
/** Query to check which tables exist in the database */
private static final String TABLE_CHECK_QUERY = "select tablename from pg_tables where tablename like 'bandwidth_%';";
/** Constant used for table regeneration */
private static final String DROP_TABLE = "drop table ";
/** Constant used for table regeneration */
private static final String DROP_SEQUENCE = "drop sequence ";
/** Constant used for table regeneration */
private static final String IF_EXISTS = "if exists ";
/** Constant used for table regeneration */
private static final String CASCADE = " cascade ";
public class HibernateBandwidthDbInit extends DbInit implements
IBandwidthDbInit {
private final HibernateBandwidthDao bandwidthDao;
@ -83,207 +59,58 @@ public class HibernateBandwidthDbInit implements IBandwidthDbInit {
*
*/
public HibernateBandwidthDbInit(HibernateBandwidthDao bandwidthDao) {
super("bandwidth manager");
this.bandwidthDao = bandwidthDao;
}
/**
* Initializes the ebxml database
* {@inheritDoc}
*/
@Override
public void init() {
protected void executeWork(final Work work) {
bandwidthDao.doWork(work);
}
statusHandler.info("Starting bandwidth database init...");
/**
* {@inheritDoc}
*/
@Override
protected Dialect getDialect() {
return bandwidthDao.getDialect();
}
/**
* {@inheritDoc}
*/
@Override
protected AnnotationConfiguration getAnnotationConfiguration() {
/*
* Create a new configuration object which holds all the classes that
* this Hibernate SessionFactory is aware of
*/
AnnotationConfiguration aConfig = new AnnotationConfiguration();
// TODO: add package scanning or some other more elegant solution, but
// for now
// just to it ugly.
aConfig.addAnnotatedClass(com.raytheon.uf.edex.datadelivery.bandwidth.dao.BandwidthDataSetUpdate.class);
aConfig.addAnnotatedClass(com.raytheon.uf.edex.datadelivery.bandwidth.dao.BandwidthSubscription.class);
aConfig.addAnnotatedClass(com.raytheon.uf.edex.datadelivery.bandwidth.dao.SubscriptionRetrieval.class);
aConfig.addAnnotatedClass(com.raytheon.uf.edex.datadelivery.bandwidth.dao.BandwidthAllocation.class);
/*
* Check to see if the database is valid.
*/
boolean dbIsValid = true;
try {
dbIsValid = isDbValid(aConfig);
} catch (SQLException e) {
throw new IllegalStateException("Error checking if db is valid!", e);
}
if (dbIsValid) {
// Database is valid.
statusHandler.info("Bandwidth database is up to date!");
} else {
// Database is not valid. Drop and regenerate the tables defined by
// Hibernate
statusHandler
.info("Bandwidth database is out of sync with defined java classes. Regenerating default database tables...");
statusHandler.info("Dropping existing tables...");
try {
dropTables(aConfig);
} catch (SQLException e) {
throw new IllegalStateException(
"An unexpected database error occurred while dropping existing Bandwidth database tables.",
e);
}
statusHandler.info("Recreating tables...");
try {
createTables(aConfig);
} catch (SQLException e) {
throw new IllegalStateException(
"An unexpected database error occurred while creating Bandwidth database tables.",
e);
}
statusHandler
.info("Bandwidth database tables have been successfully regenerated!");
}
return aConfig;
}
/**
* Drops the union set of tables defined by Hibernate and exist in the
* database.
*
* @param aConfig
* The Hibernate annotation configuration holding the metadata
* for all Hibernate-aware classes
* @throws SQLException
* If the drop sql strings cannot be executed
* @throws EbxmlRegistryException
* {@inheritDoc}
*/
@Override
public void dropTables(final AnnotationConfiguration aConfig)
throws SQLException {
bandwidthDao.doWork(new Work() {
@Override
public void execute(Connection connection) throws SQLException {
final String[] dropSqls = aConfig
.generateDropSchemaScript(bandwidthDao
.getDialect());
Statement stmt = connection.createStatement();
for (String sql : dropSqls) {
if (sql.startsWith(DROP_TABLE)) {
// Modify the drop string to add the 'if exists'
// and
// 'cascade' clauses to avoid any errors if the
// tables
// do not exist already
sql = sql.replace(DROP_TABLE, DROP_TABLE + IF_EXISTS);
sql += CASCADE;
stmt.execute(sql);
connection.commit();
} else if (sql.startsWith(DROP_SEQUENCE)) {
// Modify the drop string to add the 'if exists'
// and
// 'cascade' clauses to avoid any errors if the
// tables
// do not exist already
sql = sql.replace(DROP_SEQUENCE, DROP_SEQUENCE
+ IF_EXISTS);
sql += CASCADE;
stmt.execute(sql);
connection.commit();
}
} // end for
} // end execute()
} // end Work()
);
public void init() throws Exception {
initDb();
}
/**
* Creates the database tables based on the Class metadata that Hibernate is
* aware of
*
* @param aConfig
* The Hibernate annotation configuration holding the metadata
* for all Hibernate-aware classes
* @throws SQLException
* If the drop sql strings cannot be executed
* @throws EbxmlRegistryException
* {@inheritDoc}
*/
@Override
public void createTables(final AnnotationConfiguration aConfig)
throws SQLException {
final String[] createSqls = aConfig
.generateSchemaCreationScript(bandwidthDao.getDialect());
bandwidthDao.doWork(new Work() {
@Override
public void execute(Connection connection) throws SQLException {
Statement stmt = connection.createStatement();
for (String sql : createSqls) {
stmt.execute(sql);
connection.commit();
}
}
});
}
/**
* Checks to see if the database is valid. The Bandwidth database is
* considered to be valid if the set of tables defined by Hibernate contains
* the set of tables already in existance in the database
*
* @param aConfig
* The Hibernate annotation configuration holding the metadata
* for all Hibernate-aware classes
* @return True if the database is valid, else false
* @throws SQLException
* If the drop sql strings cannot be executed
* @throws EbxmlRegistryException
*/
public boolean isDbValid(AnnotationConfiguration aConfig)
throws SQLException {
statusHandler.info("Verifying bandwidth database...");
final List<String> existingTables = new ArrayList<String>();
List<String> definedTables = new ArrayList<String>();
bandwidthDao.doWork(new Work() {
@Override
public void execute(Connection connection) throws SQLException {
Statement stmt = connection.createStatement();
ResultSet results = stmt.executeQuery(TABLE_CHECK_QUERY);
while (results.next()) {
existingTables.add(results.getString(1));
}
}
});
final String[] dropSqls = aConfig
.generateDropSchemaScript(bandwidthDao
.getDialect());
for (String sql : dropSqls) {
if (sql.startsWith(DROP_TABLE)) {
// Drop the table names to all lower case since this is the form
// the database expects
definedTables.add(sql.replace(DROP_TABLE, "").toLowerCase());
}
}
for (String t : existingTables) {
statusHandler.info("Existing table [" + t + "]");
}
for (String t : definedTables) {
statusHandler.info("Defined table [" + t + "]");
}
// Check if the table set defined by Hibernate matches the table set
// defined in the database already
if (existingTables.size() <= definedTables.size()
&& !existingTables.containsAll(definedTables)) {
return false;
}
return true;
protected String getTableCheckQuery() {
// This intentionally returns a query that will force the tables to be
// recreated
return "SELECT 'alwaysRecreateTables'";
}
}

View file

@ -1,13 +1,10 @@
package com.raytheon.uf.edex.datadelivery.bandwidth.hibernate;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.hibernate.cfg.AnnotationConfiguration;
import com.raytheon.uf.common.datadelivery.registry.Subscription;
import com.raytheon.uf.common.registry.ebxml.RegistryUtil;
import com.raytheon.uf.common.status.IUFStatusHandler;
@ -29,6 +26,7 @@ import com.raytheon.uf.edex.datadelivery.bandwidth.interfaces.BandwidthInitializ
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Feb 20, 2013 1543 djohnson Add SW history, separate how to find subscriptions.
* Apr 30, 2013 1960 djohnson just call init rather than drop/create tables explicitly.
*
* </pre>
*
@ -57,19 +55,11 @@ public class HibernateBandwidthInitializer implements BandwidthInitializer {
// fulfilled. In the case were DD has been down for a while
// BEFORE removing the tables...
// Empty the bandwidth tables (other than BandwidthDataSetUpdate) on
// each start and reload..
AnnotationConfiguration aConfig = new AnnotationConfiguration();
aConfig.addAnnotatedClass(com.raytheon.uf.edex.datadelivery.bandwidth.dao.BandwidthSubscription.class);
aConfig.addAnnotatedClass(com.raytheon.uf.edex.datadelivery.bandwidth.dao.SubscriptionRetrieval.class);
aConfig.addAnnotatedClass(com.raytheon.uf.edex.datadelivery.bandwidth.dao.BandwidthAllocation.class);
try {
dbInit.dropTables(aConfig);
dbInit.createTables(aConfig);
} catch (SQLException e) {
// Cannot proceed from here..
return false;
dbInit.init();
} catch (Exception e1) {
throw new RuntimeException(
"Error generating bandwidth manager tables", e1);
}
Set<Subscription> activeSubscriptions = Collections.emptySet();

View file

@ -26,7 +26,8 @@ Require-Bundle: com.raytheon.uf.common.registry.schemas.ebxml;bundle-version="1.
com.google.guava;bundle-version="1.0.0",
com.raytheon.uf.common.registry.ebxml,
com.raytheon.uf.common.stats;bundle-version="1.0.0",
com.raytheon.uf.common.registry.event;bundle-version="1.0.0"
com.raytheon.uf.common.registry.event;bundle-version="1.0.0",
com.raytheon.uf.edex.database;bundle-version="1.0.0"
Export-Package: com.raytheon.uf.edex.registry.ebxml.services.lifecycle,
com.raytheon.uf.edex.registry.ebxml.services.query,
com.raytheon.uf.edex.registry.ebxml.services.util

View file

@ -6,8 +6,9 @@
<bean id="ServiceUrlFactory"
class="com.raytheon.uf.edex.registry.ebxml.util.ServiceUrlFactory" />
<bean id="DbInit" class="com.raytheon.uf.edex.registry.ebxml.dao.DbInit">
<bean id="DbInit" class="com.raytheon.uf.edex.registry.ebxml.dao.DbInit" init-method="initDb">
<constructor-arg ref="lcmServiceImpl" />
<constructor-arg ref="registryDao" />
</bean>
<bean id="registryDao"

View file

@ -27,10 +27,8 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;
@ -44,6 +42,7 @@ import oasis.names.tc.ebxml.regrep.xsd.rim.v4.RegistryObjectType;
import org.apache.commons.beanutils.PropertyUtils;
import org.hibernate.Session;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.dialect.Dialect;
import org.hibernate.impl.SessionFactoryImpl;
import org.hibernate.jdbc.Work;
@ -71,34 +70,25 @@ import com.raytheon.uf.edex.registry.ebxml.services.util.RegistrySessionManager;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 2/9/2012 184 bphillip Initial Coding
* Apr 30, 2013 1960 djohnson Extend the generalized DbInit.
* </pre>
*
* @author bphillip
* @version 1
*/
public class DbInit extends RegistryDao {
public class DbInit extends com.raytheon.uf.edex.database.init.DbInit {
/** The logger */
private static final transient IUFStatusHandler statusHandler = UFStatus
private static final IUFStatusHandler statusHandler = UFStatus
.getHandler(DbInit.class);
/** Query to check which tables exist in the ebxml database */
private static final String TABLE_CHECK_QUERY = "SELECT tablename FROM pg_tables where schemaname = 'public';";
/** Constant used for table regeneration */
private static final String DROP_TABLE = "drop table ";
/** Constant used for table regeneration */
private static final String DROP_SEQUENCE = "drop sequence ";
/** Constant used for table regeneration */
private static final String IF_EXISTS = "if exists ";
/** Constant used for table regeneration */
private static final String CASCADE = " cascade ";
private LifecycleManagerImpl lcm;
private final RegistryDao registryDao;
/**
* Creates a new instance of DbInit. This constructor should only be called
* once when loaded by the Spring container.
@ -106,260 +96,23 @@ public class DbInit extends RegistryDao {
* @throws EbxmlRegistryException
* If errors occur while regenerating the database tables
*/
public DbInit(LifecycleManagerImpl lcm) throws EbxmlRegistryException {
super(null);
public DbInit(LifecycleManagerImpl lcm, RegistryDao registryDao)
throws EbxmlRegistryException {
super("ebxml registry");
this.lcm = lcm;
// try {
initDb();
this.registryDao = registryDao;
}
/**
* Initializes the RegRep database. This method compares the existing tables
* in the database to verify that they match the tables that Hibernate is
* aware of. If the existing tables in the database do not match the tables
* Hibernate is expecting, the tables are regenerated. During the
* regeneration process, the minimum database objects are reloaded into the
* database.
*
* @throws EbxmlRegistryException
* {@inheritDoc}
*/
private void initDb() throws EbxmlRegistryException {
/*
* Create a new configuration object which holds all the classes that
* this Hibernate SessionFactory is aware of
*/
AnnotationConfiguration aConfig = new AnnotationConfiguration();
for (Object obj : this.getSessionFactory().getAllClassMetadata()
.keySet()) {
try {
Class<?> clazz = Class.forName((String) obj);
aConfig.addAnnotatedClass(clazz);
} catch (ClassNotFoundException e) {
statusHandler.error(
"Error initializing RegRep database. Class not found: "
+ obj, e);
}
}
@Override
protected void executeAdditionalSql() throws Exception {
super.executeAdditionalSql();
/*
* Check to see if the database is valid.
*/
boolean dbIsValid = true;
try {
dbIsValid = isDbValid(aConfig);
} catch (SQLException e) {
throw new EbxmlRegistryException("Error checking if db is valid!",
e);
}
executeRegistrySql();
if (dbIsValid) {
// Database is valid.
statusHandler.info("RegRep database is up to date!");
} else {
// Database is not valid. Drop and regenerate the tables defined by
// Hibernate
statusHandler
.info("RegRep database is out of sync with defined java classes. Regenerating default database tables...");
statusHandler.info("Dropping existing tables...");
try {
dropTables(aConfig);
} catch (SQLException e) {
throw new EbxmlRegistryException(
"An unexpected database error occurred while dropping existing RegRep database tables.",
e);
}
statusHandler.info("Recreating tables...");
try {
createTables(aConfig);
} catch (SQLException e) {
throw new EbxmlRegistryException(
"An unexpected database error occurred while creating RegRep database tables.",
e);
}
statusHandler.info("Executing additional registry SQL...");
try {
executeRegistrySql();
} catch (EbxmlRegistryException e) {
throw new EbxmlRegistryException(
"An unexpected database error occurred while executing additional sql on the registry",
e);
}
try {
populateDB();
} catch (SerializationException e) {
throw new EbxmlRegistryException(
"Serialization error populating RegRep database with minDB objects",
e);
} catch (MsgRegistryException e) {
throw new EbxmlRegistryException(
"SubmitObjects encountered an error while populating RegRep database with minDB",
e);
}
statusHandler
.info("RegRep database tables have been successfully regenerated!");
}
}
/**
* Drops the union set of tables defined by Hibernate and exist in the
* database.
*
* @param aConfig
* The Hibernate annotation configuration holding the metadata
* for all Hibernate-aware classes
* @throws SQLException
* If the drop sql strings cannot be executed
* @throws EbxmlRegistryException
*/
private void dropTables(final AnnotationConfiguration aConfig)
throws SQLException, EbxmlRegistryException {
this.doInTransaction(new RegistryTransactionCallback() {
@Override
public Object execute(Session session)
throws EbxmlRegistryException {
session.doWork(new Work() {
@Override
public void execute(Connection connection)
throws SQLException {
final String[] dropSqls = aConfig
.generateDropSchemaScript(((SessionFactoryImpl) getSessionFactory())
.getDialect());
Statement stmt = connection.createStatement();
for (String sql : dropSqls) {
if (sql.startsWith(DROP_TABLE)) {
// Modify the drop string to add the 'if exists'
// and
// 'cascade' clauses to avoid any errors if the
// tables
// do not exist already
sql = sql.replace(DROP_TABLE, DROP_TABLE
+ IF_EXISTS);
sql += CASCADE;
stmt.execute(sql);
connection.commit();
} else if (sql.startsWith(DROP_SEQUENCE)) {
// Modify the drop string to add the 'if exists'
// and
// 'cascade' clauses to avoid any errors if the
// tables
// do not exist already
sql = sql.replace(DROP_SEQUENCE, DROP_SEQUENCE
+ IF_EXISTS);
sql += CASCADE;
stmt.execute(sql);
connection.commit();
}
}
}
});
return null;
}
});
}
/**
* Creates the database tables based on the Class metadata that Hibernate is
* aware of
*
* @param aConfig
* The Hibernate annotation configuration holding the metadata
* for all Hibernate-aware classes
* @throws SQLException
* If the drop sql strings cannot be executed
* @throws EbxmlRegistryException
*/
private void createTables(final AnnotationConfiguration aConfig)
throws SQLException, EbxmlRegistryException {
this.doInTransaction(new RegistryTransactionCallback() {
@Override
public Object execute(Session session)
throws EbxmlRegistryException {
final String[] createSqls = aConfig
.generateSchemaCreationScript(((SessionFactoryImpl) getSessionFactory())
.getDialect());
session.doWork(new Work() {
@Override
public void execute(Connection connection)
throws SQLException {
Statement stmt = connection.createStatement();
for (String sql : createSqls) {
stmt.execute(sql);
connection.commit();
}
}
});
return null;
}
});
}
/**
* Checks to see if the database is valid. The RegRep database is considered
* to be valid if the set of tables defined by Hibernate contains the set of
* tables already in existance in the database
*
* @param aConfig
* The Hibernate annotation configuration holding the metadata
* for all Hibernate-aware classes
* @return True if the database is valid, else false
* @throws SQLException
* If the drop sql strings cannot be executed
* @throws EbxmlRegistryException
*/
private boolean isDbValid(AnnotationConfiguration aConfig)
throws SQLException, EbxmlRegistryException {
statusHandler.info("Verifying RegRep database...");
final List<String> existingTables = new ArrayList<String>();
List<String> definedTables = new ArrayList<String>();
this.doInTransaction(new RegistryTransactionCallback() {
@Override
public Object execute(Session session)
throws EbxmlRegistryException {
session.doWork(new Work() {
@Override
public void execute(Connection connection)
throws SQLException {
Statement stmt = connection.createStatement();
ResultSet results = stmt
.executeQuery(TABLE_CHECK_QUERY);
while (results.next()) {
existingTables.add(results.getString(1));
}
}
});
return null;
}
});
final String[] dropSqls = aConfig
.generateDropSchemaScript(((SessionFactoryImpl) getSessionFactory())
.getDialect());
for (String sql : dropSqls) {
if (sql.startsWith(DROP_TABLE)) {
// Drop the table names to all lower case since this is the form
// the database expects
definedTables.add(sql.replace(DROP_TABLE, "").toLowerCase());
}
}
// Check if the table set defined by Hibernate matches the table set
// defined in the database already
if (existingTables.size() <= definedTables.size()
&& !existingTables.containsAll(definedTables)) {
return false;
}
return true;
populateDB();
}
/**
@ -388,9 +141,9 @@ public class DbInit extends RegistryDao {
statusHandler.info("Populating RegRep database from file: "
+ fileList[i].getName());
SubmitObjectsRequest obj = null;
obj = (SubmitObjectsRequest) SerializationUtil
.jaxbUnmarshalFromXmlFile(fileList[i]);
SubmitObjectsRequest obj = SerializationUtil
.jaxbUnmarshalFromXmlFile(SubmitObjectsRequest.class,
fileList[i]);
// Ensure an owner is assigned
for (RegistryObjectType regObject : obj.getRegistryObjectList()
@ -403,7 +156,6 @@ public class DbInit extends RegistryDao {
}
}
// try {
RegistrySessionManager.openSession();
try {
lcm.submitObjectsInternal(obj);
@ -449,21 +201,13 @@ public class DbInit extends RegistryDao {
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
this.doInTransaction(new RegistryTransactionCallback() {
executeWork(new Work() {
@Override
public Object execute(Session session)
throws EbxmlRegistryException {
session.doWork(new Work() {
@Override
public void execute(Connection connection)
throws SQLException {
Statement stmt = connection
.createStatement();
stmt.execute(buffer.toString());
connection.commit();
}
});
return null;
public void execute(Connection connection)
throws SQLException {
Statement stmt = connection.createStatement();
stmt.execute(buffer.toString());
connection.commit();
}
});
} catch (Exception e) {
@ -535,6 +279,66 @@ public class DbInit extends RegistryDao {
}
}
/**
* {@inheritDoc}
*/
@Override
protected void executeWork(final Work work) {
try {
registryDao.doInTransaction(new RegistryTransactionCallback() {
@Override
public Object execute(Session session)
throws EbxmlRegistryException {
session.doWork(work);
return null;
}
});
} catch (EbxmlRegistryException e) {
throw new RuntimeException(e);
}
}
/**
* {@inheritDoc}
*/
@Override
protected AnnotationConfiguration getAnnotationConfiguration() {
/*
* Create a new configuration object which holds all the classes that
* this Hibernate SessionFactory is aware of
*/
AnnotationConfiguration aConfig = new AnnotationConfiguration();
for (Object obj : registryDao.getSessionFactory().getAllClassMetadata()
.keySet()) {
try {
Class<?> clazz = Class.forName((String) obj);
aConfig.addAnnotatedClass(clazz);
} catch (ClassNotFoundException e) {
statusHandler.error(
"Error initializing RegRep database. Class not found: "
+ obj, e);
}
}
return aConfig;
}
/**
* {@inheritDoc}
*/
@Override
protected Dialect getDialect() {
return ((SessionFactoryImpl) registryDao.getSessionFactory())
.getDialect();
}
/**
* {@inheritDoc}
*/
@Override
protected String getTableCheckQuery() {
return TABLE_CHECK_QUERY;
}
public LifecycleManagerImpl getLcm() {
return lcm;
}
@ -542,5 +346,4 @@ public class DbInit extends RegistryDao {
public void setLcm(LifecycleManagerImpl lcm) {
this.lcm = lcm;
}
}

View file

@ -19,10 +19,6 @@
**/
package com.raytheon.uf.edex.datadelivery.bandwidth;
import java.sql.SQLException;
import org.hibernate.cfg.AnnotationConfiguration;
import com.raytheon.uf.edex.datadelivery.bandwidth.dao.IBandwidthDbInit;
/**
@ -35,6 +31,7 @@ import com.raytheon.uf.edex.datadelivery.bandwidth.dao.IBandwidthDbInit;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 12, 2012 0726 djohnson Initial creation
* Apr 30, 2013 1960 djohnson Remove unnecessary methods.
*
* </pre>
*
@ -51,22 +48,4 @@ public class IntegrationTestDbInit implements IBandwidthDbInit {
public void init() {
// Nothing required
}
/**
* {@inheritDoc}
*/
@Override
public void dropTables(AnnotationConfiguration aConfig) throws SQLException {
// Nothing required
}
/**
* {@inheritDoc}
*/
@Override
public void createTables(AnnotationConfiguration aConfig)
throws SQLException {
// Nothing required
}
}