Пример #1
0
		/// <summary>
		/// Write a new version of the topic (doesn't write a new version).  Generate all needed federation update changes via the supplied generator.
		/// </summary>
		/// <param name="topic">Topic to write</param>
		/// <param name="content">New content</param>
		/// <param name="sink">Object to recieve change info about the topic</param>
		override protected void WriteTopic(LocalTopicName topic, string content, FederationUpdateGenerator gen)
		{
			string root = Root;
			string fullpath = MakePath(root, topic);
			bool isNew = !(File.Exists(fullpath));

			// Get old topic so we can analyze it for properties to compare with the new one
			string oldText = null;
			Hashtable oldProperties = null;
			if (!isNew)
			{
				using (StreamReader sr = new StreamReader(new FileStream(fullpath, FileMode.Open, FileAccess.Read, FileShare.Read)))
				{
					oldText = sr.ReadToEnd();
				}
				oldProperties = ExtractExplicitFieldsFromTopicBody(oldText);	
			}

			// Change it
			using (StreamWriter sw = new StreamWriter(fullpath))
			{
				sw.Write(content);
			}

			// Quick check to see if we're about to let somebody write the DefinitionTopic for this ContentBase.  
			// If so, we reset our Info object to reread
			string pathToDefinitionTopic = MakePath(Root, DefinitionTopicName.LocalName);
			if (fullpath == pathToDefinitionTopic)
				this.Federation.InvalidateNamespace(Namespace);

			// Record changes
			try
			{
				AbsoluteTopicName absTopic = topic.AsAbsoluteTopicName(Namespace);

				gen.Push();

				// Record the topic-level change
				if (isNew)
					gen.RecordCreatedTopic(absTopic);
				else
					gen.RecordUpdatedTopic(absTopic);

				//	Now process the properties
				Hashtable newProperties = ExtractExplicitFieldsFromTopicBody(content);
				if (isNew)
				{
					foreach (string pName in newProperties.Keys)
						gen.RecordPropertyChange(absTopic, pName, FederationUpdate.PropertyChangeType.PropertyAdd);
					gen.RecordPropertyChange(absTopic, "_Body", FederationUpdate.PropertyChangeType.PropertyAdd);
					gen.RecordPropertyChange(absTopic, "_TopicName", FederationUpdate.PropertyChangeType.PropertyAdd);
					gen.RecordPropertyChange(absTopic, "_TopicFullName", FederationUpdate.PropertyChangeType.PropertyAdd);
					gen.RecordPropertyChange(absTopic, "_LastModifiedBy", FederationUpdate.PropertyChangeType.PropertyAdd);
					gen.RecordPropertyChange(absTopic, "_CreationTime", FederationUpdate.PropertyChangeType.PropertyAdd);
					gen.RecordPropertyChange(absTopic, "_ModificationTime", FederationUpdate.PropertyChangeType.PropertyAdd);
				}
				else
				{
					if (content != oldText)
					{
						FillFederationUpdateByComparingPropertyHashes(gen, absTopic, oldProperties, newProperties);
						gen.RecordPropertyChange(absTopic, "_Body", FederationUpdate.PropertyChangeType.PropertyUpdate);
					}
					gen.RecordPropertyChange(absTopic, "_ModificationTime", FederationUpdate.PropertyChangeType.PropertyUpdate);				
				}
			}
			finally
			{
				gen.Pop();
			}
		}
