Exemplo n.º 1
0
        public void VerifyDeleteRemovesDatabaseFiles()
        {
            const string DictionaryLocation = "DictionaryToDelete";
            var          dict = new PersistentDictionary <ulong, bool>(DictionaryLocation);

            dict.Dispose();
            Assert.IsTrue(PersistentDictionaryFile.Exists(DictionaryLocation));
            PersistentDictionaryFile.DeleteFiles(DictionaryLocation);
            Assert.IsFalse(PersistentDictionaryFile.Exists(DictionaryLocation));
            Directory.Delete(DictionaryLocation, false);
        }
Exemplo n.º 2
0
 public static PersistentDictionary <string, string> Instance()
 {
     if (instance == null)
     {
         if (PersistentDictionaryFile.Exists("Property"))
         {
             PersistentDictionaryFile.DeleteFiles("Property");
         }
         instance = new PersistentDictionary <string, string>("Property");
     }
     return(instance);
 }
Exemplo n.º 3
0
        public void VerifyDeleteSucceedsWhenDirectoryIsEmpty()
        {
            const string TestDirectory = "testdirectory";

            if (Directory.Exists(TestDirectory))
            {
                Directory.Delete(TestDirectory);
            }

            Directory.CreateDirectory(TestDirectory);
            PersistentDictionaryFile.DeleteFiles(TestDirectory);
            Directory.Delete(TestDirectory);
        }
        //
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion

        /// <summary>
        ///A test for PersistentMemoryCache`1 Constructor
        ///</summary>
        public void PersistentMemoryCacheTestHelper <T>(T testValue)
        {
            Random rand    = new Random(DateTime.Now.Millisecond);
            string name    = Path.Combine(Path.GetTempPath(), "MLifterCacheTest_" + rand.Next(100, 10000));
            string testKey = "test";

            if (PersistentDictionaryFile.Exists(Path.Combine(name, "values")) || PersistentDictionaryFile.Exists(Path.Combine(name, "lifetime")))
            {
                Assert.Fail("Cache already exisits");
            }

            Directory.CreateDirectory(name);
            using (PersistentMemoryCache <T> target = new PersistentMemoryCache <T>(name))
            {
                target.Add(testKey, testValue, DateTime.Now.AddDays(1));
                Assert.AreEqual(target[testKey], testValue, "Value not saved!");
                target.Remove(testKey);
                Assert.IsNull(target[testKey], "Value not removed!");

                target.Add(testKey, testValue, DateTime.Now.AddDays(1));
                target.Dispose();
            }

            using (PersistentMemoryCache <T> reload = new PersistentMemoryCache <T>(name))
            {
                Assert.AreEqual(reload[testKey], testValue, "Reloaded value not restored!");
                reload.Remove(testKey);
                Assert.IsNull(reload[testKey], "Reloaded value not removed!");
                reload.Dispose();
            }

            using (PersistentMemoryCache <T> reload = new PersistentMemoryCache <T>(name))
            {
                Assert.IsNull(reload[testKey], "Reloaded value not null!");

                reload.Add(testKey, testValue, DateTime.Now.AddMilliseconds(50));
                Assert.AreEqual(reload[testKey], testValue, "Timeout to low!");
                Thread.Sleep(75);
                Assert.IsNull(reload[testKey], "Expired value not null!");

                reload.Dispose();
            }

            PersistentDictionaryFile.DeleteFiles(Path.Combine(name, "values"));
            PersistentDictionaryFile.DeleteFiles(Path.Combine(name, "lifetime"));
            if (PersistentDictionaryFile.Exists(Path.Combine(name, "values")) || PersistentDictionaryFile.Exists(Path.Combine(name, "lifetime")))
            {
                Assert.Fail("Cache not deleted!");
            }
        }
Exemplo n.º 5
0
 public DatabaseResolver(string workingDir)
 {
     if (!String.IsNullOrEmpty(workingDir) &&
         Directory.Exists(workingDir))
     {
         _isExisted = PersistentDictionaryFile.Exists(workingDir);
         if (_isExisted)
         {
             _dataDir          = workingDir;
             _databaseMsdnUrls =
                 new PersistentDictionary <string, string>(workingDir);
         }
     }
 }
