OpenLiveWriter/utilities/BlogServer/Model/Blog.cs

218 lines
4.3 KiB
C#

using System;
using System.Collections;
using System.Diagnostics;
using System.Threading;
using BlogServer.XmlRpc;
namespace BlogServer.Model
{
public abstract class Blog
{
protected ArrayList _postList = new ArrayList();
protected Hashtable _postTable = new Hashtable();
private readonly ReaderWriterLock _rwLock = new ReaderWriterLock();
protected BlogPersist GetBlogPersist()
{
using (Lock(false))
{
return new BlogPersist((BlogPost[]) _postList.ToArray(typeof(BlogPost)));
}
}
protected void Add(params BlogPost[] posts)
{
foreach (BlogPost post in posts)
{
if (post.Id == null)
throw new ArgumentException("One or more posts had a null ID");
if (_postTable.ContainsKey(post.Id))
throw new InvalidOperationException("Duplicate post ID detected: " + post.Id);
_postTable.Add(post.Id, post);
_postList.Add(post);
}
}
public BlogPost this[int index]
{
get
{
BlogPost blogPost;
using (Lock(false))
blogPost = (BlogPost) _postList[index];
if (blogPost != null)
blogPost = blogPost.Clone();
return blogPost;
}
}
public BlogPost this[string postId]
{
get
{
BlogPost blogPost;
using (Lock(false))
blogPost = (BlogPost) _postTable[postId];
if (blogPost != null)
blogPost = blogPost.Clone();
return blogPost;
}
}
public int Count
{
get
{
using (Lock(false))
return _postList.Count;
}
}
public BlogPost[] GetRecentPosts(int numberOfPosts)
{
ArrayList results = new ArrayList();
using (Lock(false))
{
numberOfPosts = Math.Min(numberOfPosts, Count);
for (int i = 0; i < numberOfPosts; i++)
results.Add(this[Count - i - 1].Clone());
}
return (BlogPost[]) results.ToArray(typeof (BlogPost));
}
public BlogPost[] GetRecentPublishedPosts(int numberOfPosts)
{
ArrayList results = new ArrayList();
using (Lock(false))
{
for (int i = 0; i < Count && results.Count < numberOfPosts; i++)
{
BlogPost post = this[Count - i - 1];
if (post.Published)
results.Add(post.Clone());
}
}
return (BlogPost[]) results.ToArray(typeof (BlogPost));
}
protected abstract void Persist();
public bool Contains(string postid)
{
using (Lock(false))
{
return _postTable.ContainsKey(postid);
}
}
public string CreateBlogPost(BlogPost newPost)
{
string newId = Guid.NewGuid().ToString("d");
newPost.Id = newId;
using (Lock(true))
{
Add(newPost.Clone());
}
return newId;
}
public void UpdateBlogPost(BlogPost existingPost)
{
using (Lock(true))
{
if (!_postTable.ContainsKey(existingPost.Id))
throw new XmlRpcServerException(404, "Cannot edit a post that doesn't exist (was it deleted?)");
// pass-by-value semantics
BlogPost clone = existingPost.Clone();
_postTable[existingPost.Id] = clone;
for (int i = 0; i < _postList.Count; i++)
{
if (((BlogPost) _postList[i]).Id == clone.Id)
{
_postList[i] = clone;
break;
}
}
}
}
private IDisposable Lock(bool write)
{
if (write)
_rwLock.AcquireWriterLock(Timeout.Infinite);
else
_rwLock.AcquireReaderLock(Timeout.Infinite);
return new LockReleaser(this, write);
}
private class LockReleaser : IDisposable
{
private readonly Blog _blog;
private readonly bool _write;
public LockReleaser(Blog blog, bool write)
{
_blog = blog;
_write = write;
}
public void Dispose()
{
if (_write)
{
_blog.Persist();
_blog._rwLock.ReleaseWriterLock();
}
else
_blog._rwLock.ReleaseReaderLock();
}
}
public class BlogPersist
{
private BlogPost[] _blogPosts;
public BlogPersist()
{
}
public BlogPersist(BlogPost[] blogPosts)
{
_blogPosts = blogPosts;
}
public BlogPost[] BlogPosts
{
get { return _blogPosts; }
set { _blogPosts = value; }
}
}
public bool DeleteBlogPost(string postid)
{
using (Lock(true))
{
if (_postTable.ContainsKey(postid))
{
BlogPost post = (BlogPost) _postTable[postid];
Debug.Assert(_postList.Contains(post));
_postList.Remove(post);
_postTable.Remove(postid);
return true;
}
return false;
}
}
}
}