Пример #2
0
		/// <summary>
		/// Rename the given topic.  If requested, find references and fix them up.  Answer a report of what was fixed up.  Throw a DuplicationTopicException
		/// if the new name is the name of a topic that already exists.
		/// </summary>
		/// <param name="oldName">Old topic name</param>
		/// <param name="newName">The new name</param>
		/// <param name="fixup">true to fixup referenced topic *in this namespace*; false to do no fixups</param>
		/// <returns>ArrayList of strings that can be reported back to the user of what happened during the fixup process</returns>
		override public ArrayList RenameTopic(LocalTopicName oldName, string newName, bool fixup)
		{
			FederationUpdateGenerator gen = CreateFederationUpdateGenerator();

			// TRIGGER
			ArrayList answer = new ArrayList();
			string root = Root;
			string pathToTopicFile =  root + "\\" + oldName.Name + ".wiki";
			string pathToArchiveFolder = root + "\\archive\\" + oldName.Name;
			string newNameForTopicFile = root + "\\" + newName + ".wiki";
			string newNameForArchiveFolder = root + "\\archive\\" + newName;
			AbsoluteTopicName newFullName = new AbsoluteTopicName(newName, Namespace);

			// Make sure it's not goign to overwrite an existing topic
			if (TopicExistsLocally(newName))
			{
				throw DuplicateTopicException.ForTopic(newFullName);
			}

			// If the topic does not exist (e.g., it's a backing topic), don't bother...
			if (!TipFileExists(oldName.Name))
			{
				answer.Add("This topic can not be renamed (it is probably a backing topic).");
				return answer;
			}

			try
			{
				gen.Push();

				// Rename the archive files, too
				foreach (FileInfo each in FileInfosForTopic(oldName))
				{
					AbsoluteTopicName newNameForThisVersion = new AbsoluteTopicName(newName, Namespace);
					newNameForThisVersion.Version = ExtractVersionFromHistoricalFilename(each.Name);

					AbsoluteTopicName oldNameForThisVersion = new AbsoluteTopicName(oldName.Name, Namespace);
					oldNameForThisVersion.Version = newNameForThisVersion.Version;
					
					string newFilename = MakePath(root, newNameForThisVersion.LocalName);
					File.Move(each.FullName, newFilename);

					// record changes (a delete for the old one and an add for the new one)
					gen.RecordCreatedTopic(newNameForThisVersion);
					gen.RecordDeletedTopic(oldNameForThisVersion);
				}

				// Rename the topic file
				File.Move(pathToTopicFile, newNameForTopicFile);

				// Record changes (a delete for the old one and an add for the new one)
				gen.RecordCreatedTopic(newFullName);
				gen.RecordDeletedTopic(oldName.AsAbsoluteTopicName(Namespace));

				// Now get ready to do fixups
				if (!fixup)
					return answer;

				// OK, we need to do the hard work
				AbsoluteTopicName oldabs = oldName.AsAbsoluteTopicName(Namespace);
				AbsoluteTopicName newabs = new AbsoluteTopicName(newName, oldabs.Namespace);
				
				// Now the master loop
				foreach (AbsoluteTopicName topic in AllTopics(false))
					if (RenameTopicReferences(topic.LocalName, oldabs, newabs, gen))
						answer.Add("Found and replaced references in " + topic);
			}
			finally
			{
				gen.Pop();
			}

			return answer;
		}
Пример #3
0
		/// <summary>
		/// Answer all of the versions for a given topic
		/// </summary>
		/// <remarks>
		/// TODO: Change this to return TopicChanges instead of the TopicNames
		/// </remarks>
		/// <param name="topic">A topic</param>
		/// <returns>Enumeration of the topic names (with non-null versions in them) </returns>
		override public IEnumerable AllVersionsForTopic(LocalTopicName topic)
		{
			ArrayList answer = new ArrayList();
			FileInfo[] infos = FileInfosForTopic(topic);
			ArrayList sortable = new ArrayList();
			foreach (FileInfo each in infos)
				sortable.Add(new FileInfoTopicData(each, Namespace));
			BackingTopic back = GetBackingTopicNamed(topic);
			if (back != null)
				sortable.Add(new BackingTopicTopicData(back));
			sortable.Sort(new TimeSort());
			foreach (TopicData each in sortable)
			{
				AbsoluteTopicName name = topic.AsAbsoluteTopicName(Namespace);
				name.Version = each.Version;
				answer.Add(name);
			}
			return answer;
		}
