/*
* NOTE: This copyright does *not* cover user programs that use HQ
* program services by normal system calls through the application
* program interfaces provided as part of the Hyperic Plug-in Development
* Kit or the Hyperic Client Development Kit - this is merely considered
* normal use of the program, and does *not* fall under the heading of
* "derived work".
*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of HQ.
*
* HQ is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.tools.db;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.DecimalFormat;
import java.util.Collection;
import java.util.Iterator;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.hyperic.util.StrongCollection;
import org.hyperic.util.jdbc.JDBC;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* To Do:
* - implement abstract factory for tables,columns,views,etc - the "if dbtype"
* stuff is yucky
* - The verbose/quiet System.out'ing stuff should go away in favor of
* commons-logging
* - hungarian notation must be destroyed
* - schema diff'ing (semantic diff, not xml file diff or something)
* - fix how the driver classes are loaded and the relationship to
* org.hyperic.util.jdbc.JDBC (do you load drivers with just database name
* or by deriving the drivername from the database name and then loading it,
* both seem to happening now, which is bad)
* - fix up terminology ("create" should be "rdbms-export", "setup" should be
* "rdbms-import" or something else) to more descriptive
*/
public class DBSetup {
private static final String COPYRIGHT = "DBSetup, Copyright (C) 2005, Hyperic, Inc. All Rights Reserved.";
private boolean m_bQuiet; // Defaults to false
private boolean m_bNoninteractive; // Defaults to false
private boolean m_bVerbose; // Defaults to false
private String m_logFileName = null;
private boolean m_logAppend = false;
private FileWriter m_log = null;
public static boolean m_bDMLonly = false;
private String m_typeMapFile = null;
private InputStream m_typeMapStream = null;
private int m_lCreatedIndexes;
private int m_lCreatedTables;
private int m_lCreatedViews;
private int m_lFailedIndexes;
private int m_lFailedTables;
private int m_lFailedViews;
private Connection m_conn = null;
/**
* Constructs a DBSetup class with quiet mode turned on.
*/
public DBSetup()
{
}
/**
* Constructs a DBSetup object with quiet mode turned on or off.
*
* @param quiet
* Status messages are sent to std out if true, no message otherwise.
*/
public DBSetup(boolean quiet)
{
this.setQuiet(quiet);
}
/**
* Constructs a DBSetup object with quiet mode turned on or off.
*
* @param quiet
* Status messages are sent to stdout if true, no messages otherwise.
* @param verbose
* SQL Commands and other verbose information is sent to stdout if
* true, no verbose messages otherwise.
*/
public DBSetup(boolean quiet, boolean verbose)
{
if(quiet == true && verbose == true)
verbose = false;
this.setQuiet(quiet);
this.setVerbose(verbose);
}
public DBSetup(boolean quiet, boolean verbose, boolean nonInteractive,
String logFileName, boolean append, boolean noexec) {
this(quiet, verbose);
m_bNoninteractive = nonInteractive;
m_logFileName = logFileName;
m_logAppend = append;
}
public void create(String file, String database, String username, String password)
throws ClassNotFoundException, IOException, SQLException
{
try
{
////////////////////////////////////////////////////////
// Make sure we can connect to the database
m_conn = connect(database, username, password);
////////////////////////////////////////////////////////
// Create the DBSetup XML file
Document doc = this.newDocument();
Element elemRoot = doc.createElement("Covalent.DBSetup");
elemRoot.setAttribute("name", file);
elemRoot.setAttribute("notice", DBSetup.COPYRIGHT);
doc.appendChild(elemRoot);
Iterator iterTabs = Table.getTables(this, username).iterator();
///////////////////////////////////////////////////////
// Find Tables
while(iterTabs.hasNext() == true)
{
Table tab = (Table)iterTabs.next();
if(this.isQuiet() == false)
System.out.println("\nFound Table : " + tab.getName());
Element elemTab = doc.createElement("table");
elemTab.setAttribute("name", tab.getName());
elemRoot.appendChild(elemTab);
///////////////////////////////////////////////////
// Get Columns
Iterator iterCols = tab.getColumns().iterator();
while(iterCols.hasNext() == true)
{
Column col = (Column)iterCols.next();
if(this.isQuiet() == false)
System.out.println("Found Column: " + col.getName());
Element elemChild = doc.createElement("column");
elemChild.setAttribute("name", col.getName());
elemChild.setAttribute("type", col.getType());
elemChild.setAttribute("size", String.valueOf(col.getSize()));
if(col.isRequired() == true)
elemChild.setAttribute("required", String.valueOf(col.isRequired()));
elemTab.appendChild(elemChild);
}
///////////////////////////////////////////////////
// Get Data
DataSet dataset = tab.getDataSet();
while(dataset.next() == true)
{
Element elemChild = doc.createElement("data");
int iCols = tab.getColumns().size();
for(int i = 0;i < iCols;i++)
{
Data data = dataset.getData(i);
elemChild.setAttribute(data.getColumnName(), data.getValue());
}
elemTab.appendChild(elemChild);
}
this.m_lCreatedTables ++;
}
boolean bWrite = true;
if(this.isQuiet() == false)
{
File f = new File(file);
if(f.exists() == true)
{
System.out.print("\nThe file " + file + " already exist. Do you want to overwrite this file? (Y/N): ");
char ch = (char)System.in.read();
if(Character.toUpperCase(ch) != 'Y')
{
System.out.println("Aborted.");;
bWrite = false;
}
}
}
if(bWrite == true)
this.writeDocument(doc, file);
//////////////////////////////////////////////////////////////
// Print Results
if(this.isQuiet() == false)
{
DecimalFormat fmt = new DecimalFormat("#,###");
System.out.println();
System.out.println(fmt.format(this.m_lCreatedViews) +
" views validated.");
System.out.println(fmt.format(this.m_lFailedViews) +
" views failed to validate.");
System.out.println(fmt.format(this.m_lCreatedTables) +
" tables validated.");
System.out.println(fmt.format(this.m_lFailedTables) +
" tables failed to validate.");
System.out.println(fmt.format(this.m_lCreatedIndexes) +
" indexes validated.");
System.out.println(fmt.format(this.m_lFailedIndexes) +
" indexes failed to validate.");
}
} catch(SAXException e) {
throw new IOException(e.getMessage());
} finally {
try {
if(m_conn != null) m_conn.close();
} catch(SQLException e) {}
}
}
public Document newDocument() throws SAXException
{
Document docResult = null;
try
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setErrorHandler(new ErrorHandler());
docResult = builder.newDocument();
}
catch(ParserConfigurationException e)
{
throw new SAXException(e);
}
return docResult;
}
protected static Node copyNode(Document target, Node source, boolean deep)
{
Node nodeNew;
String strNodeName = source.getNodeName();
String strNodeValue = source.getNodeValue();
switch(source.getNodeType()) {
case Node.ELEMENT_NODE:
Element elem = target.createElement(strNodeName);
nodeNew = elem;
NamedNodeMap map = source.getAttributes();
for(int iMap = 0;iMap < map.getLength();iMap ++)
{
Node attr = map.item(iMap);
elem.setAttribute(attr.getNodeName(), attr.getNodeValue());
}
break;
case Node.COMMENT_NODE:
nodeNew = target.createComment(strNodeName);
break;
case Node.TEXT_NODE:
nodeNew = target.createTextNode(strNodeName);
break;
default:
nodeNew = null;
break;
}
nodeNew.setNodeValue(strNodeValue);
if(deep == true && nodeNew != null)
DBSetup.importChildNodes(nodeNew, source, deep);
return nodeNew;
}
protected static void importNodeAfter(Node after, Node source, boolean deep)
{
Node nodeNew = DBSetup.copyNode(after.getOwnerDocument(), source, deep);
//////////////////////////////////////////////////
// Append the node to the target
Node nodeNext = after.getNextSibling();
if(nodeNext != null)
after.getParentNode().insertBefore(nodeNew, after);
else
after.getParentNode().appendChild(nodeNew);
// Get Children
//if(deep == true)
// DBSetup.importChildNodes(nodeNew, source, deep);
}
protected static void importChildNodes(Node parent, Node source, boolean deep)
{
NodeList listChildren = source.getChildNodes();
for(int i = 0;i < listChildren.getLength();i ++)
parent.appendChild(DBSetup.copyNode(parent.getOwnerDocument(), listChildren.item(i), deep));
}
public Document readDocument(String file) throws IOException, SAXException
{
Document docResult = this.readDocument(file, null);
return docResult;
}
public Document readDocument(InputStream is) throws IOException, SAXException
{
Document docResult = this.readDocument(is, null);
return docResult;
}
public Document readDocument(Object source, Node after) throws IOException, SAXException
{
Document docResult = null;
try
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setErrorHandler(new ErrorHandler());
File f = null;
if (source instanceof String) {
f = new File((String) source);
docResult = builder.parse(f);
} else if (source instanceof InputStream) {
docResult = builder.parse((InputStream) source);
}
Node nodeRoot = docResult.getFirstChild();
////////////////////////////////////////////////////////
// Make sure we have a DBSetup XML file.
// This is dumb, because there could be an XML comment before
// the root element. The root node is not the same thing as the
// root element.
if(nodeRoot.getNodeName().equalsIgnoreCase("Covalent.DBSetup") == false) {
if (source instanceof String) {
throw new IOException(source.toString() + " is not a DBSetup XML file.");
} else {
throw new IOException("Source is not a DBSetup XML file.");
}
}
/////////////////////////////////////////////////////////
// Look for include tags
NodeList listNodes = nodeRoot.getChildNodes();
for(int iNode = 0;iNode < listNodes.getLength();iNode ++)
{
Node node = listNodes.item(iNode);
if(node.getNodeName().equalsIgnoreCase("include") == true)
{
NamedNodeMap map = node.getAttributes();
for(int iAttr = 0;iAttr < map.getLength();iAttr++)
{
Node nodeMap = map.item(iAttr);
if(nodeMap.getNodeName().equalsIgnoreCase("file") == true)
{
File fileInclude = new File(nodeMap.getNodeValue());
if(fileInclude.isAbsolute() == false)
{
if (!(source instanceof String)) {
throw new IOException("Cannot resolve paths"
+ " relative to a "
+ "stream.");
}
String strPath = f.getAbsolutePath();
int iIndex = strPath.lastIndexOf(File.separatorChar);
strPath = strPath.substring(0, iIndex);
fileInclude = new File(strPath + File.separatorChar + fileInclude.getPath());
}
this.readDocument(fileInclude.getAbsolutePath(), node);
nodeRoot.removeChild(node);
}
}
}
else if(after != null)
DBSetup.importNodeAfter(after, node, true);
}
}
catch(ParserConfigurationException e)
{
throw new SAXException(e);
}
return docResult;
}
public void writeDocument(Document doc, String file) throws IOException, SAXException
{
try
{
TransformerFactory factory = TransformerFactory.newInstance();
Transformer trans = factory.newTransformer();
trans.setOutputProperty("indent", "yes");
trans.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
DOMSource src = new DOMSource(doc);
StreamResult result = new StreamResult(new File(file));
trans.transform(src, result);
}
catch(TransformerException e)
{
throw new SAXException(e);
}
}
public boolean setup(String file, String database) throws ClassNotFoundException, IOException, SQLException
{
return this.doSetup(file, database, null, null);
}
public boolean setup(String file, String database, String username, String password)
throws ClassNotFoundException, IOException, SQLException
{
return this.doSetup(file, database, username, password);
}
public boolean setup(String file, String database, String username, String password,
String table, boolean doDelete)
throws ClassNotFoundException, IOException, SQLException
{
return this.doSetup(file, database, username, password, table, doDelete);
}
public boolean setup(InputStream is, String database, String username, String password)
throws ClassNotFoundException, IOException, SQLException
{
return this.doSetup(is, database, username, password);
}
protected boolean doSetup(Object source, String database, String username, String password)
throws ClassNotFoundException, IOException, SQLException
{
return this.doSetup(source, database, username, password, null, false);
}
protected boolean doSetup(Object source, String database, String username, String password,
String table, boolean doDelete)
throws ClassNotFoundException, IOException, SQLException
{
try
{
Document doc = null;
if (source instanceof String) {
doc = this.readDocument((String) source);
} else if (source instanceof InputStream) {
doc = this.readDocument((InputStream) source);
}
////////////////////////////////////////////////////////
// Make sure we can connect to the database
JDBC.loadDriver(database);
if(this.isQuiet() == false)
System.out.println("Successfully loaded the database driver.");
m_conn = connect(database, username, password);
if(this.isQuiet() == false)
System.out.println("Successfully connected to the database.");
Collection collTypeMaps = null;
if ( m_typeMapFile != null ) {
collTypeMaps = TypeMap.readTypeMaps(readDocument(m_typeMapFile).getFirstChild());
} else if ( m_typeMapStream != null ) {
collTypeMaps = TypeMap.readTypeMaps(readDocument(m_typeMapStream).getFirstChild());
} else {
collTypeMaps = TypeMap.readTypeMaps(doc.getFirstChild());
}
/**
// check to see if we're dealing with a view or a table
Node dbSetupNode = doc.getFirstChild();
// actually, its the first child of the main node in the schema
NodeList nodeList = dbSetupNode.getChildNodes();
for(int i=0;i < nodeList.getLength(); i++) {
Node rootNode = nodeList.item(i);
if(rootNode.getNodeName().equalsIgnoreCase("table")) {
**/
Node rootNode = doc.getFirstChild();
Iterator iterTab = Table.getTables(rootNode,
JDBC.toType(database), this).iterator();
///////////////////////////////////////////////////////////////////
// Open the log file if we are supposed to log SQL statements.
if ( m_logFileName != null ) {
m_log = new FileWriter(m_logFileName, m_logAppend);
}
while(iterTab.hasNext() == true)
{
Table tab = (Table)iterTab.next();
if (table != null) {
if (!table.equals(tab.getName())) {
continue;
}
if (doDelete) tab.clear();
}
if(this.isVerbose() == true)
System.out.println("Processing Table: " + tab.getName());
if(m_bDMLonly == false)
{
//////////////////////////////////////////////////////////////
// Create the Table
try
{
// Only attempt to create the table if the table tag has columns
if(tab.getColumns().size() > 0)
{
tab.create(collTypeMaps);
if(this.isQuiet() == false)
System.out.println("Created Table: " + tab.getName());
this.m_lCreatedTables ++;
}
}
catch(SQLException e)
{
if(this.isQuiet() == false)
{
System.out.println("Error: " +
"Cannot create table " + tab.getName());
JDBC.printSQLException(e);
}
this.m_lFailedTables ++;
}
///////////////////////////////////////////////////////////////
// Create the Indexes
Iterator iterCol = tab.getIndexes().iterator();
while(iterCol.hasNext() == true)
{
Index idx = (Index)iterCol.next();
try
{
idx.create();
if(this.isQuiet() == false)
System.out.println("Created Index: " +
idx.getName() + " for Table \'" +
idx.getTable().getName() + '\'');
this.m_lCreatedIndexes ++;
}
catch(SQLException e)
{
if(this.isQuiet() == false)
{
System.out.println("Error: Cannot create index " + idx.getName());
JDBC.printSQLException(e);
}
this.m_lFailedIndexes ++;
}
}
}
//////////////////////////////////////////////////////////////
// Create the Data
DataSet dataset = tab.getDataSet();
try
{
int iRowCnt = dataset.create();
if(this.isQuiet() == false)
System.out.println("Created " + iRowCnt + " Row(s).");
}
catch(SQLException e)
{
if(this.isQuiet() == false)
{
System.out.println("Error: " + "Cannot create Row.");
JDBC.printSQLException(e);
if(this.isVerbose() == true)
e.printStackTrace();
}
}
}
// }
// if(rootNode.getNodeName().equalsIgnoreCase("view")) {
// process views
Iterator iterView = View.getViews(rootNode,
JDBC.toType(database), this).iterator();
////////////////////////////////////////////////////
///////////////
// Open the log file if we are supposed to log SQL statements.
if ( m_logFileName != null ) {
m_log = new FileWriter(m_logFileName, m_logAppend);
}
while(iterView.hasNext() == true)
{
View view = (View)iterView.next();
if(this.isVerbose() == true)
System.out.println("Processing view: " + view.getName());
if(m_bDMLonly == false)
{
////////////////////////////////////////////
//////////////////
// Create the View
try
{
view.create(collTypeMaps);
if(this.isQuiet() == false)
System.out.println("Created View: " +
view.getName());
this.m_lCreatedViews ++;
}
catch (SQLException e) {
if(this.isQuiet() == false)
{
System.out.println("Error: " + "Cannot create View.");
JDBC.printSQLException(e);
if(this.isVerbose() == true)
e.printStackTrace();
}
}
}
}
// }
// }
//////////////////////////////////////////////////////////////
// Print Results
if(this.isQuiet() == false)
{
DecimalFormat fmt = new DecimalFormat("#,###");
System.out.println();
System.out.println(fmt.format(this.m_lCreatedTables) + " tables created succesfully.");
System.out.println(fmt.format(this.m_lCreatedViews) + " views created succesfully.");
System.out.println(fmt.format(this.m_lCreatedIndexes) + " indexes created successfully.");
System.out.println(fmt.format(this.m_lFailedTables) + " tables failed to create.");
System.out.println(fmt.format(this.m_lFailedIndexes) + " indexes failed to create.");
}
} catch(SAXException e) {
e.printStackTrace();
throw new IOException(e.getMessage());
} finally {
if ( m_log != null ) {
try { m_log.close(); } catch ( Exception e ) {}
}
try {
if(m_conn != null) m_conn.close();
} catch(SQLException e) {}
}
return true;
}
public boolean clear(String file, String database, String username,
String password)
throws ClassNotFoundException, IOException, SQLException
{
return this.clear(file, database, username, password, null);
}
public boolean clear(String file, String database, String username,
String password, String table)
throws ClassNotFoundException, IOException, SQLException
{
boolean bProceed = false;
Statement stmt = null;
try
{
Document doc = this.readDocument(file);
////////////////////////////////////////////////////////
// Make sure we can connect to the database
m_conn = connect(database, username, password);
stmt = m_conn.createStatement();
////////////////////////////////////////////////////////
// Verify that the user wants to do this.
if(this.isQuiet() == false && (!this.isNoninteractive()) )
{
System.out.print("DBSetup will permanently delete data. " +
"DO YOU WANT TO PROCEED? (Y/N): ");
if(Character.toUpperCase((char)System.in.read()) == 'Y')
{
System.out.println();
bProceed = true;
}
else
System.out.println("Aborted.");
}
else bProceed = true; // If they go quiet, delete without asking.
if(bProceed == true)
{
// remove data from tables in reverse order of their creation
// to bypass dependency constraints
StrongCollection tables = (StrongCollection)
Table.getTables(doc.getFirstChild(),
JDBC.toType(database),
this);
tables.reverse();
Iterator iterTab = tables.iterator();
while(iterTab.hasNext() == true)
{
Table tab = (Table)iterTab.next();
if(table != null &&
tab.getName().compareToIgnoreCase(table) != 0)
continue;
try
{
tab.clear();
if(this.isQuiet() == false)
System.out.println("Clear Table: " + tab.getName());
this.m_lCreatedTables ++;
}
catch(SQLException e)
{
if(this.isQuiet() == false)
{
System.out.println("Error: Cannot clear table " +
tab.getName());
JDBC.printSQLException(e);
}
this.m_lFailedTables ++;
}
}
}
//////////////////////////////////////////////////////////////
// Print Results
if(this.isQuiet() == false)
{
DecimalFormat fmt = new DecimalFormat("#,###");
System.out.println();
System.out.println(fmt.format(this.m_lCreatedTables) +
" tables cleared succesfully.");
System.out.println(fmt.format(this.m_lFailedTables) +
" tables failed to clear.");
}
} catch(SAXException e) {
throw new IOException(e.getMessage());
} finally {
try {
if(stmt != null) stmt.close();
if(m_conn != null) m_conn.close();
} catch(SQLException e) {}
}
return true;
}
public boolean uninstall(String file, String database, String username, String password)
throws ClassNotFoundException, IOException, SQLException
{
return this.doUninstall(file, database, username, password);
}
public boolean uninstall(InputStream is, String database, String username, String password)
throws ClassNotFoundException, IOException, SQLException
{
return this.doUninstall(is, database, username, password);
}
protected boolean doUninstall(Object source, String database, String username, String password)
throws ClassNotFoundException, IOException, SQLException
{
boolean bProceed = false;
Statement stmt = null;
try
{
///////////////////////////////////////////////////////////////////
// Open the log file if we are supposed to log SQL statements.
if ( m_logFileName != null ) {
m_log = new FileWriter(m_logFileName, m_logAppend);
}
Document doc = null;
if (source instanceof String) {
doc = this.readDocument((String) source);
} else if (source instanceof InputStream) {
doc = this.readDocument((InputStream) source);
}
////////////////////////////////////////////////////////
// Make sure we can connect to the database
m_conn = connect(database, username, password);
stmt = m_conn.createStatement();
////////////////////////////////////////////////////////
// Verify that the user wants to do this.
if(this.isQuiet() == false && (!this.isNoninteractive()) )
{
System.out.print("DBSetup will permanently drop tables and data. DO YOU WANT TO PROCEED? (Y/N): ");
if(Character.toUpperCase((char)System.in.read()) == 'Y')
{
System.out.println();
bProceed = true;
}
else
System.out.println("Aborted.");
}
else bProceed = true; // If they go quiet, delete without asking.
if(bProceed == true)
{
// drop the views first
StrongCollection views = (StrongCollection)
View.getViews(doc.getFirstChild(),
JDBC.toType(database),
this);
Iterator iterTab = views.iterator();
while(iterTab.hasNext() == true)
{
View view = (View)iterTab.next();
try
{
view.drop();
if(this.isQuiet() == false)
System.out.println("Dropped View: " +
view.getName());
this.m_lCreatedViews ++;
}
catch(SQLException e)
{
if(this.isQuiet() == false)
{
System.out.println("Error: Cannot drop view " +
view.getName());
JDBC.printSQLException(e);
}
this.m_lFailedViews ++;
}
}
// Post Processing
View.uninstallCleanup(this);
// remove tables in reverse order of their creation
// to bypass dependency constraints
StrongCollection tables = (StrongCollection)
Table.getTables(doc.getFirstChild(),
JDBC.toType(database),
this);
tables.reverse();
iterTab = tables.iterator();
while(iterTab.hasNext() == true)
{
Table tab = (Table)iterTab.next();
try
{
tab.drop();
if(this.isQuiet() == false)
System.out.println("Dropped Table: " + tab.getName());
this.m_lCreatedTables ++;
}
catch(SQLException e)
{
if(this.isQuiet() == false)
{
System.out.println("Error: " + "Cannot drop table " + tab.getName());
JDBC.printSQLException(e);
}
this.m_lFailedTables ++;
}
}
// Post Processing
Table.uninstallCleanup(this);
}
//////////////////////////////////////////////////////////////
// Print Results
if(this.isQuiet() == false)
{
DecimalFormat fmt = new DecimalFormat("#,###");
System.out.println();
System.out.println(fmt.format(this.m_lCreatedViews) +
" views dropped succesfully.");
System.out.println(fmt.format(this.m_lFailedViews) +
" views failed to drop.");
System.out.println(fmt.format(this.m_lCreatedTables) +
" tables dropped succesfully.");
System.out.println(fmt.format(this.m_lFailedTables) +
" tables failed to drop.");
//System.out.println(fmt.format(this.m_lCreatedIndexes) + " indexes dropped successfully.");
//System.out.println(fmt.format(this.m_lFailedIndexes) + " indexes failed to drop.");
}
} catch(SAXException e) {
throw new IOException(e.getMessage());
} finally {
if ( m_log != null ) {
try { m_log.close(); } catch ( Exception e ) {}
}
try {
if(stmt != null) stmt.close();
if(m_conn != null) m_conn.close();
} catch(SQLException e) {}
}
return true;
}
public boolean validate(String file, String database, String username, String password) throws ClassNotFoundException, IOException, SQLException
{
try
{
Document doc = this.readDocument(file);
////////////////////////////////////////////////////////
// Make sure we can connect to the database
m_conn = connect(database, username, password);
DatabaseMetaData meta = m_conn.getMetaData();
Iterator iterTab = Table.getTables(doc.getFirstChild(), JDBC.toType(database), this).iterator();
while(iterTab.hasNext() == true)
{
Table tab = (Table)iterTab.next();
try
{
ResultSet set = meta.getTables(null, null, tab.getName(), null);
if(set.next() == true)
{
if(this.isQuiet() == false)
System.out.println("Found Table : " + tab.getName());
// Check the Columns
Iterator iterCol = tab.getColumns().iterator();
while(iterCol.hasNext() == true)
{
Column col = (Column)iterCol.next();
set = meta.getColumns(null, null, tab.getName(), col.getName());
if(set.next() == true)
{
if(this.isQuiet() == false)
System.out.println("Found Column: " + col.getName());
}
}
this.m_lCreatedTables ++;
}
}
catch(SQLException e)
{
if(this.isQuiet() == false)
{
System.out.println("Error: " + "Cannot find table " + tab.getName());
JDBC.printSQLException(e);
}
this.m_lFailedTables ++;
}
}
//////////////////////////////////////////////////////////////
// Print Results
if(this.isQuiet() == false)
{
DecimalFormat fmt = new DecimalFormat("#,###");
System.out.println();
System.out.println(fmt.format(this.m_lCreatedTables) + " tables validated.");
System.out.println(fmt.format(this.m_lFailedTables) + " tables failed to validate.");
System.out.println(fmt.format(this.m_lCreatedIndexes) + " indexes validated.");
System.out.println(fmt.format(this.m_lFailedIndexes) + " indexes failed to validate.");
}
} catch(SAXException e) {
throw new IOException(e.getMessage());
} finally {
try {
if(m_conn != null) m_conn.close();
} catch(SQLException e) {}
}
return true;
}
/**
* Retrieves whether status messages will be printed to System.out.
*
* @return boolean
* true if status messages will be printed, false otherwise.
*/
public boolean isQuiet()
{
return this.m_bQuiet;
}
/**
* Sets whether status messages will be printed to System.out.
*
* @param quiet
* true if status messages should be printed, false otherwise.
*/
public void setQuiet(boolean quiet)
{
this.m_bQuiet = quiet;
}
/**
* Retrieves whether questions should be asked on stdin.
*
* @return boolean
* true if questions will be asked, false otherwise.
*/
public boolean isNoninteractive()
{
return this.m_bNoninteractive;
}
/**
* Sets whether questions should be asked on stdin.
*
* @param noninteractive
* true if questions should be asked, false otherwise.
*/
public void setNoninteractive(boolean noninteractive)
{
this.m_bNoninteractive = noninteractive;
}
/**
* Retrieves whether status messages will be printed to System.out.
*
* @return boolean
* true if status messages will be printed, false otherwise.
*/
public boolean isVerbose()
{
return this.m_bVerbose;
}
/**
* Sets whether status messages will be printed to System.out.
*
* @param quiet
* true if status messages should be printed, false otherwise.
*/
public void setVerbose(boolean quiet)
{
this.m_bVerbose = quiet;
}
private class ErrorHandler implements org.xml.sax.ErrorHandler
{
public void fatalError(SAXParseException e) throws SAXException
{
System.out.println("Fatal Error: " + e);
}
public void error(SAXParseException e) throws SAXException
{
System.out.println("Error: " + e);
}
public void warning(SAXParseException e) throws SAXException
{
System.out.println("Warning: " + e);
}
}
protected void doSQL(String cmd) throws SQLException
{
this.doSQL(cmd, false);
}
/**
* Thou shalt be responsible for .close()'ing the returned prepared
* statement when they're through, lest they suffer a cursor flood
*/
protected Statement doSQL(String cmd, boolean bPrepared) throws SQLException
{
Statement stmt;
// Cache the original commit option
boolean committing = this.getConn().getAutoCommit();
if (committing)
this.getConn().setAutoCommit(false);
if(bPrepared == true)
stmt = this.getConn().prepareStatement(cmd);
else
stmt = this.getConn().createStatement();
if( m_bVerbose )
System.out.println("Command: " + cmd);
if ( bPrepared == false ) {
try {
stmt.executeUpdate(cmd);
this.getConn().commit();
} catch (SQLException e) {
try { this.getConn().rollback(); }
catch (Exception e2) {
// Log this?
}
throw e;
} finally {
if (stmt != null) stmt.close();
}
}
// Reset the commit option
this.getConn().setAutoCommit(committing);
return stmt;
}
protected Connection getConn () { return m_conn; }
public void setTypeMapFile ( String tmapFile ) {
m_typeMapFile = tmapFile;
}
public void setTypeMapStream ( InputStream is ) {
m_typeMapStream = is;
}
private Connection connect (String database,
String user, String password)
throws ClassNotFoundException, SQLException {
return connect(null, database, user, password);
}
private Connection connect (String driver, String database,
String user, String password)
throws ClassNotFoundException, SQLException {
if ( driver == null ) {
driver = JDBC.getDriverString(database);
}
JDBC.loadDriver(driver);
Connection conn = DriverManager.getConnection(database, user, password);
// mysql complains if autocomit is true and you try to commit...
// ddl operations are not transactional anyhow.
conn.setAutoCommit(false);
return conn;
}
public void init (boolean verbose, boolean sqlonly) {}
// The implementation of the Statement and PreparedStatement classes
// in the org.hyperic.util.jdbc.log package will callback this method
// when they have SQL to execute.
public void logSQL ( String sql ) {
if ( m_log != null ) {
try {
m_log.write(sql + ";\n");
m_log.flush();
} catch ( Exception e ) {
System.err.println("DBSetup: ERROR writing to log file: " + e);
}
}
}
protected int getDbType() {
int iResult = -1;
try {
iResult = JDBC.toType(this.getConn().getMetaData().getURL());
}
catch(SQLException e) {}
return iResult;
}
}