/// <summary>
        /// Saves the published page collection, represented as XML, to the database.
        /// </summary>
        /// <param name="doc">An XML document containing the published page collection
        ///			to save to the database.</param>
        public void SavePublishInfo(
            PublishedPageCollection	pageInfo)
        {
            SqlConnection	conn	= null;
            SqlCommand		cmd		= null;
            SqlTransaction	trans	= null;
            XmlDocument		doc		= pageInfo.ToXml();

            #if (PUBLISH_TRACE)
            Stopwatch stopWatch = new Stopwatch();
            stopWatch.Start();
            #endif
            try {
            //			conn = (SqlConnection)ConnectionManager.GetConnection("PublishDAO", connType);
            PublishConfigSection config = ConfigurationManager.GetSection(
                    TritonConfigurationSection.SectionName + "/publishing") as PublishConfigSection;
            string connName = config.Settings[CONNECTION_SETTING].Value;
            conn = new SqlConnection(ConfigurationManager.ConnectionStrings[connName].ConnectionString);

            cmd = new SqlCommand();
            cmd.Connection = conn;
            conn.Open();

            #if (PUBLISH_TRACE)
            cmd.CommandText = string.Format("select count(1) from {0} where server = '{1}'",
                    TABLE_NAME, Environment.MachineName);
            int beforeCnt = (int)cmd.ExecuteScalar();
            #endif
                    //  set up the transaction
            trans = conn.BeginTransaction("SavePublishInfo");
            cmd.Transaction = trans;

                    //  ======  remove entries for this server from the publish table  =====
            cmd.CommandText = string.Format("delete from {0} where server = '{1}'", TABLE_NAME, Environment.MachineName);
            int rows = cmd.ExecuteNonQuery();
            #if (PUBLISH_TRACE)
            LogManager.GetCurrentClassLogger().DebugFormat("Deleted {0} records from {1} for server {2}.", rows, TABLE_NAME, Environment.MachineName);
            #endif

                    //  get the list of pages to be written
            XmlNodeList pageNodes = doc.DocumentElement.SelectNodes("Page");

                    //  don't bother preparing the command if there is nothing
                    //  to save
            if (pageNodes.Count > 0) {
                cmd.CommandText = "insert into " + TABLE_NAME
                        + " (start_state_id, published_state_id, [key], event, published_path, last_published_time, publisher, hits, server)"
                        + " values (@start_state_id, @published_state_id, @key, @event, @published_path, @last_published_time, @publisher, @hits, @server)";
                cmd.Parameters.Add("@start_state_id", SqlDbType.Int);
                cmd.Parameters.Add("@published_state_id", SqlDbType.Int);
                        // TODO: find better way than hard-coded field lengths
                cmd.Parameters.Add("@key", SqlDbType.NVarChar, 200);
                cmd.Parameters.Add("@event", SqlDbType.NVarChar, 200);
                cmd.Parameters.Add("@published_path", SqlDbType.NVarChar, 400);
                cmd.Parameters.Add("@last_published_time", SqlDbType.DateTime);
                cmd.Parameters.Add("@hits", SqlDbType.Int);
                cmd.Parameters.Add("@server", SqlDbType.NVarChar, 30);
                cmd.Parameters.Add("@publisher", SqlDbType.NVarChar, 200);

                cmd.Prepare();

                        //  server doesn't change per page, so set before we loop
                cmd.Parameters["@server"].Value = Environment.MachineName;

                        //  write each published page record to the DB
                foreach (XmlNode page in pageNodes) {
                    try {
                        cmd.Parameters["@start_state_id"].Value = int.Parse(page.Attributes["startState"].Value);
                        cmd.Parameters["@published_state_id"].Value = int.Parse(page.Attributes["publishedState"].Value);
                        cmd.Parameters["@key"].Value = page.Attributes["key"].Value;
                        cmd.Parameters["@event"].Value = page.Attributes["event"].Value;
                        cmd.Parameters["@published_path"].Value = page.Attributes["path"].Value;
                        cmd.Parameters["@last_published_time"].Value = page.Attributes["lastPublished"].Value;
                        cmd.Parameters["@hits"].Value = int.Parse(page.Attributes["hits"].Value);
                        cmd.Parameters["@publisher"].Value = page.Attributes["publisher"].Value;

                        cmd.ExecuteNonQuery();
                    } catch (Exception e) {
                        LogManager.GetCurrentClassLogger().Error(string.Format(
                                "SavePublishInfo - error saving page key='{0}' path='{1}' event='{2}': ",
                                page.Attributes["key"].Value,
                                page.Attributes["path"].Value,
                                page.Attributes["event"].Value), e);
                    }
                }
            }

                    //  if we got here everything went OK, so commit the changes
            trans.Commit();
            cmd.Transaction = null;

            #if (PUBLISH_TRACE)
            cmd.CommandText = string.Format("select count(1) from {0} where server = '{1}'", TABLE_NAME, Environment.MachineName);
            int afterCnt = (int)cmd.ExecuteScalar();
            LogManager.GetCurrentClassLogger().Trace(string.Format("SavePublishInfo - {0}:  before: {1}, after {2}.", Environment.MachineName, beforeCnt, afterCnt));
            #endif

            } catch (Exception e) {
            if (trans != null) {
                trans.Rollback();
            }
            LogManager.GetCurrentClassLogger().Error("SavePublishInfo", e);

            } finally {
            #if (PUBLISH_TRACE)
            stopWatch.Stop();
            LogManager.GetCurrentClassLogger().Trace(string.Format("SavePublishInfo time (for {0}) = {1}.", Environment.MachineName, stopWatch.Elapsed));
            #endif
                    //  close everything
            DbUtilities.Close(conn, cmd, null);
            }
        }
        /// <summary>
        /// Initializes the <b>PublishManager</b>.
        /// </summary>
        private void Initialize()
        {
            //  call the abstract Init to allow sub-class to perform its initialization
            //		Init();

            //  get the intervals for checking the published content list for expired
            //  content and for saving the list to persistant storage
            PublishConfigSection config = ConfigurationManager.GetSection(
                    TritonConfigurationSection.SectionName + "/publishing") as PublishConfigSection;

            if (config.Publish) {
                try {
                    this.checkInterval = long.Parse(config.Settings["expireCheckInterval"].Value);
                } catch (Exception e) {
            // TODO:
                }
                try {
                    this.saveInterval = long.Parse(config.Settings["storeInterval"].Value);
                } catch (Exception e) {
            // TODO:
                }

                //  set up the thread timers
                this.InitializeTimers();

                //  load the published page info from persistent store
                this.publishedPages = this.LoadPages();
                //  remove any expired pages from PublishedPageCollection
                this.CleanUpExpired(null);
            }
        }