Пример #4
0
		/// <summary>
		/// A list of TopicChanges to a topic since a given date [sorted by date]
		/// </summary>
		/// <param name="topic">A given date</param>
		/// <param name="stamp">A non-null timestamp; changes before this time won't be included in the answer </param>
		/// <returns>Enumeration of TopicChanges</returns>
		override public IEnumerable AllChangesForTopicSince(LocalTopicName topic, DateTime stamp, CompositeCacheRule rule)
		{
			ArrayList answer = new ArrayList();
			FileInfo[] infos = FileInfosForTopic(topic);
			ArrayList sortable = new ArrayList();
			foreach (FileInfo each in infos)
				sortable.Add(new FileInfoTopicData(each, Namespace));
			BackingTopic back = GetBackingTopicNamed(topic);
			if (back != null)
				sortable.Add(new BackingTopicTopicData(back));
			sortable.Sort(new TimeSort());
			TopicsCacheRule tcr = null;
			if (rule != null)
			{
				tcr = new TopicsCacheRule(Federation);
				tcr.AddTopic(topic.AsAbsoluteTopicName(Namespace));
				rule.Add(tcr);
			}
			foreach (TopicData each in sortable)
			{
				if (each.LastModificationTime < stamp)
					continue;
				AbsoluteTopicName name = topic.AsAbsoluteTopicName(Namespace);
				name.Version = each.Version;
				TopicChange change = TopicChangeFromName(name);
				answer.Add(change);
				if (tcr != null)
					tcr.AddTopic(name.AsAbsoluteTopicName(Namespace));
			}
			return answer;
		}
Пример #5
0
		/// <summary>
		/// Find the version of a topic immediately previous to another version
		/// </summary>
		/// <param name="topic">The name (with version) of the topic for which you want the change previous to</param>
		/// <returns>TopicChange or null if none</returns>
		public AbsoluteTopicName VersionPreviousTo(LocalTopicName topic)
		{
			bool next = false;
			bool first = true;
			AbsoluteTopicName answer = topic.AsAbsoluteTopicName(Namespace);
			foreach (TopicChange ver in AllChangesForTopic(topic))
			{
				answer.Version = ver.Version;
				if (next)
					return answer;
				if (topic.Version == null && !first)	// The version prior to the most recent is the second in line
					return answer;
				if (ver.Version == topic.Version)
					next = true;
				first = false;
			}
			return null;
		}
Пример #6
0
		/// <summary>
		/// Delete a topic
		/// </summary>
		/// <param name="topic"></param>
		override public void DeleteTopic(LocalTopicName topic)
		{
			string path = TopicPath(topic);
			if (!File.Exists(path))
				return;

			// Delete the sucker!
			File.Delete(path);

			// Fire the event
			FederationUpdate update = new FederationUpdate();
			update.RecordDeletedTopic(topic.AsAbsoluteTopicName(Namespace));
			OnFederationUpdated(new FederationUpdateEventArgs(update));
		}
Пример #7
0
		/// <summary>
		/// Write a topic (and create a historical version)
		/// </summary>
		/// <param name="topic">The topic to write</param>
		/// <param name="content">The content</param>
		void WriteTopicAndNewVersion(LocalTopicName topic, string content, FederationUpdateGenerator gen)
		{
			gen.Push();
			LocalTopicName versionless = new LocalTopicName(topic.Name);

			bool isVersionlessNew = !TopicExistsLocally(versionless);
			bool isVersionedNew = !TopicExistsLocally(topic);

			string oldAuthor = null;
			if (!isVersionlessNew)
				oldAuthor = GetTopicLastAuthor(topic);

			// Write it
			WriteTopic(versionless, content, gen);
			WriteTopic(topic, content, gen);	

			//Generate author property change if needed
			if (!isVersionlessNew)
			{
				//See if the last modified by has changed (not this only happens when writing out the versioned tip file)
				string newLastAuthor = GetTopicLastAuthor(topic);
				if (oldAuthor != newLastAuthor)
				{
					gen.RecordPropertyChange(versionless.AsAbsoluteTopicName(Namespace), "_LastModifiedBy", FederationUpdate.PropertyChangeType.PropertyUpdate);
				}
			}

			gen.Pop();
		}
Пример #8
0
		/// <summary>
		/// Reach and answer all the properties (aka fields) for the given topic.  This includes both the 
		/// properties defined in the topic plus the extra properties that every topic has (e.g., _TopicName, _TopicFullName, _LastModifiedBy, etc.)
		/// </summary>
		/// <param name="topic"></param>
		/// <returns>Hashtable (keys = string property names, values = values [as strings]);  or null if the topic doesn't exist</returns>
		public Hashtable GetFieldsForTopic(LocalTopicName topic)
		{
			if (!TopicExistsLocally(topic))
				return null;

			string allLines = Read(topic);
			Hashtable answer = ExtractExplicitFieldsFromTopicBody(allLines);	
			Federation.AddImplicitPropertiesToHash(answer, topic.AsAbsoluteTopicName(Namespace), GetTopicLastAuthor(topic), GetTopicCreationTime(topic), GetTopicLastWriteTime(topic), allLines);
			return answer;
		}
