private IBELObject BorderPropertyFromTopic(AbsoluteTopicName relativeToTopic, AbsoluteTopicName abs, Border border, CompositeCacheRule rule) { ContentBase cb = ContentBaseForTopic(abs); if (cb == null) { return null; } rule.Add(cb.CacheRuleForAllPossibleInstancesOfTopic(abs)); if (!cb.TopicExists(abs)) { return null; } // OK, looks like the topic exist -- let's see if the property is there string borderPropertyName = BorderPropertyName(border); string prop = GetTopicProperty(abs, borderPropertyName); if (prop == null || prop == "") { return null; } // Yup, so evaluate it! string code = "federation.GetTopic(\"" + abs.Fullname + "\")." + borderPropertyName + "(federation.GetTopicInfo(\"" + relativeToTopic + "\"))"; BehaviorInterpreter interpreter = new BehaviorInterpreter(code, this, this.WikiTalkVersion, null); if (!interpreter.Parse()) { throw new Exception("Border property expression failed to parse."); } TopicContext topicContext = new TopicContext(this, this.ContentBaseForTopic(abs), new TopicInfo(this, abs)); IBELObject obj = interpreter.EvaluateToObject(topicContext, null); if (interpreter.ErrorString != null) { obj = new BELString(interpreter.ErrorString); } foreach (CacheRule r in interpreter.CacheRules) { rule.Add(r); } return obj; }
/// <summary> /// Answer the formatted text for a given topic, formatted using a given OutputFormat and possibly showing diffs /// with a specified revision /// </summary> /// <param name="topic">The topic</param> /// <param name="format">What format</param> /// <param name="showDiffs">true to show diffs</param> /// <param name="accumulator">composite cache rule in which to accumulate cache rules (ignored for diffs)</param> /// <returns></returns> public static string FormattedTopicWithSpecificDiffs(AbsoluteTopicName topic, OutputFormat format, AbsoluteTopicName diffWithThisVersion, Federation aFederation, LinkMaker lm, CompositeCacheRule accumulator) { // Setup a special link maker that knows what to make the edit links return to LinkMaker linker = lm.Clone(); linker.ReturnToTopicForEditLinks = topic; ContentBase relativeToBase = aFederation.ContentBaseForNamespace(topic.Namespace); if (accumulator != null) accumulator.Add(relativeToBase.CacheRuleForAllPossibleInstancesOfTopic(topic)); WikiOutput output = WikiOutput.ForFormat(format, null); if (diffWithThisVersion != null) { ArrayList styledLines = new ArrayList(); IList leftLines; IList rightLines; using (TextReader srLeft = relativeToBase.TextReaderForTopic(topic.LocalName)) { leftLines = MergeBehaviorLines(srLeft.ReadToEnd().Replace("\r", "").Split('\n')); } using (TextReader srRight = relativeToBase.TextReaderForTopic(diffWithThisVersion.LocalName)) { rightLines = MergeBehaviorLines(srRight.ReadToEnd().Replace("\r", "").Split('\n')); } IEnumerable diffs = Diff.Compare(leftLines, rightLines); foreach (LineData ld in diffs) { LineStyle style = LineStyle.Unchanged; switch (ld.Type) { case LineType.Common: style = LineStyle.Unchanged; break; case LineType.LeftOnly: style = LineStyle.Add; break; case LineType.RightOnly: style = LineStyle.Delete; break; } styledLines.Add(new StyledLine(ld.Text, style)); } Format(topic, styledLines, output, relativeToBase, linker, relativeToBase.ExternalWikiHash(), 0, accumulator); } else { using (TextReader sr = relativeToBase.TextReaderForTopic(topic.LocalName)) { Format(topic, sr.ReadToEnd(), output, relativeToBase, linker, relativeToBase.ExternalWikiHash(), 0, accumulator); } } return output.ToString(); }
private CachedTopic GetCachedTopic(AbsoluteTopicName name) { CachedTopic answer = null; if (CacheManager != null) { answer = (CachedTopic)CacheManager.GetCachedTopic(name); } if (answer != null) { return answer; } ContentBase cb = ContentBaseForTopic(name); if (cb ==null || !cb.TopicExists(name)) { return null; } answer = new CachedTopic(name); CompositeCacheRule rule = new CompositeCacheRule(); rule.Add(cb.CacheRuleForAllPossibleInstancesOfTopic(name)); answer.Changes = cb.AllChangesForTopic(name.LocalName, rule); answer.CreationTime = cb.GetTopicCreationTime(name.LocalName); answer.LastModified = cb.GetTopicLastWriteTime(name.LocalName); answer.LastModifiedBy = cb.GetTopicLastAuthor(name.LocalName); answer.UnformattedContent = cb.Read(name.LocalName); answer.Properties = ContentBase.ExtractExplicitFieldsFromTopicBody(answer.UnformattedContent); AddImplicitPropertiesToHash(answer.Properties, name, answer.LastModifiedBy, answer.CreationTime, answer.LastModified, answer.UnformattedContent); if (CacheManager != null) { CacheManager.PutCachedTopic(name, answer, rule); } return answer; }
/// <summary> /// Answer a list of the wikitext components (IBELObjects) of the given border. If nothing specifies any border; answer the system default /// </summary> /// <param name="name"></param> /// <param name="border"></param> /// <param name="rule"></param> /// <returns></returns> private IEnumerable BorderText(AbsoluteTopicName name, Border border, CompositeCacheRule rule) { ArrayList answer = new ArrayList(); ContentBase cb; string bordersTopicsProperty = "Borders"; ArrayList borderTopics = new ArrayList(); // Start with whatever the namespace defines if (Borders != null) { foreach (string at in ParseListPropertyValue(Borders)) { AbsoluteTopicName abs = new AbsoluteTopicName(at); cb = ContentBaseForTopic(abs); if (abs == null || cb == null) { throw new Exception("Unknown namespace listed in border topic (" + at +") listed in federation configuration Borders property."); } borderTopics.Add(at); } } // If the namespace, specifies border topics, get them cb = ContentBaseForTopic(name); if (cb != null) { borderTopics.AddRange(GetTopicListPropertyValue(cb.DefinitionTopicName, bordersTopicsProperty)); rule.Add(cb.CacheRuleForAllPossibleInstancesOfTopic(cb.DefinitionTopicName)); } // If there are no border topics specified for the federation or the namespace, add the default (_NormalBorders from the local namespace) if (borderTopics.Count == 0) { borderTopics.Add("_NormalBorders"); } // Finally, any border elements form the topic itself (skip the def topic so we don't get double borders!) if (cb == null || cb.DefinitionTopicName.ToString() != name.ToString()) { borderTopics.AddRange(GetTopicListPropertyValue(name, bordersTopicsProperty)); } Set done = new Set(); foreach (string borderTopicName in borderTopics) { // Figure out what the absolute topic name is that we're going to get this topic from RelativeTopicName rel = new RelativeTopicName(borderTopicName); if (rel.Namespace == null) { rel.Namespace = name.Namespace; } AbsoluteTopicName abs = new AbsoluteTopicName(rel.Name, rel.Namespace); if (done.Contains(abs)) { continue; } done.Add(abs); IBELObject s = BorderPropertyFromTopic(name, abs, border, rule); if (s != null) { answer.Add(s); } } return answer; }
/// <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; }
public CacheRule CacheRuleForAllPossibleInstancesOfTopic(TopicName aName) { TopicsCacheRule rule = new TopicsCacheRule(Federation); foreach (AbsoluteTopicName possible in aName.AllAbsoluteTopicNamesFor(this)) rule.AddTopic(possible); CompositeCacheRule answer = new CompositeCacheRule(); answer.Add(rule); answer.Add(CacheRuleForDefinition); // Add the cache rule for the content base, too, since if that changes there might be a change in imports return answer; }
/// <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; }