Exemplo n.º 6
0
        public void VerifyDeleteLeavesUnrelatedFiles()
        {
            const string TestDirectory = "testdirectory";
            string       testFile      = Path.Combine(TestDirectory, "myfile.log");

            if (Directory.Exists(TestDirectory))
            {
                Directory.Delete(TestDirectory);
            }

            Directory.CreateDirectory(TestDirectory);
            File.WriteAllText(testFile, "hello world");
            PersistentDictionaryFile.DeleteFiles(TestDirectory);
            Assert.IsTrue(File.Exists(testFile));
            Cleanup.DeleteDirectoryWithRetry(TestDirectory);
        }
Exemplo n.º 7
0
        public void VerifyDeleteRemovesReservedLogs()
        {
            const string DictionaryLocation = "DictionaryToDelete";
            const string ReservedLog        = @"DictionaryToDelete\res1.log";
            var          dict = new PersistentDictionary <ulong, bool>(DictionaryLocation);

            dict.Dispose();
            if (!File.Exists(ReservedLog))
            {
                File.WriteAllText(ReservedLog, "VerifyDeleteRemovesDatabaseFiles");
            }

            Assert.IsTrue(PersistentDictionaryFile.Exists(DictionaryLocation));
            PersistentDictionaryFile.DeleteFiles(DictionaryLocation);
            Assert.IsFalse(PersistentDictionaryFile.Exists(DictionaryLocation));
            Directory.Delete(DictionaryLocation, false);
        }
Exemplo n.º 8
0
        /// <summary>
        /// Create and modify a generic dictionary.
        /// </summary>
        /// <typeparam name="TKey">The key type for the dictionary.</typeparam>
        /// <typeparam name="TValue">The value type for the dictionary.</typeparam>
        private static void TestGenericDictionary <TKey, TValue>() where TKey : IComparable <TKey>
        {
            using (var dictionary = new PersistentDictionary <TKey, TValue>(DictionaryPath))
            {
                TKey   key   = default(TKey);
                TValue value = default(TValue);
                RunDictionaryTests(dictionary, key, value);
            }

            // Reopen the database
            using (var dictionary = new PersistentDictionary <TKey, TValue>(DictionaryPath))
            {
            }

            // Delete the database
            Assert.IsTrue(PersistentDictionaryFile.Exists(DictionaryPath), "Dictionary should exist");
            PersistentDictionaryFile.DeleteFiles(DictionaryPath);
            Assert.IsFalse(PersistentDictionaryFile.Exists(DictionaryPath), "Dictionary should have been deleted");
        }
Exemplo n.º 9
0
        public void Initialize(string workingDir, bool createNotFound)
        {
            if (String.IsNullOrEmpty(workingDir) || _indexedDocument != null)
            {
                return;
            }

            if (Directory.Exists(workingDir))
            {
                _isExisted = PersistentDictionaryFile.Exists(workingDir);
                if (_isExisted)
                {
                    _indexedDataDir  = workingDir;
                    _indexedDocument = new PersistentDictionary <string, string>(_indexedDataDir);

                    _isInitialized = true;
                }
                else
                {
                    if (createNotFound)
                    {
                        _indexedDataDir  = workingDir;
                        _indexedDocument = new PersistentDictionary <string, string>(_indexedDataDir);

                        _isInitialized = true;
                    }
                }
            }
            else
            {
                if (createNotFound)
                {
                    Directory.CreateDirectory(workingDir);

                    _indexedDataDir  = workingDir;
                    _indexedDocument = new PersistentDictionary <string, string>(_indexedDataDir);

                    _isInitialized = true;
                }
            }
        }
        public void TestCloseAndDelete()
        {
            var rand = new Random();

            for (int i = 0; i < 64; ++i)
            {
                string k = rand.NextDouble().ToString();
                string v = rand.Next().ToString();
                this.expected.Add(k, v);
                this.actual.Add(k, v);
            }

            this.actual.Dispose();
            PersistentDictionaryFile.DeleteFiles(DictionaryLocation);

            // Deleting the files clears the dictionary
            this.expected.Clear();

            this.actual = new PersistentDictionary <string, string>(DictionaryLocation);
            DictionaryAssert.AreSortedAndEqual(this.expected, this.actual);
        }