Пример #9
0
		/// <summary>
		/// Rename the given topic.  If requested, find references and fix them up.  Answer a report of what was fixed up.  Throw a DuplicationTopicException
		/// if the new name is the name of a topic that already exists.
		/// </summary>
		/// <param name="oldName">Old topic name</param>
		/// <param name="newName">The new name</param>
		/// <param name="fixup">true to fixup referenced topic *in this namespace*; false to do no fixups</param>
		/// <returns>ArrayList of strings that can be reported back to the user of what happened during the fixup process</returns>
		public override ArrayList RenameTopic(LocalTopicName oldName, string newName, bool fixup)
		{
			FederationUpdateGenerator gen = CreateFederationUpdateGenerator();

			// TRIGGER
			ArrayList answer = new ArrayList();
			string currentTopicName =  oldName.Name;
			string newTopicName = newName;
			AbsoluteTopicName newFullName = new AbsoluteTopicName(newName, Namespace);

			// Make sure it's not goign to overwrite an existing topic
			if (TopicExistsLocally(newName))
			{
				throw DuplicateTopicException.ForTopic(newFullName);
			}

			// If the topic does not exist (e.g., it's a backing topic), don't bother...
			if (!TipTopicRecordExists(oldName.Name))
			{
				answer.Add("This topic can not be renamed (it is probably a backing topic).");
				return answer;
			}

			try
			{
				gen.Push();

				// Rename the archive files, too
				foreach (SqlInfoForTopic each in SqlTopicInfosForTopic(oldName))
				{
					AbsoluteTopicName newNameForThisVersion = new AbsoluteTopicName(newName, Namespace);
					newNameForThisVersion.Version = ExtractVersionFromTopicName(each.Name);

					AbsoluteTopicName oldNameForThisVersion = new AbsoluteTopicName(oldName.Name, Namespace);
					oldNameForThisVersion.Version = newNameForThisVersion.Version;
					
					SqlHelper.RenameTopic(Namespace, each.Name, MakeTopicName(newNameForThisVersion.LocalName), _ConnectionString);

					// record changes (a delete for the old one and an add for the new one)
					gen.RecordCreatedTopic(newNameForThisVersion);
					gen.RecordDeletedTopic(oldNameForThisVersion);
				}

				// Rename the topic file
				SqlHelper.RenameTopic(Namespace, currentTopicName, newTopicName, _ConnectionString);

				// Record changes (a delete for the old one and an add for the new one)
				gen.RecordCreatedTopic(newFullName);
				gen.RecordDeletedTopic(oldName.AsAbsoluteTopicName(Namespace));

				// Now get ready to do fixups
				if (!fixup)
					return answer;

				// OK, we need to do the hard work
				AbsoluteTopicName oldabs = oldName.AsAbsoluteTopicName(Namespace);
				AbsoluteTopicName newabs = new AbsoluteTopicName(newName, oldabs.Namespace);
				
				// Now the master loop
				foreach (AbsoluteTopicName topic in AllTopics(false))
					if (RenameTopicReferences(topic.LocalName, oldabs, newabs, gen))
						answer.Add("Found and replaced references in " + topic);
			}
			finally
			{
				gen.Pop();
			}

			return answer;
		}
