rendered paste bodyusing AqDWeb.Attributes;
using AqDWeb.Exceptions;
using AqDWeb.Services;
using Lucene.Net.Documents;
using NHibernate.Type;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Web;
using YaDiary.Base;
namespace YaDiary.Domain
{
/// <summary>A generic service for <see cref="IndexedArticle"/>. It hooks
/// into the NHibernate interceptor to update DotLucene indexes incrementally.
/// </summary>
[GenericService(typeof(IndexedArticle))]
public class IndexedArticleService<T>: VersionedEntityService<T>
where T: IndexedArticle
{
public delegate string Translate(string text);
public override bool OnSave(object entity, object id,
IDictionary<string, object> namedState,
IDictionary<string, IType> namedTypes)
{
T e = entity as T;
// Skip historical objects.
if (e.EntityTimestamp == DateTime.MinValue
&& IsSearchableEntity(namedState))
{
// Set EntityID manually here because it's going to be used when saving
// index. The change will be overrided when NHibernate refreshs the
// entity from state (base.OnSave sets the same EntityID in state).
e.EntityID = (Guid) id;
SaveIndexes(new IndexedArticle[]{e});
}
return base.OnSave(entity, id, namedState, namedTypes);
}
public override bool OnFlushDirty(object entity, object id,
IDictionary<string, object> namedCurrentState,
IDictionary<string, object> namedPreviousState,
IDictionary<string, IType> namedTypes)
{
T e = entity as T;
bool currentlySearchable
= IsSearchableEntity(namedCurrentState);
bool previouslySearchable
= IsSearchableEntity(namedPreviousState);
if (currentlySearchable && previouslySearchable && e.IsEntityDeleted)
DeleteIndexes(new IndexedArticle[]{e});
else if (currentlySearchable && !previouslySearchable)
SaveIndexes(new IndexedArticle[]{e});
else if (currentlySearchable)
UpdateIndexes(new IndexedArticle[]{e});
else if (!currentlySearchable && previouslySearchable)
DeleteIndexes(new IndexedArticle[]{e});
return base.OnFlushDirty(entity, id, namedCurrentState,
namedPreviousState, namedTypes);
}
public virtual void ClearAllIndexes()
{
YaDiarySearchModule.Instance.ClearIndexes();
}
public virtual void OptimizeAllIndexes()
{
YaDiarySearchModule.Instance.OptimizeIndexes();
}
public virtual void SaveIndexes(IList<IndexedArticle> entities)
{
UpdateIndexes(entities, true);
}
public virtual void UpdateIndexes(IList<IndexedArticle> entities)
{
UpdateIndexes(entities, false);
}
public virtual void UpdateIndexes(IList<IndexedArticle> entities, bool saveOnly)
{
YaDiarySearchModule.Instance.BatchUpdateIndexes(
entities,
delegate(IndexedArticle entity, YaDiarySearchModule.CreateDocument createDocument)
{
Document zhTwDoc = createDocument();
zhTwDoc.Add(Field.Keyword("language", "zh-TW"));
SetupIndexDocument(
entity, zhTwDoc,
delegate (string text)
{
return text;
}
);
Document zhCnDoc = createDocument();
zhCnDoc.Add(Field.Keyword("language", "zh-CN"));
ChineseConversionModule translator
= ChineseConversionModule.Instance;
SetupIndexDocument(
entity, zhCnDoc,
delegate (string text)
{
return translator.TranslateTraditionalToSimple(text);
}
);
return new Document[] {zhTwDoc, zhCnDoc};
},
saveOnly
);
}
public virtual void DeleteIndexes(IList<IndexedArticle> entities)
{
YaDiarySearchModule.Instance.BatchDeleteIndexes(entities);
}
protected virtual void SetupIndexDocument(IndexedArticle entity,
Document doc,
Translate translate)
{
char splitChar = (entity.Keywords.Contains(",") ? ',': ' ');
foreach (string keyword in entity.Keywords.Split(splitChar))
{
Field kf = Field.Text("keyword", translate(keyword.Trim()));
kf.SetBoost(3.0f); doc.Add(kf);
}
Field sf = Field.Text("subject", translate(entity.Subject));
sf.SetBoost(2.0f); doc.Add(sf);
Field af = Field.Text("author", translate(entity.Author.Name));
af.SetBoost(1.5f); doc.Add(af);
doc.Add(Field.Keyword("postdate", entity.PostDate));
doc.Add(
Field.Text(
"text",
new StringReader(translate(ExtractHtmlBodyText(entity.Text)))
)
);
if (entity is DiscussionAnswer)
{
doc.Add(
Field.Keyword(
"threadID",
(entity as DiscussionAnswer).Question.ID.ToString())
);
}
}
protected virtual string ExtractHtmlBodyText(string html)
{
// Strip all tags and convert back html entity chars, this should be
// sufficient for simple HTML body without javascript
return HttpUtility.HtmlDecode(Regex.Replace(html, "<[^>]*>", ""));
}
protected virtual bool IsSearchableEntity(IDictionary<string, object> namedState)
{
if (typeof(Discussion).IsAssignableFrom(typeof(T)))
{
try
{
return (bool) namedState["IsPublic"];
}
catch (KeyNotFoundException ex)
{
throw new InvalidUserCodeException(
typeof(T).FullName + " contains no \"IsPublic\" property?!", ex);
}
}
else
return true;
}
}
}