Exemplo n.º 11
0
        /// <summary>
        /// Create and modify a generic dictionary.
        /// </summary>
        /// <typeparam name="TKey">The key type for the dictionary.</typeparam>
        /// <typeparam name="TValue">The value type for the dictionary.</typeparam>
        private static void TestNullableGenericDictionary <TKey, TValue>() where TKey : IComparable <TKey> where TValue : struct
        {
            // Test the version with a nullable value. Use both null and non-null values.
            using (var dictionary = new PersistentDictionary <TKey, TValue?>(DictionaryPath))
            {
                RunDictionaryTests(dictionary, default(TKey), default(TValue));
                dictionary.Clear();
                RunDictionaryTests(dictionary, default(TKey), default(TValue?));
            }

            PersistentDictionaryFile.DeleteFiles(DictionaryPath);

            using (var dictionary = new PersistentDictionary <TKey, TValue>(DictionaryPath))
            {
                TKey   key   = default(TKey);
                TValue value = default(TValue);
                RunDictionaryTests(dictionary, key, value);
            }

            // Reopen the database
            Dictionary <TKey, TValue> temp;

            using (var dictionary = new PersistentDictionary <TKey, TValue>(DictionaryPath))
            {
                temp = new Dictionary <TKey, TValue>(dictionary);
            }

            // Delete the database
            Assert.IsTrue(PersistentDictionaryFile.Exists(DictionaryPath), "Dictionary should exist");
            PersistentDictionaryFile.DeleteFiles(DictionaryPath);
            Assert.IsFalse(PersistentDictionaryFile.Exists(DictionaryPath), "Dictionary should have been deleted");

            // Recreate the database
            using (var dictionary = new PersistentDictionary <TKey, TValue>(temp, DictionaryPath))
            {
                DictionaryAssert.AreEqual(temp, dictionary);
            }

            PersistentDictionaryFile.DeleteFiles(DictionaryPath);
        }
Exemplo n.º 12
0
        public static void MigratePrevServerGroups(string name)
        {
            lock (MigratePrevServerGroupsLock)
            {
                var directory = string.Format(@"{0}\{1}\PrevServerGroups", BasicHelper.DataDirectory, name);
                if (PersistentDictionaryFile.Exists(directory))
                {
                    LogService.Debug("Start migrating 'PrevServerGroups' data.");

                    var oldDictionary = new PersistentDictionary <uint, string>(directory);

                    using (var database = new BotDatabaseEntities(GetInstanceConnectionString(name)))
                    {
                        foreach (var oldDictionaryEntry in oldDictionary)
                        {
                            oldDictionaryEntry.Value.Split(';').Select(int.Parse).ForEach(oldServerGroup =>
                            {
                                database.PreviousServerGroup.AddObject(new PreviousServerGroup
                                {
                                    Id = Guid.NewGuid(),
                                    ClientDatabaseId = (int)oldDictionaryEntry.Key,
                                    ServerGroup      = oldServerGroup,
                                    Creation         = DateTime.UtcNow
                                });
                            });
                        }

                        database.SaveChanges();
                    }

                    oldDictionary.Flush();
                    oldDictionary.Dispose();

                    PersistentDictionaryFile.DeleteFiles(directory);
                    Directory.Delete(directory);

                    LogService.Debug("Finished migrating 'PrevServerGroups' data.");
                }
            }
        }
Exemplo n.º 13
0
        public bool ImportFromXml(string xmlFile, bool deleteExiting)
        {
            if (String.IsNullOrEmpty(_workingDir) ||
                !Directory.Exists(_workingDir))
            {
                return(false);
            }
            if (!Directory.Exists(_workingDir))
            {
                Directory.CreateDirectory(_workingDir);
            }

            if (deleteExiting && PersistentDictionaryFile.Exists(_workingDir))
            {
                PersistentDictionaryFile.DeleteFiles(_workingDir);
            }

            PersistentDictionary <string, string> linkDatabase =
                new PersistentDictionary <string, string>(_workingDir);

            return(true);
        }
