/******************************************************************************** * * * (c) Copyright 2010 Verizon Communications USA and The Open University UK * * * * This software is freely distributed in accordance with * * the GNU Lesser General Public (LGPL) license, version 3 or later * * as published by the Free Software Foundation. * * For details see LGPL: http://www.fsf.org/licensing/licenses/lgpl.html * * and GPL: http://www.fsf.org/licensing/licenses/gpl-3.0.html * * * * This software is provided by the copyright holders and contributors "as is" * * and any express or implied warranties, including, but not limited to, the * * implied warranties of merchantability and fitness for a particular purpose * * are disclaimed. In no event shall the copyright owner or contributors be * * liable for any direct, indirect, incidental, special, exemplary, or * * consequential damages (including, but not limited to, procurement of * * substitute goods or services; loss of use, data, or profits; or business * * interruption) however caused and on any theory of liability, whether in * * contract, strict liability, or tort (including negligence or otherwise) * * arising in any way out of the use of this software, even if advised of the * * possibility of such damage. * * * ********************************************************************************/ package com.compendium.core.db.management; import java.io.FileNotFoundException; import java.io.IOException; import java.io.StringReader; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ConcurrentModificationException; import java.util.Enumeration; import java.util.Vector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.compendium.core.CoreUtilities; import com.compendium.core.ICoreConstants; import com.compendium.core.datamodel.Model; import com.compendium.core.datamodel.UserProfile; import com.compendium.core.db.DBSystem; /** * This class handles creating a new database, adds the default data to it and if required, a new user record. * It allows external classes to register DBProgressListeners and fires appropriate progress information to them. * This facilitates the display of progress information in a user interface, if desired. * * @author Michelle Bachler */ public class DBNewDatabase implements DBProgressListener { /** * class's own logger */ final Logger log = LoggerFactory.getLogger(getClass()); /** SQL statement to insert the default database version number into the System table of the database*/ public static final String INSERT_SYSTEM_QUERY = "INSERT INTO System (Property, Contents) VALUES ('version','"+ICoreConstants.sDATABASEVERSION+"')"; /** NOT CURRENTLY USED */ public static final String INSERT_PREFERENCE_QUERY1 = "INSERT INTO Preference (UserID, Property, Contents) VALUES (?, 'codegroup', '')"; /** NOT CURRENTLY USED */ public static final String INSERT_PREFERENCE_QUERY2 = "INSERT INTO Preference (UserID, Property, Contents) VALUES (?, 'LAF', '')"; /** NOT CURRENTLY USED */ public static final String INSERT_PREFERENCE_QUERY3 = "INSERT INTO Preference (UserID, Property, Contents) VALUES (?, 'Skin', '')"; /** NOT CURRENTLY USED */ public static final String INSERT_PREFERENCE_QUERY4 = "INSERT INTO Preference (UserID, Property, Contents) VALUES (?, 'DnDFiles', 'N')"; /** NOT CURRENTLY USED */ public static final String INSERT_PREFERENCE_QUERY5 = "INSERT INTO Preference (UserID, Property, Contents) VALUES (?, 'AudioOn', 'N')"; /** SQL statement to insert the homeview node for the newly created user*/ public final static String INSERT_NODE_QUERY = "INSERT INTO Node (NodeID, NodeType, ExtendedNodeType, OriginalID, Author, " + "CreationDate, ModificationDate, Label, Detail, CurrentStatus) "+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "; /** SQL statement to insert a new user into the new database*/ public final static String INSERT_USER_QUERY = "INSERT INTO Users (UserID, Author, CreationDate, ModificationDate, " + "Login, Name, Password, Description, " + "HomeView, IsAdministrator) "+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "; /** SQL statement to install a code to represent the newly created user name*/ public final static String INSERT_CODE_QUERY = "INSERT INTO Code (CodeID, Author, CreationDate, ModificationDate, Name, Description, Behavior) "+ "VALUES (?, ?, ?, ?, ?, ?, ?) "; /** An integer representing the increment to use for the progress updates */ private int increment = 1; /** A Vector of registered DBProgressListeners */ protected Vector progressListeners; /** The UserProfile for a new user to be added to the newly created database*/ private UserProfile userProfile = null; /** A local reference for the DBAdminDatabase object which is required to register the new database*/ private DBAdminDatabase adminDatabase = null; /** The name to use whn accessing the MySQL database */ private String sDatabaseUserName = ICoreConstants.sDEFAULT_DATABASE_USER; /** The password to use when accessing the MySQL database */ private String sDatabasePassword = ICoreConstants.sDEFAULT_DATABASE_PASSWORD; /** The password to use when accessing the MySQL database */ private String sDatabaseIP = ICoreConstants.sDEFAULT_DATABASE_ADDRESS; /** Indicates if one or more external resources being backed up could not be found*/ private boolean bNotFound = false; /** The given user is the default user for this new database*/ private boolean isDefaultUser = false; /** The type of the databasse application to create an empty database for.*/ private int nDatabaseType = -1; /** * This constructor takes a name and password to use when accessing the database, * and the IP address of the server machine. * * @param nDatabaseType, the type of the database being used (e.g, MySQL, Derby). * @param DBAdminDatabase admin, a reference to the administration database so that the new database can be registered. * @param sDatabaseUserName, the name to use when creating the connection to the database * @param sDatabasePassword, the password to use when connection to the database * @param sDatabaseIP, the IP address of the server machine. The default if 'localhost'. */ public DBNewDatabase(int nDatabaseType, DBAdminDatabase admin, String sDatabaseUserName, String sDatabasePassword, String sDatabaseIP) { progressListeners = new Vector(); this.adminDatabase = admin; this.sDatabaseUserName = sDatabaseUserName; this.sDatabasePassword = sDatabasePassword; this.nDatabaseType = nDatabaseType; if (sDatabaseIP != null && !sDatabaseIP.equals("")) { this.sDatabaseIP = sDatabaseIP; } } /** * Constructor, takes the user profile to add to the newly created database. * This constructor takes a name and password to use when accessing the database, * and the IP address of the server machine. * * @param nDatabaseType, the type of the database being used (e.g, MySQL, Derby). * @param DBAdminDatabase admin, a reference to the administration database so that the nwe database can be registered. * @param UserProile up, the UserProfile of a new user to be added to the newly created database. * @param sDatabaseUserName, the name to use when creating the connection to the database * @param sDatabasePassword, the password to use when connection to the database * @param sDatabaseIP, the IP address of the server machine. The default if 'localhost'. */ public DBNewDatabase(int nDatabaseType, DBAdminDatabase admin, UserProfile up, boolean isDefaultUser, String sDatabaseUserName, String sDatabasePassword, String sDatabaseIP) { progressListeners = new Vector(); userProfile = up; this.isDefaultUser = isDefaultUser; this.adminDatabase = admin; this.sDatabaseUserName = sDatabaseUserName; this.sDatabasePassword = sDatabasePassword; this.nDatabaseType = nDatabaseType; if (sDatabaseIP != null && !sDatabaseIP.equals("")) { this.sDatabaseIP = sDatabaseIP; } } /** * Create a new database, and then load the default data. * If a user was specified in the constructor, add the new user details to the new database. * * @param String sFriendlyName, the name of the database as seen by a Compendium user. * This name is 'cleaned' to remove illegal characters and a time/date stamp is addded. * @exception java.sql.SQLException * @exception java.io.IOException * @exception java.io.FileNotFoundLException * @exception java.lang.ClassNotFoundException * @exception DBProjectListException, thrown if the list of projects could not be loaded from the database. * @see com.compendium.core.CoreUtilities#cleanDatabaseName * @return the id of the users home view for this new project - so default data can be loaded. */ public String createNewDatabase(String sFriendlyName) throws DBDatabaseNameException, DBDatabaseTypeException, ClassNotFoundException, IOException, SQLException, FileNotFoundException, DBProjectListException { String sHomeViewID = ""; String sCleanName = CoreUtilities.cleanDatabaseName(sFriendlyName); DBEmptyDatabase empty = new DBEmptyDatabase(nDatabaseType, adminDatabase, sDatabaseUserName, sDatabasePassword, sDatabaseIP); empty.addProgressListener(this); Connection connection = null; empty.createEmptyDatabase(sCleanName); connection = DBConnectionManager.getPlainConnection(nDatabaseType, sCleanName, sDatabaseUserName, sDatabasePassword, sDatabaseIP); if (connection == null) { throw new DBDatabaseTypeException("Database type "+nDatabaseType+" not found"); } // UPDATE THE DATABASE VERSION PreparedStatement pstmt = connection.prepareStatement(INSERT_SYSTEM_QUERY); pstmt.executeUpdate(); pstmt.close(); fireProgressUpdate(increment, "Finished"); fireProgressComplete(); adminDatabase.addNewDatabase(sFriendlyName, sCleanName); if (userProfile != null) { sHomeViewID = insertNewUser(connection); if (isDefaultUser) { //log.info("About to add default user as"+userProfile.getId()); DBSystem.setDefaultUser(new DBConnection(connection, true, nDatabaseType), userProfile.getId()); } } try { connection.close(); } catch(ConcurrentModificationException io) { log.info("Exception closing connection for new database:\n\n"+io.getMessage()); } return sHomeViewID; } /** * If new user details where passed into the contructor, set up the new user and their home page. * * @param Connection con, the connection to use to write the new user information to the database. * @exception java.sql.SQLException */ private String insertNewUser(Connection con) throws SQLException { if (con == null) throw new SQLException("A database connection could not be established to create the new user."); String name = userProfile.getUserName(); java.util.Date date = new java.util.Date(); String homeViewId = Model.getStaticUniqueID(); PreparedStatement pstmt = con.prepareStatement(INSERT_NODE_QUERY); pstmt.setString(1, homeViewId) ; pstmt.setInt(2, ICoreConstants.MAPVIEW); pstmt.setString(3, "") ; pstmt.setString(4, ""); pstmt.setString(5, name); pstmt.setDouble(6, new Long(date.getTime()).doubleValue()); pstmt.setDouble(7, new Long(date.getTime()).doubleValue()); // ACCOMODATES UNICODE String sLabel = new String("Home Window"); StringReader reader = new StringReader(sLabel); pstmt.setCharacterStream(8, reader, sLabel.length()); // ACCOMODATES UNICODE sLabel = new String("Home Window of " + name); reader = new StringReader(sLabel); pstmt.setCharacterStream(9, reader, sLabel.length()); pstmt.setInt(10, ICoreConstants.STATUS_ACTIVE); int nRowCount = pstmt.executeUpdate(); pstmt.close(); if (nRowCount >0) { pstmt = con.prepareStatement(INSERT_CODE_QUERY); pstmt.setString(1, Model.getStaticUniqueID()); pstmt.setString(2, name) ; pstmt.setDouble(3, new Long(date.getTime()).doubleValue()); pstmt.setDouble(4, new Long(date.getTime()).doubleValue()); pstmt.setString(5, name) ; pstmt.setString(6, "No Description"); pstmt.setString(7, "No Behavior") ; nRowCount = pstmt.executeUpdate(); // close pstmt to save resources pstmt.close() ; if (nRowCount > 0) { pstmt = con.prepareStatement(INSERT_USER_QUERY); String id = Model.getStaticUniqueID(); userProfile.setId(id); String login = userProfile.getLoginName(); String desc = userProfile.getUserDescription(); String password = userProfile.getPassword(); String admin = "N"; if (userProfile.isAdministrator()) admin = "Y"; pstmt.setString(1, id); pstmt.setString(2, name); pstmt.setDouble(3, new Long(date.getTime()).doubleValue()); pstmt.setDouble(4, new Long(date.getTime()).doubleValue()); pstmt.setString(5, login); pstmt.setString(6, name); pstmt.setString(7, password); pstmt.setString(8, desc); pstmt.setString(9, homeViewId); pstmt.setString(10, admin); nRowCount = pstmt.executeUpdate(); pstmt.close(); } } return homeViewId; } // IMPLEMENT PROGRESS LISTENER /** * Set the amount of progress items being counted. * * @param int nCount, the amount of progress items being counted. */ public void progressCount(int nCount) { fireProgressCount(nCount); } /** * Indicate that progress has been updated. * * @param int nIncrement, the current position of the progress in relation to the inital count * @param String sMessage, the message to display to the user */ public void progressUpdate(int nIncrement, String sMessage) { fireProgressUpdate(nIncrement, sMessage); } /** * Indicate that progress has complete. */ public void progressComplete() { fireProgressComplete(); } /** * Indicate that progress has had a problem. * * @param String sMessage, the message to display to the user. */ public void progressAlert(String sMessage) { fireProgressAlert(sMessage); } // PROGRESS LISTENER EVENTS /** * Adds <code>DBProgressListener</code> to listeners notified when progress events happen. * * @see #removeProgressListener * @see #removeAllProgressListeners * @see #fireProgressCount * @see #fireProgressUpdate * @see #fireProgressComplete * @see #fireProgressAlert */ public void addProgressListener(DBProgressListener listener) { if (listener == null) return; if (!progressListeners.contains(listener)) { progressListeners.addElement(listener); } } /** * Removes <code>DBProgressListener</code> from listeners notified of progress events. * * @see #addProgressListener * @see #removeAllProgressListeners * @see #fireProgressCount * @see #fireProgressUpdate * @see #fireProgressComplete * @see #fireProgressAlert */ public void removeProgressListener(DBProgressListener listener) { if (listener == null) return; progressListeners.removeElement(listener); } /** * Removes all listeners notified about progress events. * * @see #addProgressListener * @see #removeProgressListener * @see #fireProgressCount * @see #fireProgressUpdate * @see #fireProgressComplete * @see #fireProgressAlert */ public void removeAllProgressListeners() { progressListeners.clear(); } /** * Notifies progress listeners of the total count of progress events. * * @see #fireProgressUpdate * @see #fireProgressComplete * @see #fireProgressAlert * @see #addProgressListener * @see #removeProgressListener * @see #removeAllProgressListeners */ protected void fireProgressCount(int nCount) { for (Enumeration e = progressListeners.elements(); e.hasMoreElements(); ) { DBProgressListener listener = (DBProgressListener) e.nextElement(); listener.progressCount(nCount); } } /** * Notifies progress listeners about progress change. * * @see #fireProgressCount * @see #fireProgressComplete * @see #fireProgressAlert * @see #addProgressListener * @see #removeProgressListener * @see #removeAllProgressListeners */ protected void fireProgressUpdate(int nIncrement, String sMessage) { for (Enumeration e = progressListeners.elements(); e.hasMoreElements(); ) { DBProgressListener listener = (DBProgressListener) e.nextElement(); listener.progressUpdate(nIncrement, sMessage); } } /** * Notifies progress listeners about progress completion. * * @see #fireProgressCount * @see #fireProgressUpdate * @see #fireProgressAlert * @see #addProgressListener * @see #removeProgressListener * @see #removeAllProgressListeners */ protected void fireProgressComplete() { for (Enumeration e = progressListeners.elements(); e.hasMoreElements(); ) { DBProgressListener listener = (DBProgressListener) e.nextElement(); listener.progressComplete(); } } /** * Notifies progress listeners about progress alert. * * @see #fireProgressCount * @see #fireProgressUpdate * @see #fireProgressComplete * @see #addProgressListener * @see #removeProgressListener * @see #removeAllProgressListeners * @see #removeAllProgressListeners */ protected void fireProgressAlert(String sMessage) { for (Enumeration e = progressListeners.elements(); e.hasMoreElements(); ) { DBProgressListener listener = (DBProgressListener) e.nextElement(); listener.progressAlert(sMessage); } } }