Implementation of blog functionality
Introduction
Blog feature is being implemented in last couple of development iterations. One of the technical objectives of blog feature has been to make it reusable, pluggable so that the functionality can be separated from project.net. While implementing blog feature, it has also been considered to modify the Roller for closer integration with project.net for more flexibility within project.net development by keeping the long term objective of de-coupling.
The details of the blog feature can be found here …
http://community.project.net/trac/pnet-community/wiki/feature-blog
The user manual for the current implementation can be found here …
http://community.project.net/trac/pnet-community/wiki/feature-blog-user-manual
Database layer
Implementation approach
Roller has many tables for persisting information in database. In the current implementation, only the required database objects have been used in proect.net. Additional database objects will be added as and when blog feature is improved with additional functionality.
Implementation
Five database objects have been used in blog feature as follows...
- USER
The main object used to link the creator of blog entries as well as commenter. The owner of post is identified with the help of this database object.
Few important attributes/columns are as below
PERSON_ID NUMBER,
USERNAME VARCHAR2,
PASSWORD VARCHAR2,
JOG_QUESTION VARCHAR2,
JOG_ANSWER VARCHAR2,
EMAIL VARCHAR2,
PREFIX_NAME VARCHAR2,
FIRST_NAME VARCHAR2,
- WEBLOG
An object which has blog details persisted. In project.net a space (personal, business, project, etc) can have blog attached to it.
Important attributes/columns are as below
WEBLOG_ID NUMBER,
NAME VARCHAR2,
DESCRIPTION VARCHAR2,
PERSON_ID NUMBER,
ALLOW_COMMENTS NUMBER,
EMAIL_COMMENTS NUMBER,
EMAIL_FROM_ADDRESS VARCHAR2,
EMAIL_ADDRESS VARCHAR2,
LOCALE VARCHAR2,
TIMEZONE VARCHAR2,
IS_ENABLED NUMBER,
IS_ACTIVE NUMBER,
CREATED_DATE DATE,
DEFAULT_ALLOW_COMMENTS NUMBER
- WEBLOG_COMMENT
Any comments added to blog entries are persisted into this object.
COMMENT_ID NUMBER,
WEBLOG_ENTRY_ID NUMBER,
NAME VARCHAR2,
EMAIL VARCHAR2,
URL VARCHAR2,
CONTENT CLOB,
POST_TIME DATE NOT NULL ENABLE,
NOTIFY NUMBER,
REMOTE_HOST VARCHAR2,
REFERRER VARCHAR2,
USER_AGENT VARCHAR2,
STATUS VARCHAR2
- WEBLOG_ENTRY
A blog has many entries, which are persisted and linked with blog entry object.
WEBLOG_ENTRY_ID NUMBER,
PERSON_ID NUMBER,
ANCHOR VARCHAR2,
TITLE VARCHAR2,
TEXT CLOB NOT NULL ENABLE,
PUB_TIME DATE,
UPDATE_TIME DATE NOT NULL ENABLE,
WEBLOG_ID NUMBER,
PUBLISH_ENTRY NUMBER,
LINK VARCHAR2,
ALLOW_COMMENTS NUMBER,
COMMENT_DAYS NUMBER,
RIGHT_TO_LEFT NUMBER,
LOCALE VARCHAR2,
STATUS VARCHAR2
- WEBLOG_ENTRY_ATTRIBUTE
Entry attributes are used to store generic attributes of blog entry. Currently space id to which this entry is linked is persisted as attribute, also the flags like ‘important’ and persisted as attributes. In future these will be used to add additional attributes such as type of entry viz. timesheet, daily updates, status change, etc.
WEBLOG_ENTRY_ATTRIBUTE_ID NUMBER,
WEBLOG_ENTRY_ID NUMBER,
NAME VARCHAR2,
VALUE VARCHAR2
Database interface
Project.net blog uses following database objects; any database that has these objects, blog feature can be ported to run on it. In other words these table objects can reside on different system for functioning of independent blog module.
WEBLOG
WEBLOG_ENTRY
WEBLOG_ENTRY_ATTRIBUTES
WEBLOG_COMMENT
Service Layer
Implementation approach
Service layer has been implemented using hibernate and spring layer. Hibernate mapping files are not kept completely in separate configuration file; however this does not avoid or restrict the decoupling of blog module in future.
Internal implementation is internal to blog feature; the interaction with outside application has been done by IBlogProvider interface. This interface defines the functionality to be provided by the blog implementation; so that project.net can be integrated with multiple blog providers and the blog functionality are completely pluggable for project.net.
Implementation
Hibernate Persistence class for WEBLOG
public class PnWeblog? implements Serializable {
// primary key
private java.lang.Integer weblogId;
// fields
private java.lang.String name;
private java.lang.String description;
private java.lang.Integer allowComments;
private java.lang.Integer emailComments;
private java.lang.String emailFromAddress;
private java.lang.String emailAddress;
private java.lang.String locale;
private java.lang.String timezone;
private java.lang.Integer isEnabled;
private java.lang.Integer isActive;
private java.util.Date createdDate;
private java.lang.Integer defaultAllowComments;
Hibernate persistence class for WEBLOG_COMMENT
public class PnWeblogComment? implements Serializable {
// primary key
private java.lang.Integer commentId;
// fields
private java.lang.String name;
private java.lang.String email;
private java.lang.String url;
private java.lang.String content;
private java.util.Date postTime;
private java.lang.Integer notify;
private java.lang.String remoteHost;
private java.lang.String referrer;
private java.lang.String userAgent;
Hibernate persistence class for WEBLOG_ENTRY
public class PnWeblogEntry? implements Serializable {
// primary key
private java.lang.Integer weblogEntryId;
// fields
private java.lang.String anchor;
private java.lang.String title;
private java.lang.String text;
private java.util.Date pubTime;
private java.util.Date updateTime;
private java.lang.Integer publishEntry;
private java.lang.String link;
private java.lang.Integer allowComments;
private java.lang.Integer commentDays;
private java.lang.Integer rightToLeft;
private java.lang.String locale;
private java.lang.String status;
private java.lang.String summary;
private java.lang.String contentType;
private java.lang.String contentSrc;
private java.lang.String isImportant;
private java.lang.String pubTimeString;
Hibernate persistence class for WEBLOG_ENTRY_ATTRIBUTE
public class PnWeblogEntryAttribute? implements Serializable {
// primary key
private java.lang.Integer weblogEntryAttributeId;
// fields
private java.lang.String name;
private java.lang.String value;
Each of the above class has spring service interface and implementation class attached to each hibernate object.
This implementation is abstracted by IBlogProvider interface which is implemented by RollerBlogProvider?.
RollerBlogProvider? is an implementation of Roller blog functionality for project.net.
Service Interface
Blog feature exposes the blog functionality with the help of interface IBlogProvider which has following public methods …
public interface IBlogProvider {
public static final String DESCENDING = "DESCENDING";
public static final String ASCENDING = "ASCENDING";
public java.lang.Integer saveWeblog(PnWeblog? data);
public void removeWeblog(PnWeblog? website);
public PnWeblog? getWeblog(Integer userId);
public List getWeblogs(
PnUser? user,
Boolean enabled,
Boolean active,
Date startDate,
Date endDate,
int offset,
int length);
public List getMostCommentedWeblogs(
Date startDate,
Date endDate,
int offset,
int length);
public java.lang.Integer saveWeblogEntry(PnWeblogEntry? entry);
public void updateWeblogEntry(PnWeblogEntry? entry);
public void removeWeblogEntry(PnWeblogEntry? entry);
public PnWeblogEntry? getWeblogEntry(Integer id);
public PnWeblogEntry? getWeblogEntryByAnchor(PnWeblog? website, String anchor) ;
public List getWeblogEntries(
Integer weblogId,
Integer userId,
Date startDate,
Date endDate,
String status,
int offset,
int range);
public PnWeblogEntryAttribute? getWeblogEntryAtribute(Integer weblogEntryId, String name);
public PnWeblog? getWeblogBySpaceId(Integer spaceId);
public Map getWeblogEntryObjectMap(
PnWeblog? website,
Date startDate,
Date endDate,
String catName,
List tags,
String status,
String locale,
int offset,
int range);
public Map getWeblogEntryStringMap(
PnWeblog? website,
Date startDate,
Date endDate,
String catName,
List tags,
String status,
String locale,
int offset,
int range);
public List getMostCommentedWeblogEntries(
PnWeblog? website,
Date startDate,
Date endDate,
int offset,
int length);
public PnWeblogEntry? getNextEntry(PnWeblogEntry? current, String catName, String locale);
public PnWeblogEntry? getPreviousEntry(PnWeblogEntry? current, String catName, String locale);
public List getWeblogEntriesPinnedToMain(Integer max);
public java.lang.Integer saveWeblogEntryAttribute(PnWeblogEntryAttribute? pnWeblogEntryAttribute);
public void updateWeblogEntryAttribute(PnWeblogEntryAttribute? pnWeblogEntryAttribute);
public void removeWeblogEntryAttribute(PnWeblogEntryAttribute? attribute);
public void saveComment(PnWeblogComment? comment);
public void removeComment(PnWeblogComment? comment);
public PnWeblogComment? getComment(String id);
public List getComments(
PnWeblog? website,
PnWeblogComment? entry,
String searchString,
Date startDate,
Date endDate,
String status,
boolean reverseChrono,
int offset,
int length);
public int removeMatchingComments(
PnWeblog? website,
PnWeblogComment? entry,
String searchString,
Date startDate,
Date endDate,
String status);
public void applyCommentDefaultsToEntries(PnWeblog? website);
public void release();
}
User Interface
Implementation approach
UI components are developed using Tapestry5 components. Blog feature has separate components for blog post, blog edit and blog view. Comment functionality is also been developed as Tapestry5 component for new and edit.
Implementation
Tapestry components developed for blog functionality interact with blog functionality by using interface IBlogProvider. However the UI components in project.net are tightly integrated with project.net functionality. E.g posting a new blog entry has facility to select the assignment, this makes tapestry component to interact with other project.net functionality from within the component. Hence it is common that the components interact with project.net as well as blog feature for rendering the single UI.
UI interface
Generic UI components
AddWeblogEntryComment? - depend only on IBlogProvider.
Project.net internal components
AddWeblogEntry?
BlogArchives?
BlogTeam?
ViewBlog?
These components are reusable internal to project.net, because they depend on project.net internal functionality as well as IBlogProvider
Other layers
Future plan
Other external layers are not been the part of blog functionality yet. It was considered that the maximum of functionality is kept reusable and customize it for project.net wherever required.