Exemplo n.º 14
0
        public static void MigrateModerates(string name)
        {
            lock (MigrateModeratesLock)
            {
                var directory = string.Format(@"{0}\{1}\Moderates", BasicHelper.DataDirectory, name);
                if (PersistentDictionaryFile.Exists(directory))
                {
                    LogService.Debug("Start migrating 'Moderates' data.");

                    var oldDictionary = new PersistentDictionary <string, ModeratedClientEntity>(directory);

                    using (var database = new BotDatabaseEntities(GetInstanceConnectionString(name)))
                    {
                        foreach (var oldDictionaryEntry in oldDictionary)
                        {
                            database.Moderate.AddObject(new Moderate
                            {
                                Id = Guid.NewGuid(),
                                ClientDatabaseId    = (int)oldDictionaryEntry.Value.User,
                                ModeratorDatabaseId = (int)oldDictionaryEntry.Value.Moderator,
                                ServerGroup         = (int)oldDictionaryEntry.Value.ServerGroup,
                                Type     = (byte)oldDictionaryEntry.Value.Type,
                                Creation = oldDictionaryEntry.Value.Moderated
                            });
                        }

                        database.SaveChanges();
                    }

                    oldDictionary.Flush();
                    oldDictionary.Dispose();

                    PersistentDictionaryFile.DeleteFiles(directory);
                    Directory.Delete(directory);

                    LogService.Debug("Finished migrating 'Moderates' data.");
                }
            }
        }
Exemplo n.º 15
0
        public void Initialize(string workingDir, bool createNotFound)
        {
            if (_isInitialized)
            {
                return;
            }

            if (String.IsNullOrEmpty(workingDir))
            {
                throw new InvalidOperationException();
            }

            _dataDir   = workingDir;
            _isExisted = Directory.Exists(_dataDir) &&
                         PersistentDictionaryFile.Exists(_dataDir);
            if (_isExisted)
            {
                this.CheckDataIndex();

                _databaseMsdnUrls =
                    new PersistentDictionary <string, string>(_dataDir);
            }
            else
            {
                if (createNotFound)
                {
                    if (!Directory.Exists(_dataDir))
                    {
                        Directory.CreateDirectory(_dataDir);
                    }

                    _databaseMsdnUrls =
                        new PersistentDictionary <string, string>(_dataDir);
                }
            }

            _isInitialized = true;
        }
Exemplo n.º 16
0
        public DatabaseIndexedDocument(bool isSystem, bool isComments,
                                       string workingDir)
        {
            _isSystem   = isSystem;
            _isComments = isComments;
            _dataDir    = workingDir;

            string        keyXPath   = null;
            string        valueXPath = null;
            CustomContext context    = new CustomContext();

            // The following are the usual key/value in the configuration file...
            if (_isComments)
            {
                // <index name="comments" value="/doc/members/member" key="@name" cache="100">
                keyXPath   = "@name";
                valueXPath = "/doc/members/member";
            }
            else
            {
                //  <index name="reflection" value="/reflection/apis/api" key="@id" cache="10">
                keyXPath   = "@id";
                valueXPath = "/reflection/apis/api";
            }

            _keyExpression = XPathExpression.Compile(keyXPath);
            _keyExpression.SetContext(context);

            _valueExpression = XPathExpression.Compile(valueXPath);
            _valueExpression.SetContext(context);

            if (PersistentDictionaryFile.Exists(_dataDir))
            {
                PersistentDictionaryFile.DeleteFiles(_dataDir);
            }

            _plusTree = new PersistentDictionary <string, string>(_dataDir);
        }
Exemplo n.º 17
0
        public static void MigrateSticky(string name)
        {
            lock (MigrateStickyLock)
            {
                var directory = string.Format(@"{0}\{1}\Sticky", BasicHelper.DataDirectory, name);
                if (PersistentDictionaryFile.Exists(directory))
                {
                    LogService.Debug("Start migrating 'Sticky' data.");

                    var oldDictionary = new PersistentDictionary <Guid, StickyClientEntity>(directory);

                    using (var database = new BotDatabaseEntities(GetInstanceConnectionString(name)))
                    {
                        foreach (var oldDictionaryEntry in oldDictionary)
                        {
                            database.Sticky.AddObject(new Sticky
                            {
                                Id = Guid.NewGuid(),
                                ClientDatabaseId = (int)oldDictionaryEntry.Value.ClientDatabaseId,
                                ChannelId        = (int)oldDictionaryEntry.Value.ChannelId,
                                StickTime        = (int)oldDictionaryEntry.Value.StickTime,
                                Creation         = oldDictionaryEntry.Value.Creation
                            });
                        }

                        database.SaveChanges();
                    }

                    oldDictionary.Flush();
                    oldDictionary.Dispose();

                    PersistentDictionaryFile.DeleteFiles(directory);
                    Directory.Delete(directory);

                    LogService.Debug("Finished migrating 'Sticky' data.");
                }
            }
        }