Пример #10
0
		private void RecordTopicChanges(LocalTopicName topic, FederationUpdateGenerator gen, bool isNew, string content, string oldText, Hashtable oldProperties)
		{
			try
			{
				AbsoluteTopicName absTopic = topic.AsAbsoluteTopicName(Namespace);

				gen.Push();

				// Record the topic-level change
				if (isNew)
					gen.RecordCreatedTopic(absTopic);
				else
					gen.RecordUpdatedTopic(absTopic);

				//	Now process the properties
				Hashtable newProperties = ExtractExplicitFieldsFromTopicBody(content);
				if (isNew)
				{
					foreach (string pName in newProperties.Keys)
						gen.RecordPropertyChange(absTopic, pName, FederationUpdate.PropertyChangeType.PropertyAdd);
					gen.RecordPropertyChange(absTopic, "_Body", FederationUpdate.PropertyChangeType.PropertyAdd);
					gen.RecordPropertyChange(absTopic, "_TopicName", FederationUpdate.PropertyChangeType.PropertyAdd);
					gen.RecordPropertyChange(absTopic, "_TopicFullName", FederationUpdate.PropertyChangeType.PropertyAdd);
					gen.RecordPropertyChange(absTopic, "_LastModifiedBy", FederationUpdate.PropertyChangeType.PropertyAdd);
					gen.RecordPropertyChange(absTopic, "_CreationTime", FederationUpdate.PropertyChangeType.PropertyAdd);
					gen.RecordPropertyChange(absTopic, "_ModificationTime", FederationUpdate.PropertyChangeType.PropertyAdd);
				}
				else
				{
					if (content != oldText)
					{
						FillFederationUpdateByComparingPropertyHashes(gen, absTopic, oldProperties, newProperties);
						gen.RecordPropertyChange(absTopic, "_Body", FederationUpdate.PropertyChangeType.PropertyUpdate);
					}
					gen.RecordPropertyChange(absTopic, "_ModificationTime", FederationUpdate.PropertyChangeType.PropertyUpdate);				
				}
			}
			finally
			{
				gen.Pop();
			}
		}
Пример #11
0
		/// <summary>
		/// A list of TopicChanges to a topic since a given date [sorted by date]
		/// </summary>
		/// <param name="topic">A given date</param>
		/// <param name="stamp">A non-null timestamp; changes before this time won't be included in the answer </param>
		/// <param name="rule">A composite cache rule to fill with rules that represented accumulated dependencies (or null)</param>
		/// <returns>Enumeration of TopicChanges</returns>
		public override IEnumerable AllChangesForTopicSince(LocalTopicName topic, DateTime stamp, CompositeCacheRule rule)
		{
			ArrayList answer = new ArrayList();
			SqlInfoForTopic[] infos = SqlHelper.GetSqlTopicInfosForTopicSince(Namespace, topic.Name, stamp, ConnectionString);
			ArrayList sortable = new ArrayList();
			foreach (SqlInfoForTopic each in infos)
				sortable.Add(new SqlInfoTopicData(each, Namespace));
			BackingTopic back = GetBackingTopicNamed(topic);
			bool sortAgain = false;
			if (back != null)
			{
				sortAgain = true;
				sortable.Add(new BackingTopicTopicData(back));
			}
			if( sortAgain )
				sortable.Sort(new TimeSort());

			TopicsCacheRule tcr = null;
			if (rule != null)
			{
				tcr = new TopicsCacheRule(Federation);
				tcr.AddTopic(topic.AsAbsoluteTopicName(Namespace));
				rule.Add(tcr);
			}
			foreach (TopicData each in sortable)
			{
				if (each.LastModificationTime < stamp)
					continue;
				AbsoluteTopicName name = topic.AsAbsoluteTopicName(Namespace);
				name.Version = each.Version;
				TopicChange change = TopicChangeFromName(name);
				answer.Add(change);
				if (tcr != null)
					tcr.AddTopic(name.AsAbsoluteTopicName(Namespace));
			}
			return answer;

		}
Пример #12
0
		/// <summary>
		/// Delete a topic
		/// </summary>
		/// <param name="topic"></param>
		public override void DeleteTopic(LocalTopicName topic)
		{
			if( !SqlHelper.TopicExists(Namespace, topic.Name, _ConnectionString) )
			{
				return;
			}

			SqlHelper.DeleteTopic(Namespace, topic.Name, _ConnectionString);

			// Fire the event
			FederationUpdate update = new FederationUpdate();
			update.RecordDeletedTopic(topic.AsAbsoluteTopicName(Namespace));
			OnFederationUpdated(new FederationUpdateEventArgs(update));
		}
Пример #13
0
		public override IEnumerable AllVersionsForTopic(LocalTopicName topic)
		{
			ArrayList answer = new ArrayList();
			AbsoluteTopicName only = topic.AsAbsoluteTopicName(Namespace);
			only.Version = VersionConst;
			answer.Add(only);
			return answer;
		}