Exemplo n.º 18
0
        public static void MigrateTimes(string name)
        {
            lock (MigrateTimesLock)
            {
                var directory = string.Format(@"{0}\{1}\Times", BasicHelper.DataDirectory, name);
                if (PersistentDictionaryFile.Exists(directory))
                {
                    LogService.Debug("Start migrating 'Times' data.");

                    var oldDictionary = new PersistentDictionary <string, TimeClientEntity>(directory);

                    using (var database = new BotDatabaseEntities(GetInstanceConnectionString(name)))
                    {
                        foreach (var oldDictionaryEntry in oldDictionary)
                        {
                            database.Time.AddObject(new Time
                            {
                                Id = Guid.NewGuid(),
                                ClientDatabaseId = (int)oldDictionaryEntry.Value.User,
                                Joined           = oldDictionaryEntry.Value.Joined,
                                Disconnected     = oldDictionaryEntry.Value.Disconnected,
                                TotalMinutes     = (oldDictionaryEntry.Value.Disconnected - oldDictionaryEntry.Value.Joined).TotalMinutes
                            });
                        }

                        database.SaveChanges();
                    }

                    oldDictionary.Flush();
                    oldDictionary.Dispose();

                    PersistentDictionaryFile.DeleteFiles(directory);
                    Directory.Delete(directory);

                    LogService.Debug("Finished migrating 'Times' data.");
                }
            }
        }
Exemplo n.º 19
0
        protected override void Dispose(bool disposing)
        {
            if (_targetStorage != null)
            {
                try
                {
                    _targetStorage.Dispose();
                    _targetStorage = null;

                    // For the non-system reflection database, delete after use...
                    if (!_isSystem)
                    {
                        if (!String.IsNullOrEmpty(_targetDataDir) &&
                            Directory.Exists(_targetDataDir))
                        {
                            PersistentDictionaryFile.DeleteFiles(_targetDataDir);
                        }
                    }
                }
                catch
                {
                }
            }
        }
Exemplo n.º 20
0
        public static void MigrateSeen(string name)
        {
            lock (MigrateSeenLock)
            {
                var directory = string.Format(@"{0}\{1}\Seen", BasicHelper.DataDirectory, name);
                if (PersistentDictionaryFile.Exists(directory))
                {
                    LogService.Debug("Start migrating 'Seen' data.");

                    var oldDictionary = new PersistentDictionary <uint, DateTime>(directory);

                    using (var database = new BotDatabaseEntities(GetInstanceConnectionString(name)))
                    {
                        foreach (var oldDictionaryEntry in oldDictionary)
                        {
                            database.Seen.AddObject(new Seen
                            {
                                Id = Guid.NewGuid(),
                                ClientDatabaseId = (int)oldDictionaryEntry.Key,
                                LastSeen         = oldDictionaryEntry.Value
                            });
                        }

                        database.SaveChanges();
                    }

                    oldDictionary.Flush();
                    oldDictionary.Dispose();

                    PersistentDictionaryFile.DeleteFiles(directory);
                    Directory.Delete(directory);

                    LogService.Debug("Finished migrating 'Seen' data.");
                }
            }
        }
Exemplo n.º 21
0
        private void Dispose(bool disposing)
        {
            if (_plusTree != null)
            {
                try
                {
                    _plusTree.Dispose();
                    _plusTree = null;

                    // For the non-system reflection database, delete after use...
                    if (!_isSystem)
                    {
                        if (!String.IsNullOrEmpty(_dataDir) &&
                            Directory.Exists(_dataDir))
                        {
                            PersistentDictionaryFile.DeleteFiles(_dataDir);
                        }
                    }
                }
                catch
                {
                }
            }
        }
Exemplo n.º 22
0
 public void ExistsReturnsTrue()
 {
     Assert.IsTrue(PersistentDictionaryFile.Exists(DictionaryLocation));
 }
Exemplo n.º 23
0
 public void VerifyDeleteThrowsExceptionWhenDirectoryIsNull()
 {
     PersistentDictionaryFile.DeleteFiles((string)null);
 }
Exemplo n.º 24
0
 public void VerifyExistsThrowsExceptionWhenDirectoryIsNull()
 {
     PersistentDictionaryFile.Exists((string)null);
 }
Exemplo n.º 25
0
        private void CheckDataIndex()
        {
            if (!PersistentDictionaryFile.Exists(_dataDir))
            {
                return;
            }

            FileInfo info = new FileInfo(Path.Combine(_dataDir,
                                                      DataSource.DatabaseFileName));

            if (!info.Exists)
            {
                return;
            }

            // Get the total file size in MB...
            long fileSize = info.Length / 1024;

            if (fileSize < 1)
            {
                return;
            }

            PersistentDictionary <string, string> storage = null;

            try
            {
                storage = new PersistentDictionary <string, string>(_dataDir);
                int indexCount = storage.Count;
                if (indexCount > 0)
                {
                    return;
                }
            }
            finally
            {
                if (storage != null)
                {
                    storage.Dispose();
                    storage = null;
                }
            }

            try
            {
                // It is possible the database is corrupted, try fixing it...

                // Perform a defragmentation of the PersistentDictionary.edb database
                Process process = new Process();

                ProcessStartInfo startInfo = process.StartInfo;

                startInfo.FileName = "esentutl.exe";
                //startInfo.Arguments = "-d " + "PersistentDictionary.edb" + " -o";
                startInfo.Arguments              = "/d " + "PersistentDictionary.edb";
                startInfo.UseShellExecute        = false;
                startInfo.CreateNoWindow         = true;
                startInfo.WorkingDirectory       = _dataDir;
                startInfo.RedirectStandardOutput = false;

                // Now, start the process - there will still not be output till...
                process.Start();
                // We must wait for the process to complete...
                process.WaitForExit();
                int exitCode = process.ExitCode;
                process.Close();
                if (exitCode != 0)
                {
                    return;
                }

                string[] logFiles = Directory.GetFiles(_dataDir, "*.log",
                                                       SearchOption.TopDirectoryOnly);
                if (logFiles != null)
                {
                    for (int i = 0; i < logFiles.Length; i++)
                    {
                        File.Delete(logFiles[i]);
                    }
                }
            }
            catch
            {
            }
        }
Exemplo n.º 26
0
        public bool ExportToXml(string xmlFile)
        {
            if (String.IsNullOrEmpty(_workingDir) ||
                !Directory.Exists(_workingDir))
            {
                return(false);
            }

            PersistentDictionary <string, string> linkDatabase = null;

            if (PersistentDictionaryFile.Exists(_workingDir))
            {
                linkDatabase = new PersistentDictionary <string, string>(_workingDir);
            }
            if (linkDatabase == null || linkDatabase.Count == 0)
            {
                return(false);
            }

            string outputDir = Path.GetDirectoryName(xmlFile);

            if (String.IsNullOrEmpty(outputDir))
            {
                return(false);
            }
            if (!Directory.Exists(outputDir))
            {
                Directory.CreateDirectory(outputDir);
            }

            XmlWriterSettings settings = new XmlWriterSettings();

            settings.Indent             = true;
            settings.Encoding           = Encoding.UTF8;
            settings.OmitXmlDeclaration = false;

            XmlWriter writer = null;

            try
            {
                writer = XmlWriter.Create(xmlFile, settings);

                writer.WriteStartDocument();
                writer.WriteStartElement("externalLinks"); // start: externalLinks

                if (_source != null)
                {
                    writer.WriteStartElement("source");    // start: source
                    writer.WriteAttributeString("system", "true");
                    writer.WriteAttributeString("name", _source.SourceType.ToString());
                    writer.WriteAttributeString("platform", _source.IsSilverlight ?
                                                "Silverlight" : "Framework");
                    Version version = _source.Version;
                    writer.WriteAttributeString("version", version != null ?
                                                version.ToString(2) : "");
                    writer.WriteAttributeString("lang", "");
                    writer.WriteAttributeString("storage",
                                                _source.IsDatabase ? "database" : "memory");
                    writer.WriteEndElement();              // end: source
                }

                writer.WriteStartElement("links");    // start: links
                foreach (KeyValuePair <string, string> pair in linkDatabase)
                {
                    string id  = pair.Key;
                    string url = pair.Value;

                    if (String.IsNullOrEmpty(id) || String.IsNullOrEmpty(url))
                    {
                        continue;
                    }

                    writer.WriteStartElement("link");  // start: link
                    writer.WriteAttributeString("id", id);
                    writer.WriteAttributeString("url", url);
                    writer.WriteEndElement();          // end: link
                }
                writer.WriteEndElement();              // end: links

                writer.WriteEndElement();              // end: externalLinks
                writer.WriteEndDocument();
            }
            finally
            {
                if (writer != null)
                {
                    writer.Close();
                    writer = null;
                }
            }

            return(true);
        }