Merged in changes from trunk

git-svn-id: https://svn.apache.org/repos/asf/rave/branches/mongo@1428516 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/UPGRADING b/UPGRADING
new file mode 100644
index 0000000..f3e5694
--- /dev/null
+++ b/UPGRADING
@@ -0,0 +1,4 @@
+Upgrading from 0.17 to 0.18
+=======================================
+  - rave.shindig.properties & portal.properties keys have been changed for JPA operations.  The prefix is now jpa.xxx.xxxx
+  - the MongoDB implementation has properties added to rave.shindig.properties and portal.properties
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 2dd5586..d165168 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,7 +17,8 @@
   specific language governing permissions and limitations
   under the License.
   -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 
     <modelVersion>4.0.0</modelVersion>
 
@@ -47,6 +48,7 @@
         <org.springframework.version>3.2.0.RELEASE</org.springframework.version>
         <org.springframework.security.version>3.1.3.RELEASE</org.springframework.security.version>
         <org.springframework.mobile.version>1.0.1.RELEASE</org.springframework.mobile.version>
+        <org.springframework.data.mongodb.version>1.0.3.RELEASE</org.springframework.data.mongodb.version>
         <jstl.version>1.2</jstl.version>
         <javax.servlet.version>2.5</javax.servlet.version>
         <jsp-api.version>2.1</jsp-api.version>
@@ -76,6 +78,8 @@
         <javax.mail.version>1.4.5</javax.mail.version>
         <javax.activation.version>1.1.1</javax.activation.version>
         <freemarker.version>2.3.19</freemarker.version>
+        <org.mongodb.driver.version>2.9.1</org.mongodb.driver.version>
+        <de.flapdoodle.embed.mongo.version>1.28</de.flapdoodle.embed.mongo.version>
         <!-- The location of Rave's H2 file DB. No trailing / -->
         <rave.database.location>/tmp/rave_db</rave.database.location>
 
@@ -86,7 +90,8 @@
         <cargo.version>1.3.1</cargo.version>
         <!-- default empty javaagent
         if needed you can specify it on the command line with -Djavaagent="..." -->
-        <javaagent />
+        <javaagent/>
+        <maven-war-plugin.version>2.3</maven-war-plugin.version>
     </properties>
 
     <repositories>
@@ -120,6 +125,11 @@
             </dependency>
             <dependency>
                 <groupId>org.apache.rave</groupId>
+                <artifactId>rave-mongodb</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.rave</groupId>
                 <artifactId>rave-web</artifactId>
                 <version>${project.version}</version>
             </dependency>
@@ -150,7 +160,7 @@
                 <version>${project.version}</version>
                 <type>pom</type>
             </dependency>
-             <dependency>
+            <dependency>
                 <groupId>org.apache.rave</groupId>
                 <artifactId>rave-demo-gadgets</artifactId>
                 <version>${project.version}</version>
@@ -204,9 +214,9 @@
                 <version>${org.springframework.version}</version>
             </dependency>
             <dependency>
-              <groupId>org.springframework</groupId>
-              <artifactId>spring-context-support</artifactId>
-              <version>${org.springframework.version}</version>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring-context-support</artifactId>
+                <version>${org.springframework.version}</version>
             </dependency>
             <dependency>
                 <groupId>org.springframework</groupId>
@@ -280,9 +290,9 @@
             </dependency>
 
             <dependency>
-               <groupId>org.springframework</groupId>
-               <artifactId>spring-oxm</artifactId>
-               <version>${org.springframework.version}</version>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring-oxm</artifactId>
+                <version>${org.springframework.version}</version>
             </dependency>
 
             <dependency>
@@ -291,14 +301,25 @@
                 <version>${org.springframework.version}</version>
             </dependency>
             <dependency>
-                 <groupId>org.springframework.mobile</groupId>
-                 <artifactId>spring-mobile-device</artifactId>
-                 <version>${org.springframework.mobile.version}</version>  <exclusions>
-                <exclusion>
-                    <groupId>org.springframework</groupId>
-                    <artifactId>spring-web</artifactId>
-                </exclusion>
-            </exclusions>
+                <groupId>org.springframework.mobile</groupId>
+                <artifactId>spring-mobile-device</artifactId>
+                <version>${org.springframework.mobile.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.springframework</groupId>
+                        <artifactId>spring-web</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.data</groupId>
+                <artifactId>spring-data-mongodb</artifactId>
+                <version>${org.springframework.data.mongodb.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.codehaus.jackson</groupId>
+                <artifactId>jackson-mapper-asl</artifactId>
+                <version>${jackson.version}</version>
             </dependency>
             <dependency>
                 <groupId>org.codehaus.jackson</groupId>
@@ -335,6 +356,16 @@
                 <artifactId>h2</artifactId>
                 <version>${com.h2database.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.mongodb</groupId>
+                <artifactId>mongo-java-driver</artifactId>
+                <version>${org.mongodb.driver.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>de.flapdoodle.embed</groupId>
+                <artifactId>de.flapdoodle.embed.mongo</artifactId>
+                <version>${de.flapdoodle.embed.mongo.version}</version>
+            </dependency>
 
             <dependency>
                 <groupId>com.sun.jersey</groupId>
@@ -376,10 +407,10 @@
                 <version>${org.openid4java.version}</version>
                 <type>pom</type>
                 <exclusions>
-                   <exclusion>
-                      <groupId>com.google.code.guice</groupId>
-                      <artifactId>guice</artifactId>
-                   </exclusion>
+                    <exclusion>
+                        <groupId>com.google.code.guice</groupId>
+                        <artifactId>guice</artifactId>
+                    </exclusion>
                 </exclusions>
             </dependency>
 
@@ -464,23 +495,23 @@
                 <version>${recaptcha4j.version}</version>
             </dependency>
             <!-- Mail-->
-          <dependency>
-            <groupId>javax.mail</groupId>
-            <artifactId>mail</artifactId>
-            <version>${javax.mail.version}</version>
-            <scope>provided</scope>
-          </dependency>
-          <dependency>
-            <groupId>javax.activation</groupId>
-            <artifactId>activation</artifactId>
-            <version>${javax.activation.version}</version>
-            <scope>provided</scope>
-          </dependency>
-          <dependency>
-            <groupId>org.freemarker</groupId>
-            <artifactId>freemarker</artifactId>
-            <version>${freemarker.version}</version>
-          </dependency>
+            <dependency>
+                <groupId>javax.mail</groupId>
+                <artifactId>mail</artifactId>
+                <version>${javax.mail.version}</version>
+                <scope>provided</scope>
+            </dependency>
+            <dependency>
+                <groupId>javax.activation</groupId>
+                <artifactId>activation</artifactId>
+                <version>${javax.activation.version}</version>
+                <scope>provided</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.freemarker</groupId>
+                <artifactId>freemarker</artifactId>
+                <version>${freemarker.version}</version>
+            </dependency>
 
             <!-- ApacheDS (LDAP) -->
             <dependency>
@@ -496,7 +527,7 @@
             </dependency>
 
 
-          <!-- Test -->
+            <!-- Test -->
             <dependency>
                 <groupId>junit</groupId>
                 <artifactId>junit</artifactId>
@@ -573,7 +604,7 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-war-plugin</artifactId>
-                    <version>2.3</version>
+                    <version>${maven-war-plugin.version}</version>
                 </plugin>
                 <plugin>
                     <groupId>com.googlecode.mavenfilesync</groupId>
@@ -593,7 +624,7 @@
                 <plugin>
                     <groupId>org.codehaus.mojo</groupId>
                     <artifactId>cobertura-maven-plugin</artifactId>
-                    <version>${cobertura.version}</version> 
+                    <version>${cobertura.version}</version>
                     <configuration>
                         <formats>
                             <format>html</format>
@@ -619,7 +650,7 @@
                                         </goals>
                                     </pluginExecutionFilter>
                                     <action>
-                                        <execute />
+                                        <execute/>
                                     </action>
                                 </pluginExecution>
                                 <pluginExecution>
@@ -632,7 +663,7 @@
                                         </goals>
                                     </pluginExecutionFilter>
                                     <action>
-                                        <execute />
+                                        <execute/>
                                     </action>
                                 </pluginExecution>
                                 <pluginExecution>
@@ -645,7 +676,7 @@
                                         </goals>
                                     </pluginExecutionFilter>
                                     <action>
-                                        <execute />
+                                        <execute/>
                                     </action>
                                 </pluginExecution>
                                 <pluginExecution>
@@ -659,7 +690,7 @@
                                         </goals>
                                     </pluginExecutionFilter>
                                     <action>
-                                        <execute />
+                                        <execute/>
                                     </action>
                                 </pluginExecution>
                             </pluginExecutions>
@@ -702,6 +733,15 @@
     </modules>
     <profiles>
         <profile>
+            <id>jpa</id>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+        </profile>
+        <profile>
+            <id>mongodb</id>
+        </profile>
+        <profile>
             <id>apache-release</id>
             <build>
                 <plugins>
diff --git a/rave-components/pom.xml b/rave-components/pom.xml
index 44d4fa1..8dadec3 100644
--- a/rave-components/pom.xml
+++ b/rave-components/pom.xml
@@ -38,6 +38,7 @@
         <module>rave-commons</module>
         <module>rave-core</module>
         <module>rave-jpa</module>
+        <module>rave-mongodb</module>
         <module>rave-web</module>
     </modules>
     
diff --git a/rave-components/rave-core/pom.xml b/rave-components/rave-core/pom.xml
index a3803f9..9261b14 100644
--- a/rave-components/rave-core/pom.xml
+++ b/rave-components/rave-core/pom.xml
@@ -89,6 +89,12 @@
         <dependency>
             <groupId>org.codehaus.jackson</groupId>
             <artifactId>jackson-mapper-asl</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-mrbean</artifactId>
+            <scope>provided</scope>
         </dependency>
 
         <!-- JSON Support -->
diff --git a/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/RegionWidget.java b/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/RegionWidget.java
index 7b899e2..8fe2421 100644
--- a/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/RegionWidget.java
+++ b/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/RegionWidget.java
@@ -60,4 +60,6 @@
     boolean isHideChrome();
 
     void setHideChrome(boolean hideChrome);
+
+
 }
diff --git a/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/WidgetComment.java b/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/WidgetComment.java
index e91a553..5a18b02 100644
--- a/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/WidgetComment.java
+++ b/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/WidgetComment.java
@@ -40,4 +40,6 @@
 
     Date getCreatedDate();
     void setCreatedDate(Date created);
+
+
 }
diff --git a/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/CategoryImpl.java b/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/CategoryImpl.java
index 33cdd1c..2de5dbf 100644
--- a/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/CategoryImpl.java
+++ b/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/CategoryImpl.java
@@ -40,6 +40,11 @@
         this.id = id;

     }

 

+    public CategoryImpl(String id, String text) {

+        this.id=id;

+        this.text = text;

+    }

+

     @Override

     public String getId() {

         return id;

diff --git a/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/PageUserImpl.java b/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/PageUserImpl.java
index dff890d..f369ab7 100644
--- a/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/PageUserImpl.java
+++ b/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/PageUserImpl.java
@@ -19,15 +19,18 @@
 package org.apache.rave.portal.model.impl;

 

 import org.apache.rave.portal.model.*;

+import org.codehaus.jackson.annotate.JsonBackReference;

 

 public class PageUserImpl implements PageUser {

     private String id;

     private String userId;

-    private Page page;

     private boolean editor;

     private Long renderSequence;

     private PageInvitationStatus pageStatus;

 

+    @JsonBackReference

+    private Page page;

+

     public PageUserImpl(){}

 

     public PageUserImpl(String id){

@@ -104,4 +107,33 @@
     public void setPageStatus(PageInvitationStatus pageStatus) {

         this.pageStatus = pageStatus;

     }

+

+    @Override

+    public boolean equals(Object o) {

+        if (this == o) return true;

+        if (!(o instanceof PageUserImpl)) return false;

+

+        PageUserImpl pageUser = (PageUserImpl) o;

+

+        if (editor != pageUser.editor) return false;

+        if (id != null ? !id.equals(pageUser.id) : pageUser.id != null) return false;

+        if (page != null ? !page.equals(pageUser.page) : pageUser.page != null) return false;

+        if (pageStatus != pageUser.pageStatus) return false;

+        if (renderSequence != null ? !renderSequence.equals(pageUser.renderSequence) : pageUser.renderSequence != null)

+            return false;

+        if (userId != null ? !userId.equals(pageUser.userId) : pageUser.userId != null) return false;

+

+        return true;

+    }

+

+    @Override

+    public int hashCode() {

+        int result = id != null ? id.hashCode() : 0;

+        result = 31 * result + (userId != null ? userId.hashCode() : 0);

+        result = 31 * result + (editor ? 1 : 0);

+        result = 31 * result + (renderSequence != null ? renderSequence.hashCode() : 0);

+        result = 31 * result + (pageStatus != null ? pageStatus.hashCode() : 0);

+        result = 31 * result + (page != null ? page.hashCode() : 0);

+        return result;

+    }

 }

diff --git a/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/RegionImpl.java b/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/RegionImpl.java
index 598639d..f7e7d40 100644
--- a/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/RegionImpl.java
+++ b/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/RegionImpl.java
@@ -21,6 +21,7 @@
 import org.apache.rave.portal.model.Page;
 import org.apache.rave.portal.model.Region;
 import org.apache.rave.portal.model.RegionWidget;
+import org.codehaus.jackson.annotate.JsonBackReference;
 
 import java.util.List;
 
@@ -55,6 +56,7 @@
     }
 
     @Override
+    @JsonBackReference
     public Page getPage() {
         return page;
     }
diff --git a/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/RegionWidgetImpl.java b/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/RegionWidgetImpl.java
index 6926b1e..5033fd2 100644
--- a/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/RegionWidgetImpl.java
+++ b/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/RegionWidgetImpl.java
@@ -21,14 +21,13 @@
 import org.apache.rave.portal.model.Region;
 import org.apache.rave.portal.model.RegionWidget;
 import org.apache.rave.portal.model.RegionWidgetPreference;
-import org.apache.rave.portal.model.Widget;
+import org.codehaus.jackson.annotate.JsonBackReference;
 
 import java.util.List;
 
 public class RegionWidgetImpl implements RegionWidget {
     private String id;
     private String widgetId;
-    private Region region;
     private String renderPosition;
     private Integer renderOrder = 0;
     private Boolean collapsed = false;
@@ -36,6 +35,9 @@
     private Boolean locked = false;
     private Boolean hideChrome = false;
 
+    @JsonBackReference
+    private Region region;
+
     public RegionWidgetImpl() {
 
     }
diff --git a/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/UserImpl.java b/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/UserImpl.java
index d6f91e0..485c9fc 100644
--- a/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/UserImpl.java
+++ b/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/UserImpl.java
@@ -146,6 +146,7 @@
 
     public Person toPerson() {
         PersonImpl p = new PersonImpl();
+        p.setId(this.getId());
         p.setAboutMe(this.getAboutMe());
         p.setAdditionalName(this.getAdditionalName());
         p.setAddresses(this.getAddresses());
diff --git a/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/WidgetRatingImpl.java b/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/WidgetRatingImpl.java
index 623dc3b..7ce1103 100644
--- a/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/WidgetRatingImpl.java
+++ b/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/WidgetRatingImpl.java
@@ -23,7 +23,6 @@
 public class WidgetRatingImpl implements WidgetRating {
 
     private String id;
-    private String widgetId;
     private String userId;
     private Integer score;
 
@@ -34,7 +33,7 @@
         this.id = id;
     }
 
-    public WidgetRatingImpl(String id, String userId, int score) {
+    public WidgetRatingImpl(String id, String userId, Integer score) {
         this.id = id;
         this.userId = userId;
         this.score = score;
@@ -74,7 +73,6 @@
         if (id != null ? !id.equals(that.id) : that.id != null) return false;
         if (score != null ? !score.equals(that.score) : that.score != null) return false;
         if (userId != null ? !userId.equals(that.userId) : that.userId != null) return false;
-        if (widgetId != null ? !widgetId.equals(that.widgetId) : that.widgetId != null) return false;
 
         return true;
     }
@@ -82,7 +80,6 @@
     @Override
     public int hashCode() {
         int result = id != null ? id.hashCode() : 0;
-        result = 31 * result + (widgetId != null ? widgetId.hashCode() : 0);
         result = 31 * result + (userId != null ? userId.hashCode() : 0);
         result = 31 * result + (score != null ? score.hashCode() : 0);
         return result;
diff --git a/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/WidgetTagImpl.java b/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/WidgetTagImpl.java
index e774303..0848679 100644
--- a/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/WidgetTagImpl.java
+++ b/rave-components/rave-core/src/main/java/org/apache/rave/portal/model/impl/WidgetTagImpl.java
@@ -30,6 +30,9 @@
     private String tagId;
     private Date createdDate;
 
+    public WidgetTagImpl() {
+    }
+
     public WidgetTagImpl(User user, Date createdDate, Tag tag) {
         this.userId = user.getId();
         this.tagId = tag.getId();
diff --git a/rave-components/rave-core/src/main/java/org/apache/rave/portal/repository/PageTemplateRepository.java b/rave-components/rave-core/src/main/java/org/apache/rave/portal/repository/PageTemplateRepository.java
index 0558d69..ea76262 100644
--- a/rave-components/rave-core/src/main/java/org/apache/rave/portal/repository/PageTemplateRepository.java
+++ b/rave-components/rave-core/src/main/java/org/apache/rave/portal/repository/PageTemplateRepository.java
@@ -27,4 +27,5 @@
 

     List<PageTemplate> getAll();

     PageTemplate getDefaultPage(PageType pageType);

+    PageTemplate save(PageTemplate template);

 }

diff --git a/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultOmdlService.java b/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultOmdlService.java
index a083ddc..26344e5 100644
--- a/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultOmdlService.java
+++ b/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultOmdlService.java
@@ -18,31 +18,12 @@
  */

 package org.apache.rave.portal.service.impl;

 

-import java.io.File;

-import java.io.IOException;

-import java.io.StringReader;

-import java.util.List;

-

-import javax.xml.parsers.DocumentBuilder;

-import javax.xml.parsers.DocumentBuilderFactory;

-import javax.xml.parsers.ParserConfigurationException;

-

 import org.apache.commons.io.FileUtils;

 import org.apache.rave.exception.DuplicateItemException;

 import org.apache.rave.portal.model.Page;

 import org.apache.rave.portal.model.Widget;

-import org.apache.rave.portal.model.impl.WidgetImpl;

-import org.apache.rave.portal.model.util.omdl.BadOmdlXmlFormatException;

-import org.apache.rave.portal.model.util.omdl.OmdlConstants;

-import org.apache.rave.portal.model.util.omdl.OmdlInputAdapter;

-import org.apache.rave.portal.model.util.omdl.OmdlModelUtils;

-import org.apache.rave.portal.model.util.omdl.OmdlOutputAdapter;

-import org.apache.rave.portal.model.util.omdl.OmdlWidgetReference;

-import org.apache.rave.portal.service.OmdlService;

-import org.apache.rave.portal.service.PageService;

-import org.apache.rave.portal.service.UserService;

-import org.apache.rave.portal.service.RemoteWidgetResolverService;

-import org.apache.rave.portal.service.WidgetService;

+import org.apache.rave.portal.model.util.omdl.*;

+import org.apache.rave.portal.service.*;

 import org.slf4j.LoggerFactory;

 import org.springframework.beans.factory.annotation.Autowired;

 import org.springframework.beans.factory.annotation.Value;

@@ -54,6 +35,14 @@
 import org.w3c.dom.NodeList;

 import org.xml.sax.InputSource;

 import org.xml.sax.SAXException;

+

+import javax.xml.parsers.DocumentBuilder;

+import javax.xml.parsers.DocumentBuilderFactory;

+import javax.xml.parsers.ParserConfigurationException;

+import java.io.File;

+import java.io.IOException;

+import java.io.StringReader;

+import java.util.List;

 /**

  * This class is responsible for the import and export of page objects to/from OMDL format

  * 

diff --git a/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultPageService.java b/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultPageService.java
index 4ff4736..086729c 100644
--- a/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultPageService.java
+++ b/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultPageService.java
@@ -206,7 +206,7 @@
         RegionWidget regionWidget = regionWidgetRepository.get(regionWidgetId);

         verifyRegionWidgetIsNotLocked(regionWidget);

         verifyRegionIsNotLocked(target);

-        if (toRegionId == fromRegionId) {

+        if (toRegionId.equals(fromRegionId)) {

             moveWithinRegion(regionWidgetId, newPosition, target);

         } else {

             moveBetweenRegions(regionWidgetId, newPosition, fromRegionId, target);

@@ -223,6 +223,8 @@
         // Get the region widget

         RegionWidget regionWidget = getFromRepository(regionWidgetId, regionWidgetRepository);

 

+        Region moveFromRegion = regionWidget.getRegion();

+

         // Move it to first position of the first region

         Region moveToRegion = toPage.getRegions().get(0);

 

@@ -233,10 +235,14 @@
         regionWidget.setRenderOrder(0);

         regionWidget.setRegion(moveToRegion);

         moveToRegion.getRegionWidgets().add(0, regionWidget);

+        //remove it from the old region

+        moveFromRegion.getRegionWidgets().remove(regionWidget);

         // update the rendersequences of the widgets in this region

         updateRenderSequences(moveToRegion.getRegionWidgets());

+        updateRenderSequences(moveFromRegion.getRegionWidgets());

         // persist it

         regionRepository.save(moveToRegion);

+        regionRepository.save(moveFromRegion);

         return getFromRepository(regionWidgetId, regionWidgetRepository);

     }

 

@@ -318,7 +324,6 @@
 

     @Transactional

     public Boolean clonePageForUser(String pageId, String userId, String pageName) {

-        Widget widget = null;

         Page page = getPage(pageId);

         if(pageName == null || pageName.equals("null")){

             // try to use the original page name if none supplied

@@ -329,10 +334,10 @@
         for(int i=0; i<page.getRegions().size(); i++){

             for(int j=0; j<page.getRegions().get(i).getRegionWidgets().size(); j++){

                 String widgetId = page.getRegions().get(i).getRegionWidgets().get(j).getWidgetId();

-                widget = widgetRepository.get(widgetId);

-                addWidgetToPageRegion(clonedPage.getId(), widget.getId(), clonedPage.getRegions().get(i).getId());

+                addWidgetToPageRegion(clonedPage.getId(), widgetId, clonedPage.getRegions().get(i).getId());

             }

         }

+        clonedPage = getFromRepository(clonedPage.getId(), pageRepository);

         // newly created page - so only one pageUser

         PageUser pageUser = clonedPage.getMembers().get(0);

         // update status to pending

diff --git a/rave-components/rave-core/src/main/java/org/apache/rave/portal/util/data/DataImporter.java b/rave-components/rave-core/src/main/java/org/apache/rave/portal/util/data/DataImporter.java
new file mode 100644
index 0000000..02c2313
--- /dev/null
+++ b/rave-components/rave-core/src/main/java/org/apache/rave/portal/util/data/DataImporter.java
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.util.data;
+
+import org.apache.rave.portal.model.*;
+import org.apache.rave.portal.repository.*;
+import org.codehaus.jackson.map.AnnotationIntrospector;
+import org.codehaus.jackson.map.DeserializationConfig;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.introspect.JacksonAnnotationIntrospector;
+import org.codehaus.jackson.mrbean.MrBeanModule;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.Resource;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.PostConstruct;
+import java.io.IOException;
+import java.util.List;
+
+public class DataImporter {
+
+    private DataImporter.Executor dataExecutor;
+    private List<Resource> scriptLocations;
+
+    public List<Resource> getScriptLocations() {
+        return scriptLocations;
+    }
+
+    public void setScriptLocations(List<Resource> scriptLocations) {
+        this.scriptLocations = scriptLocations;
+    }
+
+    @PostConstruct
+    public void importData() {
+        if (scriptLocations != null && dataExecutor.needsLoading()) {
+            for (Resource resource : scriptLocations) {
+                ModelWrapper wrapper = mapObject(resource);
+                dataExecutor.loadData(wrapper);
+            }
+        }
+    }
+
+    public void setDataExecutor(Executor dataExecutor) {
+        this.dataExecutor = dataExecutor;
+    }
+
+    private ModelWrapper mapObject(Resource resource) {
+        try {
+            return getMapper().readValue(resource.getFile(), ModelWrapper.class);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private ObjectMapper getMapper() {
+        ObjectMapper jacksonMapper = new ObjectMapper();
+        AnnotationIntrospector primary = new JacksonAnnotationIntrospector();
+        jacksonMapper.setAnnotationIntrospector(primary);
+        jacksonMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+        jacksonMapper.registerModule(new MrBeanModule());
+        return jacksonMapper;
+    }
+
+    public static interface Executor {
+        boolean needsLoading();
+        void loadData(ModelWrapper models);
+    }
+
+    @Transactional
+    public static class ExecutorImpl implements Executor {
+
+        //TODO GROUP REPOSITORY
+        @Autowired
+        private PageLayoutRepository pageLayoutRepository;
+
+        @Autowired
+        private UserRepository userRepository;
+
+        @Autowired
+        private WidgetRepository widgetRepository;
+
+        @Autowired
+        private PageRepository pageRepository;
+
+        @Autowired
+        private AuthorityRepository authorityRepository;
+
+        @Autowired
+        private PortalPreferenceRepository portalPreferenceRepository;
+
+        @Autowired
+        private CategoryRepository categoryRepository;
+
+        @Autowired
+        private PageTemplateRepository pageTemplateRepository;
+
+        public boolean needsLoading() {
+            return widgetRepository.getCountAll() == 0;
+        }
+
+        @Transactional
+        public void loadData(ModelWrapper wrapper) {
+            if (wrapper.getPageLayouts() != null) {
+                for (PageLayout layout : wrapper.getPageLayouts()) {
+                    pageLayoutRepository.save(layout);
+                }
+            }
+            if (wrapper.getUsers() != null) {
+                for (User user : wrapper.getUsers()) {
+                    userRepository.save(user);
+                }
+            }
+            if (wrapper.getPageLayouts() != null) {
+                for (PageLayout layout : wrapper.getPageLayouts()) {
+                    pageLayoutRepository.save(layout);
+                }
+            }
+            if (wrapper.getWidgets() != null) {
+                for (Widget widget : wrapper.getWidgets()) {
+                    widgetRepository.save(widget);
+                }
+            }
+            if (wrapper.getPages() != null) {
+                for (Page page : wrapper.getPages()) {
+                    pageRepository.save(page);
+                }
+            }
+            if (wrapper.getAuthorities() != null) {
+                for (Authority authority : wrapper.getAuthorities()) {
+                    authorityRepository.save(authority);
+                }
+            }
+            if (wrapper.getPortalPreferences() != null) {
+                for (PortalPreference preference : wrapper.getPortalPreferences()) {
+                    portalPreferenceRepository.save(preference);
+                }
+            }
+            if (wrapper.getCategories() != null) {
+                for (Category category : wrapper.getCategories()) {
+                    categoryRepository.save(category);
+                }
+            }
+            for(PageTemplate template : wrapper.getPageTemplates()) {
+                pageTemplateRepository.save(template);
+            }
+        }
+    }
+}
diff --git a/rave-components/rave-core/src/main/java/org/apache/rave/portal/util/data/ModelWrapper.java b/rave-components/rave-core/src/main/java/org/apache/rave/portal/util/data/ModelWrapper.java
new file mode 100644
index 0000000..2921971
--- /dev/null
+++ b/rave-components/rave-core/src/main/java/org/apache/rave/portal/util/data/ModelWrapper.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.util.data;
+
+import org.apache.rave.portal.model.*;
+
+import java.util.List;
+
+public class ModelWrapper {
+    private List<PageLayout> pageLayouts;
+    private List<User> users;
+    private List<Group> groups;
+    private List<Widget> widgets;
+    private List<Page> pages;
+    private List<Authority> authorities;
+    private List<PortalPreference> portalPreferences;
+    private List<Category> categories;
+    private List<PageTemplate> pageTemplates;
+
+    public List<PageLayout> getPageLayouts() {
+        return pageLayouts;
+    }
+
+    public void setPageLayouts(List<PageLayout> pageLayouts) {
+        this.pageLayouts = pageLayouts;
+    }
+
+    public List<User> getUsers() {
+        return users;
+    }
+
+    public void setUsers(List<User> users) {
+        this.users = users;
+    }
+
+    public List<Group> getGroups() {
+        return groups;
+    }
+
+    public void setGroups(List<Group> groups) {
+        this.groups = groups;
+    }
+
+    public List<Widget> getWidgets() {
+        return widgets;
+    }
+
+    public void setWidgets(List<Widget> widgets) {
+        this.widgets = widgets;
+    }
+
+    public List<Page> getPages() {
+        return pages;
+    }
+
+    public void setPages(List<Page> pages) {
+        this.pages = pages;
+    }
+
+    public List<Authority> getAuthorities() {
+        return authorities;
+    }
+
+    public void setAuthorities(List<Authority> authorities) {
+        this.authorities = authorities;
+    }
+
+    public List<PortalPreference> getPortalPreferences() {
+        return portalPreferences;
+    }
+
+    public void setPortalPreferences(List<PortalPreference> portalPreferences) {
+        this.portalPreferences = portalPreferences;
+    }
+
+    public List<Category> getCategories() {
+        return categories;
+    }
+
+    public void setCategories(List<Category> categories) {
+        this.categories = categories;
+    }
+
+    public List<PageTemplate> getPageTemplates() {
+        return pageTemplates;
+    }
+
+    public void setPageTemplates(List<PageTemplate> pageTemplates) {
+        this.pageTemplates = pageTemplates;
+    }
+}
\ No newline at end of file
diff --git a/rave-components/rave-core/src/main/resources/org/apache/rave/core-applicationContext.xml b/rave-components/rave-core/src/main/resources/org/apache/rave/core-applicationContext.xml
index 93b900f..7915fba 100644
--- a/rave-components/rave-core/src/main/resources/org/apache/rave/core-applicationContext.xml
+++ b/rave-components/rave-core/src/main/resources/org/apache/rave/core-applicationContext.xml
@@ -50,13 +50,6 @@
     <context:component-scan base-package="org.apache.rave.portal.service"/>
     <context:component-scan base-package="org.apache.rave.portal.security"/>
 
-    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
-        <property name="url" value="${portal.dataSource.url}"/>
-        <property name="driverClassName" value="${portal.dataSource.driver}"/>
-        <property name="username" value="${portal.dataSource.username}"/>
-        <property name="password" value="${portal.dataSource.password}"/>
-    </bean>
-
     <!-- Password encoding -->
     <bean class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" id="passwordEncoder">
         <!--<constructor-arg index="0" value="10"/>-->
diff --git a/rave-components/rave-core/src/test/java/org/apache/rave/portal/service/impl/DefaultPageServiceTest.java b/rave-components/rave-core/src/test/java/org/apache/rave/portal/service/impl/DefaultPageServiceTest.java
index 72dd508..00870c2 100644
--- a/rave-components/rave-core/src/test/java/org/apache/rave/portal/service/impl/DefaultPageServiceTest.java
+++ b/rave-components/rave-core/src/test/java/org/apache/rave/portal/service/impl/DefaultPageServiceTest.java
@@ -19,6 +19,7 @@
 

 package org.apache.rave.portal.service.impl;

 

+import com.google.common.collect.Lists;

 import org.apache.rave.portal.model.Page;

 import org.apache.rave.portal.model.PageLayout;

 import org.apache.rave.portal.model.PageTemplate;

@@ -1307,21 +1308,25 @@
 

         Region region = new RegionImpl();

         region.setLocked(false);

+        region.setRegionWidgets(Lists.<RegionWidget>newArrayList());

 

         RegionWidget regionWidget = new RegionWidgetImpl(VALID_REGION_WIDGET_ID);

         regionWidget.setRegion(region);

+        region.getRegionWidgets().add(regionWidget);

 

         expect(pageRepository.get(TO_PAGE_ID)).andReturn(toPageValue);

         expect(regionWidgetRepository.get(WIDGET_ID)).andReturn(regionWidget).times(2);

+        expect(regionRepository.save(originalRegion)).andReturn(originalRegion);

+        expect(regionRepository.save(region)).andReturn(region);

 

-        replay(pageRepository);

-        replay(regionWidgetRepository);

+        replay(pageRepository, regionWidgetRepository, regionRepository);

 

         RegionWidget updatedRegionWidget = pageService.moveRegionWidgetToPage(VALID_REGION_WIDGET_ID, TO_PAGE_ID);

 

         verify(pageRepository);

         verify(regionWidgetRepository);

         verifyPositions(0, regionWidget, true);

+        assertThat(region.getRegionWidgets().isEmpty(), is(true));

 

     }

 

diff --git a/rave-components/rave-core/src/test/resources/portal.properties b/rave-components/rave-core/src/test/resources/portal.properties
index c563093..fb9966d 100644
--- a/rave-components/rave-core/src/test/resources/portal.properties
+++ b/rave-components/rave-core/src/test/resources/portal.properties
@@ -21,21 +21,21 @@
 portal.page.default_name=Main
 
 #Default Rave Portal database settings with in memory H2 database
-portal.dataSource.url=jdbc:h2:mem:portal;DB_CLOSE_DELAY=-1
-portal.dataSource.driver=org.h2.Driver
-portal.dataSource.username=sa
-portal.dataSource.password=local
+jpa.dataSource.url=jdbc:h2:mem:portal;DB_CLOSE_DELAY=-1
+jpa.dataSource.driver=org.h2.Driver
+jpa.dataSource.username=sa
+jpa.dataSource.password=local
 
-portal.jpaDialect=org.apache.rave.persistence.jpa.impl.H2OpenJpaDialect
-portal.jpaVendorAdapter.databasePlatform=org.apache.openjpa.jdbc.sql.H2Dictionary
-portal.jpaVendorAdapter.database=H2
+jpa.jpaDialect=org.apache.rave.persistence.jpa.impl.H2OpenJpaDialect
+jpa.jpaVendorAdapter.databasePlatform=org.apache.openjpa.jdbc.sql.H2Dictionary
+jpa.jpaVendorAdapter.database=H2
 
 # General Rave portal database settings
-portal.jpaVendorAdapter.showSql=true
-portal.openjpa.Log=DefaultLevel=WARN, Runtime=INFO, Tool=INFO, SQL=WARN
-portal.openjpa.RuntimeUnenhancedClasses=supported
-portal.openjpa.jdbc.SynchronizeMappings=buildSchema(ForeignKeys=true)
-portal.openjpa.jdbc.MappingDefaults=ForeignKeyDeleteAction=restrict, JoinForeignKeyDeleteAction=restrict
+jpa.jpaVendorAdapter.showSql=true
+jpa.openjpa.Log=DefaultLevel=WARN, Runtime=INFO, Tool=INFO, SQL=WARN
+jpa.openjpa.RuntimeUnenhancedClasses=supported
+jpa.openjpa.jdbc.SynchronizeMappings=buildSchema(ForeignKeys=true)
+jpa.openjpa.jdbc.MappingDefaults=ForeignKeyDeleteAction=restrict, JoinForeignKeyDeleteAction=restrict
 
 provider.wookie.wookieServerUrl=http://localhost:8080/wookie
 provider.wookie.wookieApiKey=TEST
diff --git a/rave-components/rave-jpa/src/main/java/org/apache/rave/portal/repository/impl/JpaPageTemplateRepository.java b/rave-components/rave-jpa/src/main/java/org/apache/rave/portal/repository/impl/JpaPageTemplateRepository.java
index fab22a8..1f611d8 100644
--- a/rave-components/rave-jpa/src/main/java/org/apache/rave/portal/repository/impl/JpaPageTemplateRepository.java
+++ b/rave-components/rave-jpa/src/main/java/org/apache/rave/portal/repository/impl/JpaPageTemplateRepository.java
@@ -21,6 +21,7 @@
 import org.apache.rave.portal.model.JpaPageTemplate;

 import org.apache.rave.portal.model.PageTemplate;

 import org.apache.rave.portal.model.PageType;

+import org.apache.rave.portal.model.conversion.JpaConverter;

 import org.apache.rave.portal.repository.PageTemplateRepository;

 import org.apache.rave.util.CollectionUtils;

 import org.springframework.stereotype.Repository;

@@ -30,6 +31,8 @@
 import javax.persistence.TypedQuery;

 import java.util.List;

 

+import static org.apache.rave.persistence.jpa.util.JpaUtil.saveOrUpdate;

+

 @Repository

 public class JpaPageTemplateRepository implements PageTemplateRepository {

 

@@ -48,4 +51,9 @@
         query.setParameter("pageType", pageType);

         return query.getSingleResult();

     }

+

+    @Override

+    public PageTemplate save(PageTemplate template) {

+        return (PageTemplate) saveOrUpdate(template.getId(), manager, JpaConverter.getInstance().convert(template, PageTemplate.class));

+    }

 }
\ No newline at end of file
diff --git a/rave-components/rave-jpa/src/main/resources/org/apache/rave/jpa-applicationContext.xml b/rave-components/rave-jpa/src/main/resources/org/apache/rave/jpa-applicationContext.xml
deleted file mode 100644
index 4634e17..0000000
--- a/rave-components/rave-jpa/src/main/resources/org/apache/rave/jpa-applicationContext.xml
+++ /dev/null
@@ -1,187 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements.  See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership.  The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied.  See the License for the
-  specific language governing permissions and limitations
-  under the License.
-  -->
-<beans xmlns="http://www.springframework.org/schema/beans"
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-       xmlns:context="http://www.springframework.org/schema/context"
-       xmlns:tx="http://www.springframework.org/schema/tx"
-       xmlns:p="http://www.springframework.org/schema/p"
-       xmlns:aop="http://www.springframework.org/schema/aop"
-       xsi:schemaLocation="http://www.springframework.org/schema/beans
-                           http://www.springframework.org/schema/beans/spring-beans.xsd
-        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
-        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
-        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
-
-    <!-- make the the portal.properties props available to autowire injectors, location of the properties can
-     be overridden by setting a system property "portal.override.properties" -->
-    <bean id="portalPropertyPlaceholder" class="org.apache.rave.util.OverridablePropertyPlaceholderConfigurer">
-        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
-        <property name="systemPropertyName" value="portal.override.properties"/>
-        <property name="location" value="classpath:portal.properties"/>
-    </bean>
-
-    <!-- bean post-processor for JPA annotations -->
-    <context:annotation-config/>
-
-    <!-- enable the use of the @AspectJ style of Spring AOP -->
-    <aop:aspectj-autoproxy/>
-
-    <!-- rave-common component base-package scan (maybe move to a separate common-applicationContext.xml?) -->
-    <context:component-scan base-package="org.apache.rave.service"/>
-    <context:component-scan base-package="org.apache.rave.synchronization"/>
-
-    <!-- rave-core component base-package scan -->
-    <context:component-scan base-package="org.apache.rave.portal.model"/>
-    <context:component-scan base-package="org.apache.rave.portal.repository"/>
-
-    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
-        <property name="entityManagerFactory" ref="entityManagerFactory"/>
-    </bean>
-
-    <tx:annotation-driven transaction-manager="transactionManager"/>
-
-    <bean id="entityManagerFactory"
-          class="org.apache.rave.persistence.jpa.PopulatedLocalContainerEntityManagerFactory">
-        <property name="populator" ref="dataSourcePopulator"/>
-        <property name="loadTimeWeaver">
-            <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
-        </property>
-        <property name="persistenceUnitName" value="ravePersistenceUnit"/>
-        <property name="dataSource" ref="dataSource"/>
-        <property name="jpaVendorAdapter">
-            <bean class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter"
-                  p:databasePlatform="${portal.jpaVendorAdapter.databasePlatform}"
-                  p:database="${portal.jpaVendorAdapter.database}"
-                  p:showSql="${portal.jpaVendorAdapter.showSql}"/>
-        </property>
-        <property name="jpaDialect">
-            <bean class="${portal.jpaDialect}"/>
-        </property>
-        <property name="jpaPropertyMap">
-            <map>
-                <entry key="openjpa.Log" value="${portal.openjpa.Log}"/>
-                <entry key="openjpa.RuntimeUnenhancedClasses" value="${portal.openjpa.RuntimeUnenhancedClasses}"/>
-                <entry key="openjpa.jdbc.SynchronizeMappings" value="${portal.openjpa.jdbc.SynchronizeMappings}"/>
-                <entry key="openjpa.jdbc.MappingDefaults" value="${portal.openjpa.jdbc.MappingDefaults}"/>
-            </map>
-        </property>
-    </bean>
-
-    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
-        <property name="url" value="${portal.dataSource.url}"/>
-        <property name="driverClassName" value="${portal.dataSource.driver}"/>
-        <property name="username" value="${portal.dataSource.username}"/>
-        <property name="password" value="${portal.dataSource.password}"/>
-    </bean>
-
-    <!-- Password encoding -->
-    <bean class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" id="passwordEncoder">
-        <!--<constructor-arg index="0" value="10"/>-->
-    </bean>
-
-    <!-- email settings -->
-    <bean id="emailServiceMailMessage" class="org.springframework.mail.SimpleMailMessage">
-        <property name="from" value="${portal.mail.sender}"/>
-        <property name="replyTo" value="${portal.mail.replyto}"/>
-    </bean>
-
-    <bean id="freemarkerMailConfiguration" class="org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean">
-        <property name="templateLoaderPath" value="/WEB-INF/mailtemplates"/>
-    </bean>
-    <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
-        <property name="host" value="${portal.mail.host}"/>
-        <property name="password" value="${portal.mail.password}"/>
-        <property name="username" value="${portal.mail.username}"/>
-        <property name="port" value="${portal.mail.port}"/>
-        <property name="protocol" value="${portal.mail.protocol}"/>
-        <!-- NOTE: if using Gmail, you'll need following properties-->
-        <!--<property name="javaMailProperties">
-            <props>
-                <prop key="mail.smtp.auth">true</prop>
-                <prop key="mail.smtp.starttls.enable">true</prop>
-                <prop key="mail.smtp.timeout">8500</prop>
-            </props>
-        </property>-->
-    </bean>
-    <!--
-    NOTE: to use mail session you'll need to configure following within catalina_home/conf/context.xml
-    <Resource name="mail/Session" auth="Container" type="javax.mail.Session" mail.smtp.host="my.mail.host"/>
-
-    Further, activation & mail jars needs to be placed within catalina_home/lib folder
-    -->
-    <!--
-    <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
-        <property name="session" ref="mailSession"/>
-    </bean>
-    <bean id="mailSession" class="org.springframework.jndi.JndiObjectFactoryBean">
-        <property name="jndiName" value="java:comp/env/mail/Session"/>
-    </bean>
-    -->
-
-    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate" />
-
-    <bean id="staticContentCache" class="org.apache.rave.service.impl.DefaultStaticContentFetcherService">
-        <constructor-arg ref="restTemplate"/>
-        <constructor-arg>
-            <list>
-                <!-- example of a Static Content source that doesn't have any string token placeholders in its content body
-                <bean class="org.apache.rave.model.StaticContent">
-                    <constructor-arg index="0" value="standardCompanyHeader"/>
-                    <constructor-arg index="1" value="${company.header.host}/content/standard_header.html"/>
-                    <constructor-arg index="2">
-                        <null/>
-                    </constructor-arg>
-                </bean>
-                -->
-                <!-- example of a Static Content source that has string token placeholders
-                <bean class="org.apache.rave.model.StaticContent">
-                    <constructor-arg index="0" value="environmentSpecificContent"/>
-                    <constructor-arg index="1" value="${company.header.host}/content/footer.html"/>
-                    <constructor-arg index="2">
-                        <map>
-                            <entry key="\{supportEmail\}" value="${raveproperty.supportemail}"/>
-                            <entry key="\{productVersion\}" value="${raveproperty.version}"/>
-                        </map>
-                    </constructor-arg>
-                </bean>
-                -->
-            </list>
-        </constructor-arg>
-    </bean>
-
-    <!-- example on how to setup a Spring Timer to refresh the Static Content cache at a fixed interval
-    <bean id="refreshStaticContentCacheScheduledTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
-        <property name="delay" value="5000"/>
-        <property name="period" value="300000"/>
-        <property name="timerTask">
-            <bean class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean"
-                  p:targetObject-ref="staticContentCache" p:targetMethod="refreshAll"/>
-        </property>
-    </bean>
-    <bean id="timerFactory" class="org.springframework.scheduling.timer.TimerFactoryBean">
-        <property name="daemon" value="true"/>
-        <property name="scheduledTimerTasks">
-            <list>
-                <ref local="refreshStaticContentCacheScheduledTask"/>
-            </list>
-        </property>
-    </bean>
-    -->
-</beans>
\ No newline at end of file
diff --git a/rave-components/rave-jpa/src/main/resources/org/apache/rave/marshaller-applicationContext.xml b/rave-components/rave-jpa/src/main/resources/org/apache/rave/marshaller-applicationContext.xml
new file mode 100644
index 0000000..5c43263
--- /dev/null
+++ b/rave-components/rave-jpa/src/main/resources/org/apache/rave/marshaller-applicationContext.xml
@@ -0,0 +1,42 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~  or more contributor license agreements.  See the NOTICE file
+  ~  distributed with this work for additional information
+  ~  regarding copyright ownership.  The ASF licenses this file
+  ~  to you under the Apache License, Version 2.0 (the
+  ~  "License"); you may not use this file except in compliance
+  ~  with the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing,
+  ~  software distributed under the License is distributed on an
+  ~  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~  KIND, either express or implied.  See the License for the
+  ~  specific language governing permissions and limitations
+  ~  under the License.
+  -->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:mvc="http://www.springframework.org/schema/mvc"
+       xmlns:oxm="http://www.springframework.org/schema/oxm"
+       xmlns:p="http://www.springframework.org/schema/p"
+       xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
+        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+        http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd">
+
+
+    <oxm:jaxb2-marshaller id="xmlMarshaller">
+        <oxm:class-to-be-bound name="org.apache.rave.portal.model.JpaUser"/>
+        <oxm:class-to-be-bound name="org.apache.rave.portal.model.JpaPage"/>
+        <oxm:class-to-be-bound name="org.apache.rave.portal.model.JpaRegion"/>
+        <oxm:class-to-be-bound name="org.apache.rave.portal.model.JpaRegionWidget"/>
+        <oxm:class-to-be-bound name="org.apache.rave.portal.model.JpaRegionWidgetPreference"/>
+        <oxm:class-to-be-bound name="org.apache.rave.portal.model.JpaWidget"/>
+        <oxm:class-to-be-bound name="org.apache.rave.portal.web.model.RegionWidgetPreferenceListWrapper"/>
+    </oxm:jaxb2-marshaller>
+
+</beans>
\ No newline at end of file
diff --git a/rave-components/rave-jpa/src/main/resources/org/apache/rave/persistence-applicationContext.xml b/rave-components/rave-jpa/src/main/resources/org/apache/rave/persistence-applicationContext.xml
new file mode 100644
index 0000000..95ec0c9
--- /dev/null
+++ b/rave-components/rave-jpa/src/main/resources/org/apache/rave/persistence-applicationContext.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+  -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:tx="http://www.springframework.org/schema/tx"
+       xmlns:p="http://www.springframework.org/schema/p"
+       xmlns:aop="http://www.springframework.org/schema/aop"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                           http://www.springframework.org/schema/beans/spring-beans.xsd
+        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
+        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
+
+
+    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
+        <property name="entityManagerFactory" ref="entityManagerFactory"/>
+    </bean>
+
+    <tx:annotation-driven transaction-manager="transactionManager"/>
+
+    <bean id="entityManagerFactory"
+          class="org.apache.rave.persistence.jpa.PopulatedLocalContainerEntityManagerFactory">
+        <property name="populator" ref="dataSourcePopulator"/>
+        <property name="loadTimeWeaver">
+            <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
+        </property>
+        <property name="persistenceUnitName" value="ravePersistenceUnit"/>
+        <property name="dataSource" ref="dataSource"/>
+        <property name="jpaVendorAdapter">
+            <bean class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter"
+                  p:databasePlatform="${jpa.jpaVendorAdapter.databasePlatform}"
+                  p:database="${jpa.jpaVendorAdapter.database}"
+                  p:showSql="${jpa.jpaVendorAdapter.showSql}"/>
+        </property>
+        <property name="jpaDialect">
+            <bean class="${jpa.jpaDialect}"/>
+        </property>
+        <property name="jpaPropertyMap">
+            <map>
+                <entry key="openjpa.Log" value="${jpa.openjpa.Log}"/>
+                <entry key="openjpa.RuntimeUnenhancedClasses" value="${jpa.openjpa.RuntimeUnenhancedClasses}"/>
+                <entry key="openjpa.jdbc.SynchronizeMappings" value="${jpa.openjpa.jdbc.SynchronizeMappings}"/>
+                <entry key="openjpa.jdbc.MappingDefaults" value="${jpa.openjpa.jdbc.MappingDefaults}"/>
+            </map>
+        </property>
+    </bean>
+
+    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
+        <property name="url" value="${jpa.dataSource.url}"/>
+        <property name="driverClassName" value="${jpa.dataSource.driver}"/>
+        <property name="username" value="${jpa.dataSource.username}"/>
+        <property name="password" value="${jpa.dataSource.password}"/>
+    </bean>
+</beans>
\ No newline at end of file
diff --git a/rave-components/rave-jpa/src/test/resources/portal.properties b/rave-components/rave-jpa/src/test/resources/portal.properties
index c563093..ec43a68 100644
--- a/rave-components/rave-jpa/src/test/resources/portal.properties
+++ b/rave-components/rave-jpa/src/test/resources/portal.properties
@@ -20,22 +20,23 @@
 # the default page name to create for new users
 portal.page.default_name=Main
 
+
 #Default Rave Portal database settings with in memory H2 database
-portal.dataSource.url=jdbc:h2:mem:portal;DB_CLOSE_DELAY=-1
-portal.dataSource.driver=org.h2.Driver
-portal.dataSource.username=sa
-portal.dataSource.password=local
+jpa.dataSource.url=jdbc:h2:mem:portal;DB_CLOSE_DELAY=-1
+jpa.dataSource.driver=org.h2.Driver
+jpa.dataSource.username=sa
+jpa.dataSource.password=local
 
-portal.jpaDialect=org.apache.rave.persistence.jpa.impl.H2OpenJpaDialect
-portal.jpaVendorAdapter.databasePlatform=org.apache.openjpa.jdbc.sql.H2Dictionary
-portal.jpaVendorAdapter.database=H2
+jpa.jpaDialect=org.apache.rave.persistence.jpa.impl.H2OpenJpaDialect
+jpa.jpaVendorAdapter.databasePlatform=org.apache.openjpa.jdbc.sql.H2Dictionary
+jpa.jpaVendorAdapter.database=H2
 
-# General Rave portal database settings
-portal.jpaVendorAdapter.showSql=true
-portal.openjpa.Log=DefaultLevel=WARN, Runtime=INFO, Tool=INFO, SQL=WARN
-portal.openjpa.RuntimeUnenhancedClasses=supported
-portal.openjpa.jdbc.SynchronizeMappings=buildSchema(ForeignKeys=true)
-portal.openjpa.jdbc.MappingDefaults=ForeignKeyDeleteAction=restrict, JoinForeignKeyDeleteAction=restrict
+# General Rave jpa database settings
+jpa.jpaVendorAdapter.showSql=true
+jpa.openjpa.Log=DefaultLevel=WARN, Runtime=INFO, Tool=INFO, SQL=WARN
+jpa.openjpa.RuntimeUnenhancedClasses=unsupported
+jpa.openjpa.jdbc.SynchronizeMappings=buildSchema(ForeignKeys=true)
+jpa.openjpa.jdbc.MappingDefaults=ForeignKeyDeleteAction=restrict, JoinForeignKeyDeleteAction=restrict
 
 provider.wookie.wookieServerUrl=http://localhost:8080/wookie
 provider.wookie.wookieApiKey=TEST
diff --git a/rave-components/rave-jpa/src/test/resources/test-applicationContext.xml b/rave-components/rave-jpa/src/test/resources/test-applicationContext.xml
index ce8112e..b4d97bc 100644
--- a/rave-components/rave-jpa/src/test/resources/test-applicationContext.xml
+++ b/rave-components/rave-jpa/src/test/resources/test-applicationContext.xml
@@ -19,9 +19,129 @@
 
 <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-       xsi:schemaLocation="http://www.springframework.org/schema/beans
-                           http://www.springframework.org/schema/beans/spring-beans.xsd">
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:aop="http://www.springframework.org/schema/aop"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
+                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
 
-    <import resource="classpath:org/apache/rave/jpa-applicationContext.xml"/>
+
+    <!-- make the the portal.properties props available to autowire injectors, location of the properties can
+be overridden by setting a system property "portal.override.properties" -->
+    <bean id="portalPropertyPlaceholder" class="org.apache.rave.util.OverridablePropertyPlaceholderConfigurer">
+        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
+        <property name="systemPropertyName" value="portal.override.properties"/>
+        <property name="location" value="classpath:portal.properties"/>
+    </bean>
+
+    <!-- bean post-processor for JPA annotations -->
+    <context:annotation-config/>
+
+    <!-- enable the use of the @AspectJ style of Spring AOP -->
+    <aop:aspectj-autoproxy/>
+
+    <!-- rave-common component base-package scan (maybe move to a separate common-applicationContext.xml?) -->
+    <context:component-scan base-package="org.apache.rave.service"/>
+    <context:component-scan base-package="org.apache.rave.synchronization"/>
+
+    <!-- rave-core component base-package scan -->
+    <context:component-scan base-package="org.apache.rave.portal.model"/>
+    <context:component-scan base-package="org.apache.rave.portal.repository"/>
+
+    <!-- Password encoding -->
+    <bean class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" id="passwordEncoder">
+        <!--<constructor-arg index="0" value="10"/>-->
+    </bean>
+
+    <!-- email settings -->
+    <bean id="emailServiceMailMessage" class="org.springframework.mail.SimpleMailMessage">
+        <property name="from" value="${portal.mail.sender}"/>
+        <property name="replyTo" value="${portal.mail.replyto}"/>
+    </bean>
+
+    <bean id="freemarkerMailConfiguration" class="org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean">
+        <property name="templateLoaderPath" value="/WEB-INF/mailtemplates"/>
+    </bean>
+    <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
+        <property name="host" value="${portal.mail.host}"/>
+        <property name="password" value="${portal.mail.password}"/>
+        <property name="username" value="${portal.mail.username}"/>
+        <property name="port" value="${portal.mail.port}"/>
+        <property name="protocol" value="${portal.mail.protocol}"/>
+        <!-- NOTE: if using Gmail, you'll need following properties-->
+        <!--<property name="javaMailProperties">
+            <props>
+                <prop key="mail.smtp.auth">true</prop>
+                <prop key="mail.smtp.starttls.enable">true</prop>
+                <prop key="mail.smtp.timeout">8500</prop>
+            </props>
+        </property>-->
+    </bean>
+    <!--
+    NOTE: to use mail session you'll need to configure following within catalina_home/conf/context.xml
+    <Resource name="mail/Session" auth="Container" type="javax.mail.Session" mail.smtp.host="my.mail.host"/>
+
+    Further, activation & mail jars needs to be placed within catalina_home/lib folder
+    -->
+    <!--
+    <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
+        <property name="session" ref="mailSession"/>
+    </bean>
+    <bean id="mailSession" class="org.springframework.jndi.JndiObjectFactoryBean">
+        <property name="jndiName" value="java:comp/env/mail/Session"/>
+    </bean>
+    -->
+
+    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate" />
+
+    <bean id="staticContentCache" class="org.apache.rave.service.impl.DefaultStaticContentFetcherService">
+        <constructor-arg ref="restTemplate"/>
+        <constructor-arg>
+            <list>
+                <!-- example of a Static Content source that doesn't have any string token placeholders in its content body
+                <bean class="org.apache.rave.model.StaticContent">
+                    <constructor-arg index="0" value="standardCompanyHeader"/>
+                    <constructor-arg index="1" value="${company.header.host}/content/standard_header.html"/>
+                    <constructor-arg index="2">
+                        <null/>
+                    </constructor-arg>
+                </bean>
+                -->
+                <!-- example of a Static Content source that has string token placeholders
+                <bean class="org.apache.rave.model.StaticContent">
+                    <constructor-arg index="0" value="environmentSpecificContent"/>
+                    <constructor-arg index="1" value="${company.header.host}/content/footer.html"/>
+                    <constructor-arg index="2">
+                        <map>
+                            <entry key="\{supportEmail\}" value="${raveproperty.supportemail}"/>
+                            <entry key="\{productVersion\}" value="${raveproperty.version}"/>
+                        </map>
+                    </constructor-arg>
+                </bean>
+                -->
+            </list>
+        </constructor-arg>
+    </bean>
+
+    <!-- example on how to setup a Spring Timer to refresh the Static Content cache at a fixed interval
+    <bean id="refreshStaticContentCacheScheduledTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
+        <property name="delay" value="5000"/>
+        <property name="period" value="300000"/>
+        <property name="timerTask">
+            <bean class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean"
+                  p:targetObject-ref="staticContentCache" p:targetMethod="refreshAll"/>
+        </property>
+    </bean>
+    <bean id="timerFactory" class="org.springframework.scheduling.timer.TimerFactoryBean">
+        <property name="daemon" value="true"/>
+        <property name="scheduledTimerTasks">
+            <list>
+                <ref local="refreshStaticContentCacheScheduledTask"/>
+            </list>
+        </property>
+    </bean>
+    -->
+
+    <import resource="classpath:org/apache/rave/persistence-applicationContext.xml"/>
 
 </beans>
\ No newline at end of file
diff --git a/rave-components/rave-mongodb/pom.xml b/rave-components/rave-mongodb/pom.xml
new file mode 100644
index 0000000..b806f10
--- /dev/null
+++ b/rave-components/rave-mongodb/pom.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~  or more contributor license agreements.  See the NOTICE file
+  ~  distributed with this work for additional information
+  ~  regarding copyright ownership.  The ASF licenses this file
+  ~  to you under the Apache License, Version 2.0 (the
+  ~  "License"); you may not use this file except in compliance
+  ~  with the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing,
+  ~  software distributed under the License is distributed on an
+  ~  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~  KIND, either express or implied.  See the License for the
+  ~  specific language governing permissions and limitations
+  ~  under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>rave-components</artifactId>
+        <groupId>org.apache.rave</groupId>
+        <version>0.19-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>rave-mongodb</artifactId>
+    <name>Apache Rave :: rave-mongodb</name>
+    <description>Apache Rave MongoDB Persistence Provider</description>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.rave</groupId>
+            <artifactId>rave-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mongodb</groupId>
+            <artifactId>mongo-java-driver</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.data</groupId>
+            <artifactId>spring-data-mongodb</artifactId>
+        </dependency>
+
+        <!-- Test -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-test</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.mail</groupId>
+            <artifactId>mail</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context-support</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.freemarker</groupId>
+            <artifactId>freemarker</artifactId>
+        </dependency>
+
+        <!-- Jackson JSON Mapper -->
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-mapper-asl</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-mrbean</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>de.flapdoodle.embed</groupId>
+            <artifactId>de.flapdoodle.embed.mongo</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- Logging -->
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>jcl-over-slf4j</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-log4j12</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.ibm.icu</groupId>
+            <artifactId>icu4j</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+    </dependencies>
+
+</project>
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbAuthority.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbAuthority.java
new file mode 100644
index 0000000..9bb94e4
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbAuthority.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model;
+
+import org.apache.rave.portal.model.impl.AuthorityImpl;
+
+
+public class MongoDbAuthority extends AuthorityImpl {
+    private String id;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbCategory.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbCategory.java
new file mode 100644
index 0000000..119d675
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbCategory.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model;
+
+import org.apache.rave.portal.model.impl.CategoryImpl;
+import org.apache.rave.portal.repository.MongoWidgetOperations;
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonIgnore;
+import org.codehaus.jackson.annotate.JsonMethod;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlTransient;
+import java.util.List;
+
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+@XmlAccessorType(value = XmlAccessType.FIELD)
+@JsonAutoDetect(value = JsonMethod.FIELD, fieldVisibility = JsonAutoDetect.Visibility.ANY)
+public class MongoDbCategory extends CategoryImpl {
+
+    @XmlTransient @JsonIgnore
+    private MongoWidgetOperations widgetTemplate;
+
+    public MongoWidgetOperations getWidgetRepository() {
+        return widgetTemplate;
+    }
+
+    public void setWidgetRepository(MongoWidgetOperations widgetRepository) {
+        this.widgetTemplate = widgetRepository;
+    }
+
+    @Override
+    public List<Widget> getWidgets() {
+        List<Widget> widgets =  super.getWidgets();
+        if(widgets == null) {
+            widgets = widgetTemplate.find(query(where("categoryIds").is(this.getId())));
+            super.setWidgets(widgets);
+        }
+        return widgets;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbPage.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbPage.java
new file mode 100644
index 0000000..2dafd5a
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbPage.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model;
+
+import org.apache.rave.portal.model.impl.PageImpl;
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonMethod;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+
+@XmlAccessorType(value = XmlAccessType.FIELD)
+@JsonAutoDetect(value = JsonMethod.FIELD, fieldVisibility = JsonAutoDetect.Visibility.ANY)
+public class MongoDbPage extends PageImpl {
+
+    private String pageLayoutCode;
+
+    public MongoDbPage() {}
+
+    public String getPageLayoutCode() {
+        return pageLayoutCode;
+    }
+
+    public void setPageLayoutCode(String pageLayoutCode) {
+        this.pageLayoutCode = pageLayoutCode;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof Page)) return false;
+        Page that = (Page) o;
+        return !(this.getId() != null ? !this.getId().equals(that.getId()) : that.getId() != null);
+
+    }
+
+    @Override
+    public int hashCode() {
+        return this.getId() != null ? this.getId().hashCode() : 0;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbPageLayout.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbPageLayout.java
new file mode 100644
index 0000000..0890cce
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbPageLayout.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model;
+
+
+import org.apache.rave.portal.model.impl.PageLayoutImpl;
+
+public class MongoDbPageLayout extends PageLayoutImpl{
+    private String id;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof MongoDbPageLayout)) return false;
+        if (!super.equals(o)) return false;
+
+        MongoDbPageLayout that = (MongoDbPageLayout) o;
+
+        if (id != null ? !id.equals(that.id) : that.id != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = super.hashCode();
+        result = 31 * result + (id != null ? id.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbPageTemplate.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbPageTemplate.java
new file mode 100644
index 0000000..d56fc7a
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbPageTemplate.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model;
+
+
+import org.apache.rave.portal.model.impl.PageTemplateImpl;
+import org.apache.rave.portal.repository.PageLayoutRepository;
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonIgnore;
+import org.codehaus.jackson.annotate.JsonMethod;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlTransient;
+
+@XmlAccessorType(value = XmlAccessType.FIELD)
+@JsonAutoDetect(value = JsonMethod.FIELD, fieldVisibility = JsonAutoDetect.Visibility.ANY)
+public class MongoDbPageTemplate extends PageTemplateImpl {
+
+    @XmlTransient @JsonIgnore
+    private PageLayoutRepository pageLayoutRepository;
+    private String pageLayoutCode;
+
+    public void setPageLayoutRepository(PageLayoutRepository pageLayoutRepository) {
+        this.pageLayoutRepository = pageLayoutRepository;
+    }
+
+    public String getPageLayoutCode() {
+        return pageLayoutCode;
+    }
+
+    public void setPageLayoutCode(String pageLayoutCode) {
+        this.pageLayoutCode = pageLayoutCode;
+
+    }
+
+    public PageLayoutRepository getPageLayoutRepository() {
+        return pageLayoutRepository;
+    }
+
+    @Override
+    public PageLayout getPageLayout() {
+        PageLayout layout = super.getPageLayout();
+        if(layout == null) {
+            layout = pageLayoutRepository.getByPageLayoutCode(pageLayoutCode);
+            super.setPageLayout(layout);
+        }
+        return layout;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbPersonAssociation.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbPersonAssociation.java
new file mode 100644
index 0000000..147b2c9
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbPersonAssociation.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model;
+
+/**
+ */
+public class MongoDbPersonAssociation {
+
+    public static enum Direction {
+        INCOMING, OUTGOING
+    }
+
+    private FriendRequestStatus requestStatus;
+    private String personId;
+    private Direction requestDirection;
+
+    public MongoDbPersonAssociation() { }
+
+    public MongoDbPersonAssociation(String personId, FriendRequestStatus status, Direction direction) {
+        this.requestDirection = direction;
+        this.requestStatus = status;
+        this.personId = personId;
+    }
+
+    public FriendRequestStatus getRequestStatus() {
+        return requestStatus;
+    }
+
+    public void setRequestStatus(FriendRequestStatus requestStatus) {
+        this.requestStatus = requestStatus;
+    }
+
+    public String getPersonId() {
+        return personId;
+    }
+
+    public void setPersonId(String personId) {
+        this.personId = personId;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbPortalPreference.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbPortalPreference.java
new file mode 100644
index 0000000..75c32ac
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbPortalPreference.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model;
+
+import org.apache.rave.portal.model.impl.PortalPreferenceImpl;
+
+public class MongoDbPortalPreference extends PortalPreferenceImpl {
+    
+    private String id;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbUser.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbUser.java
new file mode 100644
index 0000000..f3a17f0
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbUser.java
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model;
+
+import com.google.common.collect.Lists;
+import org.apache.rave.portal.model.impl.UserImpl;
+import org.apache.rave.portal.repository.PageLayoutRepository;
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonIgnore;
+import org.codehaus.jackson.annotate.JsonMethod;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlTransient;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ */
+@XmlAccessorType(value = XmlAccessType.FIELD)
+@JsonAutoDetect(value = JsonMethod.FIELD, fieldVisibility = JsonAutoDetect.Visibility.ANY)
+public class MongoDbUser extends UserImpl {
+
+    private List<String> authorityCodes;
+    private List<MongoDbPersonAssociation> friends;
+
+    @XmlTransient
+    @JsonIgnore
+    private PageLayoutRepository pageLayoutRepository;
+
+    public MongoDbUser(String id) {
+        super(id);
+    }
+
+    public MongoDbUser() {
+    }
+
+    public List<String> getAuthorityCodes() {
+        return authorityCodes;
+    }
+
+    public PageLayoutRepository getPageLayoutRepository() {
+        return pageLayoutRepository;
+    }
+
+    public void setAuthorityCodes(List<String> authorityCodes) {
+        this.authorityCodes = authorityCodes;
+    }
+
+    public List<MongoDbPersonAssociation> getFriends() {
+        return friends;
+    }
+
+    public void setFriends(List<MongoDbPersonAssociation> friends) {
+        this.friends = friends;
+    }
+
+    @Override
+    public void setAuthorities(Collection<Authority> authorities) {
+        if (authorities != null) {
+            for (GrantedAuthority authority : authorities) {
+                addAuthorityCode(authority);
+            }
+        } else {
+            authorityCodes.clear();
+        }
+    }
+
+    @Override
+    public Collection<GrantedAuthority> getAuthorities() {
+        ensureAuthorityCodes();
+        Collection<GrantedAuthority> grantedAuthorities = Lists.newArrayList();
+        for (String code : authorityCodes) {
+            grantedAuthorities.add(new SimpleGrantedAuthority(code));
+        }
+        return grantedAuthorities;
+    }
+
+    @Override
+    public void addAuthority(Authority authority) {
+        addAuthorityCode(authority);
+    }
+
+    @Override
+    public void removeAuthority(Authority authority) {
+        ensureAuthorityCodes();
+        if (authorityCodes.contains(authority.getAuthority())) {
+            authorityCodes.remove(authority.getAuthority());
+        }
+    }
+
+    @Override
+    public PageLayout getDefaultPageLayout() {
+        PageLayout layout = super.getDefaultPageLayout();
+        if (layout == null) {
+            layout = pageLayoutRepository.getByPageLayoutCode(super.getDefaultPageLayoutCode());
+            super.setDefaultPageLayout(layout);
+        }
+        return layout;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof MongoDbUser)) return false;
+
+        MongoDbUser that = (MongoDbUser) o;
+
+        if (this.getId() != null ? !this.getId().equals(that.getId()) : that.getId() != null)
+            return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 7;
+        hash = 67 * hash + (this.getId() != null ? this.getId().hashCode() : 0);
+        return hash;
+    }
+
+    public void setPageLayoutRepository(PageLayoutRepository pageLayoutRepository) {
+        this.pageLayoutRepository = pageLayoutRepository;
+    }
+
+    private void ensureAuthorityCodes() {
+        if (authorityCodes == null) {
+            authorityCodes = Lists.newArrayList();
+        }
+    }
+
+    private void addAuthorityCode(GrantedAuthority authority) {
+        ensureAuthorityCodes();
+        if (!authorityCodes.contains(authority.getAuthority())) {
+            authorityCodes.add(authority.getAuthority());
+        }
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbWidget.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbWidget.java
new file mode 100644
index 0000000..dc561b0
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/MongoDbWidget.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model;
+
+import com.google.common.collect.Lists;
+import org.apache.rave.portal.model.impl.WidgetImpl;
+import org.apache.rave.portal.repository.CategoryRepository;
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonIgnore;
+import org.codehaus.jackson.annotate.JsonMethod;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlTransient;
+import java.util.List;
+
+/**
+ */
+
+@XmlAccessorType(value = XmlAccessType.FIELD)
+@JsonAutoDetect(value = JsonMethod.FIELD, fieldVisibility = JsonAutoDetect.Visibility.ANY)
+public class MongoDbWidget extends WidgetImpl {
+
+    @XmlTransient @JsonIgnore
+    private CategoryRepository categoryRepository;
+
+    private List<String> categoryIds;
+
+    public MongoDbWidget() { }
+
+    public MongoDbWidget(String id) {
+        super(id);
+    }
+
+    public List<String> getCategoryIds() {
+        return categoryIds;
+    }
+
+    public void setCategoryIds(List<String> categoryIds) {
+        this.categoryIds = categoryIds;
+    }
+
+    public CategoryRepository getCategoryRepository() {
+        return categoryRepository;
+    }
+
+    public void setCategoryRepository(CategoryRepository categoryRepository) {
+        this.categoryRepository = categoryRepository;
+    }
+
+    @Override
+    public List<Category> getCategories() {
+        ensureCategoryIds();
+        List<Category> categories = super.getCategories();
+        if(categories == null || categories.isEmpty()) {
+            categories = createCategoriesFromIds();
+        }
+        return categories;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof Widget)) return false;
+
+        Widget that = (Widget) o;
+
+        if (this.getId() != null ? !this.getId().equals(that.getId()) : that.getId() != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = super.hashCode();
+        result = 31 * result + (getId() != null ? getId().hashCode() : 0);
+        return result;
+    }
+
+    private void ensureCategoryIds() {
+        if(categoryIds == null) {
+            categoryIds = Lists.newArrayList();
+        }
+    }
+
+    private void addCategory(List<Category> categories, String id) {
+        Category category = categoryRepository.get(id);
+        if(category != null) {
+            categories.add(category);
+        }
+    }
+
+    private List<Category> createCategoriesFromIds() {
+        List<Category> categories;
+        categories = Lists.newArrayList();
+        for(String id : categoryIds) {
+            addCategory(categories, id);
+        }
+        super.setCategories(categories);
+        return categories;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/WidgetRatingsMapReduceResult.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/WidgetRatingsMapReduceResult.java
new file mode 100644
index 0000000..e74cc30
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/WidgetRatingsMapReduceResult.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model;
+
+import java.util.Map;
+
+/**
+*/
+public class WidgetRatingsMapReduceResult {
+    private String id;
+    private WidgetStatisticsMapReduceResult value;
+
+    public WidgetRatingsMapReduceResult() {  }
+
+    public WidgetRatingsMapReduceResult(String id, WidgetStatisticsMapReduceResult value) {
+        this.id = id;
+        this.value = value;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public WidgetStatisticsMapReduceResult getValue() {
+        return value;
+    }
+
+    public void setValue(WidgetStatisticsMapReduceResult value) {
+        this.value = value;
+    }
+
+    public static class WidgetStatisticsMapReduceResult {
+        private Map<String, Long> userRatings;
+        private Long like;
+        private Long dislike;
+
+        public WidgetStatisticsMapReduceResult() { }
+
+        public WidgetStatisticsMapReduceResult(Map<String, Long> userRatings, Long like, Long dislike) {
+            this.userRatings = userRatings;
+            this.like = like;
+            this.dislike = dislike;
+        }
+
+        public Map<String, Long> getUserRatings() {
+            return userRatings;
+        }
+
+        public void setUserRatings(Map<String, Long> userRatings) {
+            this.userRatings = userRatings;
+        }
+
+        public Long getLike() {
+            return like;
+        }
+
+        public void setLike(Long like) {
+            this.like = like;
+        }
+
+        public Long getDislike() {
+            return dislike;
+        }
+
+        public void setDislike(Long dislike) {
+            this.dislike = dislike;
+        }
+    }
+
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/WidgetUsersMapReduceResult.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/WidgetUsersMapReduceResult.java
new file mode 100644
index 0000000..3e1a81a
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/WidgetUsersMapReduceResult.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model;
+
+import java.util.Map;
+
+public class WidgetUsersMapReduceResult {
+    private String id;
+    private Map<String, Long> value;
+
+    public WidgetUsersMapReduceResult() { }
+
+    public WidgetUsersMapReduceResult(String id, Map<String, Long> value) {
+        this.id = id;
+        this.value = value;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public Map<String, Long> getValue() {
+        return value;
+    }
+
+    public void setValue(Map<String, Long> value) {
+        this.value = value;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/HydratingConverterFactory.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/HydratingConverterFactory.java
new file mode 100644
index 0000000..cfb812e
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/HydratingConverterFactory.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model.conversion;
+
+import org.apache.rave.model.ModelConverter;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: mfranklin
+ * Date: 10/16/12
+ * Time: 8:24 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public interface HydratingConverterFactory {
+    @SuppressWarnings("unchecked")
+    <S, T> T convert(S source, Class<S> clazz);
+
+    @SuppressWarnings("unchecked")
+    <S> void hydrate(S source, Class<S> clazz);
+
+    @SuppressWarnings("unchecked")
+    <S,T> ModelConverter<S, T> getConverter(Class<S> clazz);
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/HydratingModelConverter.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/HydratingModelConverter.java
new file mode 100644
index 0000000..cc2ed25
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/HydratingModelConverter.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model.conversion;
+
+
+import org.apache.rave.model.ModelConverter;
+
+public interface HydratingModelConverter <S,T>  extends ModelConverter<S, T>{
+    public void hydrate(T dehydrated);
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbAuthorityConverter.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbAuthorityConverter.java
new file mode 100644
index 0000000..ca3fa6a
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbAuthorityConverter.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model.conversion.impl;
+
+import org.apache.rave.portal.model.Authority;
+import org.apache.rave.portal.model.MongoDbAuthority;
+import org.apache.rave.portal.model.conversion.HydratingModelConverter;
+import org.springframework.stereotype.Component;
+
+@Component
+public class MongoDbAuthorityConverter implements HydratingModelConverter<Authority, MongoDbAuthority> {
+    @Override
+    public void hydrate(MongoDbAuthority dehydrated) {
+        //NOOP
+    }
+
+    @Override
+    public Class<Authority> getSourceType() {
+        return Authority.class;
+    }
+
+    @Override
+    public MongoDbAuthority convert(Authority source) {
+        MongoDbAuthority converted = source instanceof MongoDbAuthority ? (MongoDbAuthority) source : new MongoDbAuthority();
+        converted.setAuthority(source.getAuthority());
+        converted.setDefaultForNewUser(source.isDefaultForNewUser());
+        return converted;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbCategoryConverter.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbCategoryConverter.java
new file mode 100644
index 0000000..572bb26
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbCategoryConverter.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model.conversion.impl;
+
+import org.apache.rave.portal.model.Category;
+import org.apache.rave.portal.model.MongoDbCategory;
+import org.apache.rave.portal.model.conversion.HydratingModelConverter;
+import org.apache.rave.portal.repository.MongoWidgetOperations;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import static org.apache.rave.portal.model.util.MongoDbModelUtil.generateId;
+
+@Component
+public class MongoDbCategoryConverter implements HydratingModelConverter<Category, MongoDbCategory> {
+
+    @Autowired
+    private MongoWidgetOperations widgetOperations;
+
+
+    @Override
+    public void hydrate(MongoDbCategory dehydrated) {
+        if(dehydrated == null) {
+            return;
+        }
+        dehydrated.setWidgetRepository(widgetOperations);
+    }
+
+    @Override
+    public Class<Category> getSourceType() {
+        return Category.class;
+    }
+
+    @Override
+    public MongoDbCategory convert(Category source) {
+        MongoDbCategory category = new MongoDbCategory();
+        category.setId(source.getId() == null ? generateId() : source.getId());
+        category.setCreatedDate(source.getCreatedDate());
+        category.setCreatedUserId(source.getCreatedUserId());
+        category.setLastModifiedUserId(source.getLastModifiedUserId());
+        category.setWidgetRepository(null);
+        category.setText(source.getText());
+        category.setWidgets(null);
+        return category;
+    }
+
+    public void setMongoWidgetOperations(MongoWidgetOperations mongoWidgetOperations) {
+        this.widgetOperations = mongoWidgetOperations;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbConverter.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbConverter.java
new file mode 100644
index 0000000..afc2b04
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbConverter.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model.conversion.impl;
+
+import org.apache.rave.model.ModelConverter;
+import org.apache.rave.portal.model.conversion.HydratingConverterFactory;
+import org.apache.rave.portal.model.conversion.HydratingModelConverter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Converts reference properties to hydrated objects
+ * <p/>
+ * TODO: REMOVE REPOSITORY INJECTION WHEN MODEL-SPLIT BRANCH IS MERGED
+ */
+@Component
+public class MongoDbConverter implements HydratingConverterFactory {
+
+    private Map<Class<?>, HydratingModelConverter> converterMap;
+
+    @Autowired
+    public void setConverters(List<HydratingModelConverter> converters) {
+        converterMap = new HashMap<Class<?>, HydratingModelConverter>();
+        for(HydratingModelConverter converter : converters) {
+            converterMap.put(converter.getSourceType(), converter);
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <S, T> T convert(S source, Class<S> clazz) {
+        if(converterMap.containsKey(clazz)) {
+            return (T)converterMap.get(clazz).convert(source);
+        } else {
+            throw new IllegalArgumentException("No ModelConverter found for type " + clazz);
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <S> void hydrate(S source, Class<S> clazz) {
+        if(converterMap.containsKey(clazz)) {
+            converterMap.get(clazz).hydrate(source);
+        } else {
+            throw new IllegalArgumentException("No ModelConverter found for type " + clazz);
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <S,T> ModelConverter<S, T> getConverter(Class<S> clazz) {
+        return converterMap.get(clazz);
+    }
+
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbPageConverter.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbPageConverter.java
new file mode 100644
index 0000000..a1c0d5d
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbPageConverter.java
@@ -0,0 +1,189 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model.conversion.impl;
+
+import com.google.common.collect.Lists;
+import org.apache.rave.portal.model.*;
+import org.apache.rave.portal.model.conversion.HydratingModelConverter;
+import org.apache.rave.portal.model.impl.PageUserImpl;
+import org.apache.rave.portal.model.impl.RegionImpl;
+import org.apache.rave.portal.model.impl.RegionWidgetImpl;
+import org.apache.rave.portal.model.impl.RegionWidgetPreferenceImpl;
+import org.apache.rave.portal.repository.PageLayoutRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+import static org.apache.rave.portal.model.util.MongoDbModelUtil.generateLongId;
+import static org.apache.rave.portal.model.util.MongoDbModelUtil.generateId;
+
+@Component
+public class MongoDbPageConverter implements HydratingModelConverter<Page, MongoDbPage> {
+
+    @Autowired
+    private PageLayoutRepository pageLayoutRepository;
+
+    @Override
+    public Class<Page> getSourceType() {
+        return Page.class;
+    }
+
+    @Override
+    public MongoDbPage convert(Page sourcePage) {
+        MongoDbPage page = new MongoDbPage();
+        page.setId(sourcePage.getId() == null ? generateId() : sourcePage.getId());
+        page.setOwnerId(sourcePage.getOwnerId());
+        page.setPageLayoutCode(sourcePage.getPageLayout().getCode());
+        page.setName(sourcePage.getName());
+        page.setRegions(sourcePage.getRegions());
+        page.setPageType(sourcePage.getPageType());
+
+        page.setPageLayout(null);
+        page.setParentPage(null);
+
+        List<PageUser> convertedMembers = Lists.newArrayList();
+        for (PageUser user : sourcePage.getMembers()) {
+            convertedMembers.add(convert(user));
+        }
+        page.setMembers(convertedMembers);
+
+        List<Region> convertedRegions = Lists.newArrayList();
+        for (Region region : page.getRegions()) {
+            convertedRegions.add(convert(region));
+        }
+        page.setRegions(convertedRegions);
+        if (sourcePage.getSubPages() != null) {
+            List<Page> convertedPages = Lists.newArrayList();
+            for (Page subPage : sourcePage.getSubPages()) {
+                if(subPage.getId() == null) {
+                    subPage.setId(generateId());
+                }
+                convertedPages.add(convert(subPage));
+            }
+            page.setSubPages(convertedPages);
+        }
+        return page;
+    }
+
+    public PageUserImpl convert(PageUser sourceUser) {
+        PageUserImpl user = sourceUser instanceof PageUserImpl ? (PageUserImpl) sourceUser : new PageUserImpl();
+        user.setId(sourceUser.getId() == null ? generateId() : sourceUser.getId());
+        user.setUserId(sourceUser.getUserId());
+        user.setEditor(sourceUser.isEditor());
+        user.setPageStatus(sourceUser.getPageStatus());
+        user.setRenderSequence(sourceUser.getRenderSequence());
+        user.setPage(null);
+        return user;
+    }
+
+    @Override
+    public void hydrate(MongoDbPage page) {
+        if (page == null) {
+            return;
+        }
+        page.setPageLayout(pageLayoutRepository.getByPageLayoutCode(page.getPageLayoutCode()));
+
+        for (PageUser user : page.getMembers()) {
+            user.setPage(page);
+        }
+        for (Region region : page.getRegions()) {
+            region.setPage(page);
+            hydrate(region);
+        }
+        if (page.getSubPages() != null) {
+            for (Page subPage : page.getSubPages()) {
+                subPage.setParentPage(page);
+                if (subPage instanceof MongoDbPage) {
+                    hydrate((MongoDbPage) subPage);
+                }
+            }
+        }
+    }
+
+    public void hydrate(RegionWidgetImpl widget, Region region) {
+        widget.setRegion(region);
+    }
+
+    public RegionWidgetImpl convert(RegionWidget sourceRegionWidget) {
+        RegionWidgetImpl regionWidget = sourceRegionWidget instanceof RegionWidgetImpl ? (RegionWidgetImpl) sourceRegionWidget : new RegionWidgetImpl();
+        //RegionWidgetIds MUST be a Long due to the mapping of ModuleID in Shindig.
+        regionWidget.setId(sourceRegionWidget.getId() == null ? generateLongId().toString() : sourceRegionWidget.getId());
+        regionWidget.setWidgetId(sourceRegionWidget.getWidgetId());
+        regionWidget.setRegion(null);
+        regionWidget.setPreferences(sourceRegionWidget.getPreferences());
+        updatePreferences(regionWidget);
+        updateProperties(sourceRegionWidget, regionWidget);
+        return regionWidget;
+    }
+
+    private void updatePreferences(RegionWidgetImpl regionWidget) {
+        List<RegionWidgetPreference> converted = Lists.newArrayList();
+        if (regionWidget.getPreferences() != null) {
+            for (RegionWidgetPreference preference : regionWidget.getPreferences()) {
+                converted.add(convert(preference));
+            }
+        }
+        regionWidget.setPreferences(converted);
+    }
+
+    private RegionWidgetPreference convert(RegionWidgetPreference preference) {
+        RegionWidgetPreference converted = new RegionWidgetPreferenceImpl();
+        converted.setName(preference.getName());
+        converted.setValue(preference.getValue());
+        return converted;
+    }
+
+    private void hydrate(Region region) {
+        if (region.getRegionWidgets() == null) {
+            region.setRegionWidgets(Lists.<RegionWidget>newArrayList());
+        } else {
+            for (RegionWidget regionWidget : region.getRegionWidgets()) {
+                hydrate((RegionWidgetImpl) regionWidget, region);
+            }
+        }
+    }
+
+    private Region convert(Region region) {
+        String regionId = region.getId() == null ? generateId() : region.getId();
+        Region converted = new RegionImpl(regionId, null, region.getRenderOrder());
+        converted.setLocked(region.isLocked());
+        if (region.getRegionWidgets() != null) {
+            List<RegionWidget> convertedWidgets = Lists.newArrayList();
+            for (RegionWidget widget : region.getRegionWidgets()) {
+                convertedWidgets.add(convert(widget));
+            }
+            converted.setRegionWidgets(convertedWidgets);
+        }
+        return converted;
+    }
+
+    private void updateProperties(RegionWidget source, RegionWidget converted) {
+        converted.setLocked(source.isLocked());
+        converted.setCollapsed(source.isCollapsed());
+        converted.setHideChrome(source.isHideChrome());
+        converted.setRenderPosition(source.getRenderPosition());
+        converted.setRenderOrder(source.getRenderOrder());
+    }
+
+    public void setPageLayoutRepository(PageLayoutRepository pageLayoutRepository) {
+        this.pageLayoutRepository = pageLayoutRepository;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbPageTemplateConverter.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbPageTemplateConverter.java
new file mode 100644
index 0000000..d26b36c
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbPageTemplateConverter.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model.conversion.impl;
+
+import com.google.common.collect.Lists;
+import org.apache.rave.portal.model.MongoDbPageTemplate;
+import org.apache.rave.portal.model.PageTemplate;
+import org.apache.rave.portal.model.PageTemplateRegion;
+import org.apache.rave.portal.model.PageTemplateWidget;
+import org.apache.rave.portal.model.conversion.HydratingModelConverter;
+import org.apache.rave.portal.model.impl.PageTemplateRegionImpl;
+import org.apache.rave.portal.model.impl.PageTemplateWidgetImpl;
+import org.apache.rave.portal.repository.PageLayoutRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+import static org.apache.rave.portal.model.util.MongoDbModelUtil.generateId;
+
+@Component
+public class MongoDbPageTemplateConverter implements HydratingModelConverter<PageTemplate, MongoDbPageTemplate> {
+
+    @Autowired
+    private PageLayoutRepository pageLayoutRepository;
+
+    @Override
+    public void hydrate(MongoDbPageTemplate dehydrated) {
+        if (dehydrated == null) {
+            return;
+        }
+        dehydrated.setPageLayoutRepository(pageLayoutRepository);
+        for (PageTemplateRegion region : dehydrated.getPageTemplateRegions()) {
+            region.setPageTemplate(dehydrated);
+            for (PageTemplateWidget widget : region.getPageTemplateWidgets()) {
+                widget.setPageTemplateRegion(region);
+            }
+        }
+        if (dehydrated.getSubPageTemplates() != null) {
+            for (PageTemplate sub : dehydrated.getSubPageTemplates()) {
+                sub.setParentPageTemplate(dehydrated);
+                hydrate((MongoDbPageTemplate) sub);
+            }
+        }
+    }
+
+    @Override
+    public Class<PageTemplate> getSourceType() {
+        return PageTemplate.class;
+    }
+
+    @Override
+    public MongoDbPageTemplate convert(PageTemplate source) {
+        MongoDbPageTemplate converted = source instanceof MongoDbPageTemplate ? ((MongoDbPageTemplate) source) : new MongoDbPageTemplate();
+        updateProperties(source, converted);
+
+        if (source.getSubPageTemplates() != null) {
+            List<PageTemplate> subPages = Lists.newArrayList();
+            for (PageTemplate sub : source.getSubPageTemplates()) {
+                subPages.add(convert(sub));
+            }
+            converted.setSubPageTemplates(subPages);
+        }
+
+        if (source.getPageTemplateRegions() != null) {
+            List<PageTemplateRegion> convertedRegions = Lists.newArrayList();
+            for (PageTemplateRegion region : source.getPageTemplateRegions()) {
+                convertedRegions.add(convert(region));
+            }
+            converted.setPageTemplateRegions(convertedRegions);
+        }
+        return converted;
+    }
+
+    public void setPageLayoutRepository(PageLayoutRepository pageLayoutRepository) {
+        this.pageLayoutRepository = pageLayoutRepository;
+    }
+
+    public PageLayoutRepository getPageLayoutRepository() {
+        return pageLayoutRepository;
+    }
+
+    private PageTemplateRegion convert(PageTemplateRegion region) {
+        PageTemplateRegionImpl converted = region instanceof PageTemplateRegionImpl ? ((PageTemplateRegionImpl) region) : new PageTemplateRegionImpl();
+        updateProperties(region, converted);
+
+        if (region.getPageTemplateWidgets() != null) {
+            List<PageTemplateWidget> convertedWidgets = Lists.newArrayList();
+            for (PageTemplateWidget widget : region.getPageTemplateWidgets()) {
+                convertedWidgets.add(convert(widget));
+            }
+            converted.setPageTemplateWidgets(convertedWidgets);
+        }
+        return converted;
+    }
+
+    private PageTemplateWidget convert(PageTemplateWidget widget) {
+        PageTemplateWidgetImpl converted = widget instanceof PageTemplateWidgetImpl ? ((PageTemplateWidgetImpl) widget) : new PageTemplateWidgetImpl();
+        updateProperties(widget, converted);
+        return converted;
+    }
+
+
+    private void updateProperties(PageTemplateWidget source, PageTemplateWidgetImpl converted) {
+        converted.setId(source.getId() == null ? generateId() : source.getId());
+        converted.setHideChrome(source.isHideChrome());
+        converted.setPageTemplateRegion(null);
+        converted.setRenderSeq(source.getRenderSeq());
+        converted.setWidgetId(source.getWidgetId());
+        converted.setLocked(source.isLocked());
+    }
+
+    private void updateProperties(PageTemplateRegion source, PageTemplateRegionImpl converted) {
+        converted.setId(source.getId() == null ? generateId() : source.getId());
+        converted.setRenderSequence(source.getRenderSequence());
+        converted.setPageTemplate(null);
+        converted.setLocked(source.isLocked());
+    }
+
+    private void updateProperties(PageTemplate source, MongoDbPageTemplate converted) {
+        converted.setId(source.getId() == null ? generateId() : source.getId());
+        converted.setName(source.getName());
+        converted.setDescription(source.getDescription());
+        converted.setPageType(source.getPageType());
+        converted.setParentPageTemplate(null);
+        converted.setPageLayoutCode(source.getPageLayout().getCode());
+        converted.setPageLayout(null);
+        converted.setRenderSequence(source.getRenderSequence());
+        converted.setDefaultTemplate(source.isDefaultTemplate());
+    }
+
+
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbPortalPreferenceConverter.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbPortalPreferenceConverter.java
new file mode 100644
index 0000000..75f25db
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbPortalPreferenceConverter.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model.conversion.impl;
+
+import org.apache.rave.portal.model.MongoDbPortalPreference;
+import org.apache.rave.portal.model.PortalPreference;
+import org.apache.rave.portal.model.conversion.HydratingModelConverter;
+import org.springframework.stereotype.Component;
+
+@Component
+public class MongoDbPortalPreferenceConverter implements HydratingModelConverter<PortalPreference, MongoDbPortalPreference> {
+    @Override
+    public void hydrate(MongoDbPortalPreference dehydrated) {
+        //NOOP
+    }
+
+    @Override
+    public Class<PortalPreference> getSourceType() {
+        return PortalPreference.class;
+    }
+
+    @Override
+    public MongoDbPortalPreference convert(PortalPreference source) {
+        MongoDbPortalPreference converted = source instanceof MongoDbPortalPreference ? (MongoDbPortalPreference) source : new MongoDbPortalPreference();
+        converted.setKey(source.getKey());
+        converted.setValues(source.getValues());
+        return converted;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbUserConverter.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbUserConverter.java
new file mode 100644
index 0000000..8db0ae8
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbUserConverter.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model.conversion.impl;
+
+import com.google.common.collect.Lists;
+import org.apache.rave.portal.model.MongoDbPersonAssociation;
+import org.apache.rave.portal.model.MongoDbUser;
+import org.apache.rave.portal.model.User;
+import org.apache.rave.portal.model.conversion.HydratingModelConverter;
+import org.apache.rave.portal.repository.PageLayoutRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+import static org.apache.rave.portal.model.util.MongoDbModelUtil.generateId;
+
+@Component
+public class MongoDbUserConverter implements HydratingModelConverter<User, MongoDbUser> {
+    @Autowired
+    private PageLayoutRepository pageLayoutRepository;
+
+    @Override
+    public void hydrate(MongoDbUser dehydrated) {
+        if(dehydrated == null) {
+            return;
+        }
+        if(dehydrated.getFriends() == null) {
+            dehydrated.setFriends(Lists.<MongoDbPersonAssociation>newArrayList());
+        }
+        if(dehydrated.getAuthorityCodes() == null) {
+            dehydrated.setAuthorityCodes(Lists.<String>newArrayList());
+        }
+        dehydrated.setPageLayoutRepository(pageLayoutRepository);
+    }
+
+    @Override
+    public Class<User> getSourceType() {
+        return User.class;
+    }
+
+    public void setPageLayoutRepository(PageLayoutRepository pageLayoutRepository) {
+        this.pageLayoutRepository = pageLayoutRepository;
+    }
+
+    public PageLayoutRepository getPageLayoutRepository() {
+        return pageLayoutRepository;
+    }
+
+    @Override
+    public MongoDbUser convert(User source) {
+        MongoDbUser user = source instanceof MongoDbUser ? (MongoDbUser)source : new MongoDbUser();
+        List<String> authorityCodes = Lists.newArrayList();
+        for(GrantedAuthority authority : source.getAuthorities()) {
+            authorityCodes.add(authority.getAuthority());
+        }
+        user.setAuthorityCodes(authorityCodes);
+        updateProperties(source, user);
+        return user;
+    }
+
+    private void updateProperties(User source, MongoDbUser converted) {
+        converted.setId(source.getId() == null ? generateId() : source.getId());
+        converted.setUsername(source.getUsername());
+        converted.setEmail(source.getEmail());
+        converted.setDisplayName(source.getDisplayName());
+        converted.setAdditionalName(source.getAdditionalName());
+        converted.setFamilyName(source.getFamilyName());
+        converted.setGivenName(source.getGivenName());
+        converted.setHonorificPrefix(source.getHonorificPrefix());
+        converted.setHonorificSuffix(source.getHonorificSuffix());
+        converted.setPreferredName(source.getPreferredName());
+        converted.setAboutMe(source.getAboutMe());
+        converted.setStatus(source.getStatus());
+        converted.setAddresses(source.getAddresses());
+        converted.setOrganizations(source.getOrganizations());
+        converted.setProperties(source.getProperties());
+        converted.setPassword(source.getPassword());
+        converted.setConfirmPassword(source.getConfirmPassword());
+        converted.setDefaultPageLayoutCode(getPageLayoutCode(source));
+        converted.setEnabled(source.isEnabled());
+        converted.setExpired(source.isExpired());
+        converted.setLocked(source.isLocked());
+        converted.setOpenId(source.getOpenId());
+        converted.setForgotPasswordHash(source.getForgotPasswordHash());
+        converted.setForgotPasswordTime(source.getForgotPasswordTime());
+        converted.setPageLayoutRepository(null);
+    }
+
+    private String getPageLayoutCode(User source) {
+        String code = null;
+        if (source.getDefaultPageLayout() == null) {
+            if(source.getDefaultPageLayoutCode() != null) {
+                code = source.getDefaultPageLayoutCode();
+            }
+        } else {
+            code = source.getDefaultPageLayout().getCode();
+            source.setDefaultPageLayout(null);
+        }
+        return code;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbWidgetConverter.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbWidgetConverter.java
new file mode 100644
index 0000000..6baee3b
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/MongoDbWidgetConverter.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model.conversion.impl;
+
+import com.google.common.collect.Lists;
+import org.apache.rave.portal.model.*;
+import org.apache.rave.portal.model.conversion.HydratingModelConverter;
+import org.apache.rave.portal.model.impl.WidgetCommentImpl;
+import org.apache.rave.portal.model.impl.WidgetRatingImpl;
+import org.apache.rave.portal.repository.CategoryRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+import static org.apache.rave.portal.model.util.MongoDbModelUtil.generateId;
+
+/**
+ */
+@Component
+public class MongoDbWidgetConverter implements HydratingModelConverter<Widget, MongoDbWidget> {
+
+    @Autowired
+    private CategoryRepository categoryRepository;
+
+    @Override
+    public Class<Widget> getSourceType() {
+        return Widget.class;
+    }
+
+    @Override
+    public void hydrate(MongoDbWidget dehydrated) {
+        if(dehydrated == null) {
+            return;
+        }
+        dehydrated.setCategoryRepository(categoryRepository);
+    }
+
+    @Override
+    public MongoDbWidget convert(Widget source) {
+        MongoDbWidget widget = new MongoDbWidget();
+        updateProperties(source, widget);
+        widget.setOwnerId(source.getOwnerId());
+
+        if (source.getCategories() != null) {
+            convertCategories(source, widget);
+        }
+
+        if (source.getComments() == null) {
+            widget.setComments(Lists.<WidgetComment>newArrayList());
+        } else {
+            convertComments(source, widget);
+        }
+
+        List<WidgetTag> tags = source.getTags() == null ? Lists.<WidgetTag>newArrayList() : source.getTags();
+        widget.setTags(tags);
+
+        if (source.getRatings() == null) {
+            widget.setRatings(Lists.<WidgetRating>newArrayList());
+        } else {
+            convertRatings(source, widget);
+        }
+        return widget;
+    }
+
+    private void convertRatings(Widget source, MongoDbWidget widget) {
+        List<WidgetRating> ratings = source.getRatings();
+        List<WidgetRating> converted = Lists.newArrayList();
+        for(WidgetRating rating : ratings) {
+            String id = rating.getId() == null ? generateId() : rating.getId();
+            converted.add(new WidgetRatingImpl(id, rating.getUserId(), rating.getScore()));
+        }
+        widget.setRatings(converted);
+    }
+
+
+    private void convertComments(Widget source, MongoDbWidget widget) {
+        List<WidgetComment> convertedComments = Lists.newArrayList();
+        for (WidgetComment comment : source.getComments()) {
+            convertedComments.add(convert(comment, widget));
+        }
+        widget.setComments(convertedComments);
+    }
+
+
+    private WidgetCommentImpl convert(WidgetComment comment, Widget widget) {
+        WidgetCommentImpl converted = comment instanceof WidgetCommentImpl ? ((WidgetCommentImpl) comment) : new WidgetCommentImpl();
+        converted.setUserId(comment.getUserId());
+        converted.setId(comment.getId() == null ? generateId() : comment.getId());
+
+        converted.setCreatedDate(comment.getCreatedDate());
+        converted.setLastModifiedDate(comment.getLastModifiedDate());
+        converted.setText(comment.getText());
+        return converted;
+    }
+
+    private void convertCategories(Widget source, MongoDbWidget converted) {
+        List<String> categoryIds = Lists.<String>newArrayList();
+        for (Category category : source.getCategories()) {
+            categoryIds.add(category.getId());
+        }
+        converted.setCategoryIds(categoryIds);
+        converted.setCategories(null);
+        converted.setCategoryRepository(null);
+    }
+
+    private void updateProperties(Widget source, MongoDbWidget converted) {
+        converted.setId(source.getId() == null ? generateId() : source.getId());
+        converted.setUrl(source.getUrl());
+        converted.setType(source.getType());
+        converted.setTitle(source.getTitle());
+        converted.setTitleUrl(source.getTitleUrl());
+        converted.setUrl(source.getUrl());
+        converted.setThumbnailUrl(source.getThumbnailUrl());
+        converted.setScreenshotUrl(source.getScreenshotUrl());
+        converted.setAuthor(source.getAuthor());
+        converted.setAuthorEmail(source.getAuthorEmail());
+        converted.setDescription(source.getDescription());
+        converted.setWidgetStatus(source.getWidgetStatus());
+        converted.setComments(source.getComments());
+        converted.setDisableRendering(source.isDisableRendering());
+        converted.setFeatured(source.isFeatured());
+    }
+
+    public void setCategoryRepository(CategoryRepository categoryRepository) {
+        this.categoryRepository = categoryRepository;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/TagImplConverter.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/TagImplConverter.java
new file mode 100644
index 0000000..9a485fb
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/conversion/impl/TagImplConverter.java
@@ -0,0 +1,27 @@
+package org.apache.rave.portal.model.conversion.impl;
+
+import org.apache.rave.portal.model.Tag;
+import org.apache.rave.portal.model.conversion.HydratingModelConverter;
+import org.apache.rave.portal.model.impl.TagImpl;
+import org.springframework.stereotype.Component;
+
+import static org.apache.rave.portal.model.util.MongoDbModelUtil.generateId;
+
+@Component
+public class TagImplConverter implements HydratingModelConverter<Tag, TagImpl> {
+    @Override
+    public void hydrate(TagImpl dehydrated) {
+        //NOP
+    }
+
+    @Override
+    public Class<Tag> getSourceType() {
+        return Tag.class;
+    }
+
+    @Override
+    public TagImpl convert(Tag tag) {
+        String id = tag.getId() == null ? generateId() : tag.getId();
+        return new TagImpl(id, tag.getKeyword());
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/util/MongoDbModelUtil.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/util/MongoDbModelUtil.java
new file mode 100644
index 0000000..c31cff2
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/model/util/MongoDbModelUtil.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model.util;
+
+import java.util.Random;
+import java.util.UUID;
+
+/**
+ *
+ */
+public class MongoDbModelUtil {
+
+    private MongoDbModelUtil(){}
+
+    public static String generateId() {
+        return UUID.randomUUID().toString().replace("-", "_");
+    }
+
+    public static Long generateLongId() {
+        Random random = new Random();
+        return Math.abs(random.nextLong());
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/MongoModelOperations.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/MongoModelOperations.java
new file mode 100644
index 0000000..8f004a1
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/MongoModelOperations.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository;
+
+import org.springframework.data.mongodb.core.mapreduce.MapReduceResults;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.core.query.Update;
+
+import java.util.List;
+
+/**
+ */
+public interface MongoModelOperations<T> {
+    long count(Query query);
+    T findOne(Query query);
+    List<T> find(Query query);
+    T get(String id);
+    T save(T item);
+    void remove(Query query);
+    int update(Query query, Update update);
+    <E> MapReduceResults<E> mapReduce(String mapFunction, String reduceFunction, Class<E> entityClass);
+    <E> MapReduceResults<E> mapReduce(Query query, String mapFunction, String reduceFunction, Class<E> entityClass);
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/MongoPageOperations.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/MongoPageOperations.java
new file mode 100644
index 0000000..a1f75ed
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/MongoPageOperations.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository;
+
+import org.apache.rave.portal.model.Page;
+
+public interface MongoPageOperations extends MongoModelOperations<Page> {
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/MongoTagOperations.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/MongoTagOperations.java
new file mode 100644
index 0000000..4e444aa
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/MongoTagOperations.java
@@ -0,0 +1,9 @@
+package org.apache.rave.portal.repository;
+
+import org.apache.rave.portal.model.Tag;
+
+/**
+ * Provides Mongo Model Template operations for Tags
+ */
+public interface MongoTagOperations extends MongoModelOperations<Tag> {
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/MongoUserOperations.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/MongoUserOperations.java
new file mode 100644
index 0000000..b8bedee
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/MongoUserOperations.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository;
+
+import org.apache.rave.portal.model.User;
+
+public interface MongoUserOperations extends MongoModelOperations<User> {
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/MongoWidgetOperations.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/MongoWidgetOperations.java
new file mode 100644
index 0000000..8b9340d
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/MongoWidgetOperations.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository;
+
+import org.apache.rave.portal.model.Widget;
+
+public interface MongoWidgetOperations extends MongoModelOperations<Widget> {
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/StatisticsAggregator.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/StatisticsAggregator.java
new file mode 100644
index 0000000..0ced4c4
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/StatisticsAggregator.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository;
+
+import org.apache.rave.portal.model.util.WidgetStatistics;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Manages statistics for various attributes of the Rave
+ */
+public interface StatisticsAggregator {
+    Map<String, WidgetStatistics> getAllWidgetStatistics(String  userId);
+    WidgetStatistics getWidgetStatistics(String widget_id, String user_id);
+    Set<String> getUsersWithWidget(String widgetId);
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbApplicationDataRepository.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbApplicationDataRepository.java
new file mode 100644
index 0000000..2e5f6aa
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbApplicationDataRepository.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+
+import org.apache.rave.portal.model.ApplicationData;
+import org.apache.rave.portal.model.impl.ApplicationDataImpl;
+import org.apache.rave.portal.repository.ApplicationDataRepository;
+import org.apache.rave.util.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+import static org.apache.rave.portal.repository.util.CollectionNames.APP_DATA_COLLECTION;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+@Repository
+public class MongoDbApplicationDataRepository implements ApplicationDataRepository {
+    public static final Class<ApplicationDataImpl> CLASS = ApplicationDataImpl.class;
+
+    @Autowired
+    private MongoOperations template;
+
+    @Override
+    public List<ApplicationData> getApplicationData(List<String> userIds, String appId) {
+        return CollectionUtils.<ApplicationData>toBaseTypedList(template.find(query(where("appUrl").is(appId).andOperator(where("userId").in(userIds))), CLASS, APP_DATA_COLLECTION));
+    }
+
+    @Override
+    public ApplicationData getApplicationData(String personId, String appId) {
+        return template.findOne(query(where("appUrl").is(appId).andOperator(where("userId").is(personId))), CLASS, APP_DATA_COLLECTION);
+    }
+
+    @Override
+    public Class<? extends ApplicationData> getType() {
+        return CLASS;
+    }
+
+    @Override
+    public ApplicationData get(String id) {
+        return template.findById(id, CLASS, APP_DATA_COLLECTION);
+    }
+
+    @Override
+    public ApplicationData save(ApplicationData item) {
+        template.save(item, APP_DATA_COLLECTION);
+        return item;
+    }
+
+    @Override
+    public void delete(ApplicationData item) {
+        template.remove(item, APP_DATA_COLLECTION);
+    }
+
+    public void setTemplate(MongoOperations template) {
+        this.template = template;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbAuthorityRepository.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbAuthorityRepository.java
new file mode 100644
index 0000000..2cbfcec
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbAuthorityRepository.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.rave.exception.NotSupportedException;
+import org.apache.rave.portal.model.Authority;
+import org.apache.rave.portal.model.MongoDbAuthority;
+import org.apache.rave.portal.model.conversion.HydratingConverterFactory;
+import org.apache.rave.portal.model.impl.AuthorityImpl;
+import org.apache.rave.portal.repository.AuthorityRepository;
+import org.apache.rave.util.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+import static org.apache.rave.portal.repository.util.CollectionNames.AUTHORITY_COLLECTION;
+
+@Repository
+public class MongoDbAuthorityRepository implements AuthorityRepository {
+
+    public static final Class<MongoDbAuthority> CLASS = MongoDbAuthority.class;
+
+    @Autowired
+    private MongoOperations template;
+
+    @Autowired
+    private HydratingConverterFactory converter;
+
+    @Override
+    public Authority getByAuthority(String authorityName) {
+        return template.findOne(query(where("authority").is(authorityName)), CLASS, AUTHORITY_COLLECTION);
+    }
+
+    @Override
+    public List<Authority> getAll() {
+        return CollectionUtils.<Authority>toBaseTypedList(template.findAll(CLASS, AUTHORITY_COLLECTION));
+    }
+
+    @Override
+    public List<Authority> getAllDefault() {
+        return CollectionUtils.<Authority>toBaseTypedList(template.find(query(where("defaultForNewUser").is(true)), CLASS, AUTHORITY_COLLECTION));
+    }
+
+    @Override
+    public int getCountAll() {
+        return (int)template.count(new Query(), AUTHORITY_COLLECTION);
+    }
+
+    @Override
+    public Class<? extends Authority> getType() {
+        return AuthorityImpl.class;
+    }
+
+    @Override
+    public Authority get(String id) {
+        throw new NotSupportedException();
+    }
+
+    @Override
+    public Authority save(Authority item) {
+        Authority fromDb = getByAuthority(item.getAuthority());
+        Authority save;
+        if(fromDb == null) {
+            save = converter.convert(item, Authority.class);
+        } else {
+            fromDb.setDefaultForNewUser(item.isDefaultForNewUser());
+            save=fromDb;
+        }
+        template.save(save, AUTHORITY_COLLECTION);
+        return save;
+    }
+
+    @Override
+    public void delete(Authority item) {
+        template.remove(getByAuthority(item.getAuthority()), AUTHORITY_COLLECTION);
+    }
+
+    public void setTemplate(MongoOperations template) {
+        this.template = template;
+    }
+
+    public void setConverter(HydratingConverterFactory converter) {
+        this.converter = converter;
+    }
+
+    public MongoOperations getTemplate() {
+        return template;
+    }
+
+    public HydratingConverterFactory getConverter() {
+        return converter;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbCategoryRepository.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbCategoryRepository.java
new file mode 100644
index 0000000..3ce4aee
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbCategoryRepository.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.rave.portal.model.Category;
+import org.apache.rave.portal.model.MongoDbCategory;
+import org.apache.rave.portal.model.conversion.HydratingConverterFactory;
+import org.apache.rave.portal.repository.CategoryRepository;
+import org.apache.rave.util.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+import static org.apache.rave.portal.repository.util.CollectionNames.CATEGORY_COLLECTION;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+@Repository
+public class MongoDbCategoryRepository implements CategoryRepository {
+    public static final Class<MongoDbCategory> CLASS = MongoDbCategory.class;
+
+    @Autowired
+    private MongoOperations template;
+
+    @Autowired
+    private HydratingConverterFactory converter;
+
+    @Override
+    public List<Category> getAll() {
+        return CollectionUtils.<Category>toBaseTypedList(hydrate(template.findAll(CLASS, CATEGORY_COLLECTION)));
+    }
+
+    @Override
+    public int removeFromCreatedOrModifiedFields(String userId) {
+        List<MongoDbCategory> categories = template.find(query(where("lastModifiedUserId").is(userId).orOperator(where("createdUserId").is(userId))), CLASS, CATEGORY_COLLECTION);
+        int count = 0;
+        for(MongoDbCategory category : categories) {
+            boolean updated = updateCategory(userId, category);
+            if(updated) {
+                save(category);
+                count++;
+            }
+        }
+        return count;
+    }
+
+    @Override
+    public Class<? extends Category> getType() {
+        return CLASS;
+    }
+
+    @Override
+    public Category get(String id) {
+        return hydrate(template.findById(id, CLASS, CATEGORY_COLLECTION));
+    }
+
+    @Override
+    public Category save(Category item) {
+        MongoDbCategory converted = converter.convert(item, Category.class);
+        template.save(converted, CATEGORY_COLLECTION);
+        return hydrate(converted);
+    }
+
+    @Override
+    public void delete(Category item) {
+        template.remove(get(item.getId()), CATEGORY_COLLECTION);
+    }
+
+    private Category hydrate(MongoDbCategory category) {
+        converter.hydrate(category, Category.class);
+        return category;
+    }
+
+    private List<MongoDbCategory> hydrate(List<MongoDbCategory> all) {
+        for(MongoDbCategory category : all) {
+            hydrate(category);
+        }
+        return all;
+    }
+
+    private boolean updateCategory(String userId, MongoDbCategory category) {
+        boolean updated = false;
+        if(category.getCreatedUserId().equals(userId)) {
+            category.setCreatedUserId(null);
+            updated = true;
+        }
+        if(category.getLastModifiedUserId().equals(userId)) {
+            category.setLastModifiedUserId(null);
+            updated = true;
+        }
+        return updated;
+    }
+
+    public void setTemplate(MongoOperations template) {
+        this.template = template;
+    }
+
+    public void setConverter(HydratingConverterFactory converter) {
+        this.converter = converter;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbMapReduceStatisticsAggregator.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbMapReduceStatisticsAggregator.java
new file mode 100644
index 0000000..e40c54c
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbMapReduceStatisticsAggregator.java
@@ -0,0 +1,229 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import com.google.common.collect.Maps;
+import org.apache.rave.portal.model.WidgetRatingsMapReduceResult;
+import org.apache.rave.portal.model.WidgetUsersMapReduceResult;
+import org.apache.rave.portal.model.util.WidgetStatistics;
+import org.apache.rave.portal.repository.StatisticsAggregator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions;
+import org.springframework.data.mongodb.core.mapreduce.MapReduceResults;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import static org.apache.rave.portal.repository.util.CollectionNames.*;
+
+/**
+ * Provides Statistics via MapReduce jobs
+ */
+@Component
+public class MongoDbMapReduceStatisticsAggregator implements StatisticsAggregator {
+
+    private static final Logger log = LoggerFactory.getLogger(MongoDbMapReduceStatisticsAggregator.class);
+
+    public static final String RATINGS_MAP = "classpath:/org/apache/rave/WidgetRatingsMap.js";
+    public static final String RATINGS_REDUCE = "classpath:/org/apache/rave/WidgetRatingsReduce.js";
+    public static final String USERS_MAP = "classpath:/org/apache/rave/WidgetUsersMap.js";
+    public static final String USERS_REDUCE = "classpath:/org/apache/rave/WidgetUsersReduce.js";
+    public static final int DEFAULT_RESULT_VALIDITY = 60;
+    public static final String ID = "metadata";
+
+    private final MongoOperations mongoOperations;
+
+    @Autowired
+    public MongoDbMapReduceStatisticsAggregator(MongoOperations mongoOperations) {
+        this.mongoOperations = mongoOperations;
+    }
+
+    @Override
+    public WidgetStatistics getWidgetStatistics(String widget_id, String user_id) {
+        WidgetUsersMapReduceResult userResult = mongoOperations.findById(widget_id, WidgetUsersMapReduceResult.class, WIDGET_USERS);
+        WidgetRatingsMapReduceResult ratingResult = mongoOperations.findById(widget_id, WidgetRatingsMapReduceResult.class, WIDGET_RATINGS);
+
+        int userCount = userResult == null ? 0 : userResult.getValue().size();
+        WidgetStatistics stats;
+        if(ratingResult == null) {
+            stats = new WidgetStatistics();
+            stats.setUserRating(-1);
+        } else {
+            stats = createWidgetStatisticsFromResults(user_id, ratingResult);
+        }
+        stats.setTotalUserCount(userCount);
+        return stats;
+    }
+
+    @Override
+    public Set<String> getUsersWithWidget(String widgetId) {
+        WidgetUsersMapReduceResult result = mongoOperations.findById(widgetId, WidgetUsersMapReduceResult.class, WIDGET_USERS);
+        return result.getValue().keySet();
+    }
+
+    @Override
+    public Map<String , WidgetStatistics> getAllWidgetStatistics(String userId) {
+        List<WidgetRatingsMapReduceResult> widgetStats = mongoOperations.findAll(WidgetRatingsMapReduceResult.class, WIDGET_RATINGS);
+        List<WidgetUsersMapReduceResult> widgetUsers = mongoOperations.findAll(WidgetUsersMapReduceResult.class, WIDGET_USERS);
+
+        Map<String, WidgetStatistics> stats = Maps.newHashMap();
+        Map<String, Integer> userStats = mapUsersResults(widgetUsers);
+
+        if (widgetStats.size() > 0) {
+            addCombinedStats(userId, widgetStats, userStats, stats);
+        } else {
+            addUserCount(userStats, stats);
+        }
+        return stats;
+    }
+
+    @PostConstruct
+    public void init() {
+        Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    log.debug("Executing Map/Reduce Statistics Aggregation");
+                    buildStats();
+                } catch (Exception e) {
+                    log.error("Error executing Map/Reduce Statistics Aggregation!", e);
+                }
+            }
+        }, 0, DEFAULT_RESULT_VALIDITY, TimeUnit.SECONDS);
+    }
+
+    public void buildStats() {
+        RunStatistics runStats = mongoOperations.findById(ID, RunStatistics.class, OPERATIONS);
+        if(runStats == null || (System.currentTimeMillis() - runStats.getRefreshedTimeStamp()) > (DEFAULT_RESULT_VALIDITY * 1000)) {
+            queryForUserStats();
+        }
+    }
+
+    private void queryForUserStats() {
+        synchronized (this) {
+            executeUsersMapReduce();
+            executeRatingsMapReduce();
+            mongoOperations.save(new RunStatistics(ID, System.currentTimeMillis()), OPERATIONS);
+        }
+    }
+
+    private Map<String, Integer> mapUsersResults(List<WidgetUsersMapReduceResult> widgetUsersMapReduceResults) {
+        Map<String, Integer> map = Maps.newHashMap();
+        for (WidgetUsersMapReduceResult result : widgetUsersMapReduceResults) {
+            if (result.getId() != null) {
+                map.put(result.getId(), result.getValue().size());
+            }
+        }
+        return map;
+    }
+
+    private MapReduceOptions getOptions(String collection) {
+        //Currently a bug in javascriptMode prevents maps from being correctly stored by the db
+        return MapReduceOptions.options().outputCollection(collection).outputTypeReplace();
+    }
+
+    private MapReduceResults<WidgetUsersMapReduceResult> executeUsersMapReduce() {
+        return mongoOperations.mapReduce(PAGE_COLLECTION, USERS_MAP, USERS_REDUCE, getOptions(WIDGET_USERS), WidgetUsersMapReduceResult.class);
+    }
+
+    private MapReduceResults<WidgetRatingsMapReduceResult> executeRatingsMapReduce() {
+        return mongoOperations.mapReduce(WIDGET_COLLECTION, RATINGS_MAP, RATINGS_REDUCE, getOptions(WIDGET_RATINGS), WidgetRatingsMapReduceResult.class);
+    }
+
+    private void addUserCount(Map<String, Integer> users, Map<String, WidgetStatistics> stats) {
+        for (Map.Entry<String, Integer> result : users.entrySet()) {
+            WidgetStatistics widgetStatistics = getTotalUserOnlyWidgetStatistics(result.getValue());
+            stats.put(result.getKey(), widgetStatistics);
+        }
+    }
+
+    private void addCombinedStats(String userId, List<WidgetRatingsMapReduceResult> widgetStats, Map<String, Integer> usersMap, Map<String , WidgetStatistics> stats) {
+        for (WidgetRatingsMapReduceResult result : widgetStats) {
+            stats.put(result.getId(), createWidgetStatisticsFromResults(userId, result));
+        }
+        for(Map.Entry<String, Integer> id : usersMap.entrySet()) {
+            Integer value = id.getValue();
+            if(stats.containsKey(id.getKey())) {
+                stats.get(id.getKey()).setTotalUserCount(value);
+            } else {
+                WidgetStatistics stat = getTotalUserOnlyWidgetStatistics(value);
+                stats.put(id.getKey(), stat);
+            }
+        }
+    }
+
+    private WidgetStatistics getTotalUserOnlyWidgetStatistics(Integer value) {
+        WidgetStatistics stat = new WidgetStatistics();
+        stat.setTotalUserCount(value);
+        stat.setUserRating(-1);
+        return stat;
+    }
+
+    private WidgetStatistics createWidgetStatisticsFromResults(String user_id, WidgetRatingsMapReduceResult statsResult) {
+        WidgetStatistics statistics = new WidgetStatistics();
+        WidgetRatingsMapReduceResult.WidgetStatisticsMapReduceResult result = statsResult.getValue();
+        if (result != null) {
+            statistics.setTotalDislike(result.getDislike().intValue());
+            statistics.setTotalLike(result.getLike().intValue());
+            statistics.setUserRating(result.getUserRatings().containsKey(user_id) ? result.getUserRatings().get(user_id).intValue() : -1);
+        } else {
+            statistics.setUserRating(-1);
+        }
+        return statistics;
+    }
+
+    public static class RunStatistics {
+        private String id;
+        private Long refreshedTimeStamp;
+
+        public RunStatistics() {
+        }
+
+        public RunStatistics(String id, long timestamp) {
+            this.id = id;
+            this.refreshedTimeStamp = timestamp;
+        }
+
+        public String getId() {
+            return id;
+        }
+
+        public void setId(String id) {
+            this.id = id;
+        }
+
+        public Long getRefreshedTimeStamp() {
+            return refreshedTimeStamp;
+        }
+
+        public void setRefreshedTimeStamp(Long refreshedTimeStamp) {
+            this.refreshedTimeStamp = refreshedTimeStamp;
+        }
+    }
+
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbOAuthTokenInfoRepository.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbOAuthTokenInfoRepository.java
new file mode 100644
index 0000000..dc56a85
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbOAuthTokenInfoRepository.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.rave.portal.model.OAuthTokenInfo;
+import org.apache.rave.portal.model.impl.OAuthTokenInfoImpl;
+import org.apache.rave.portal.repository.OAuthTokenInfoRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.stereotype.Repository;
+
+import static org.apache.rave.portal.repository.util.CollectionNames.OAUTH_TOKEN_COLLECTION;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+@Repository
+public class MongoDbOAuthTokenInfoRepository implements OAuthTokenInfoRepository {
+
+    public static final Class<OAuthTokenInfoImpl> CLASS = OAuthTokenInfoImpl.class;
+
+    @Autowired
+    private MongoOperations template;
+
+    @Override
+    public OAuthTokenInfo findOAuthTokenInfo(String userId, String appUrl, String moduleId, String tokenName, String serviceName) {
+        return template.findOne(
+                query(where("userId").is(userId)
+                .andOperator(where("appUrl").is(appUrl))
+                .andOperator(where("moduleId").is(moduleId))
+                .andOperator(where("tokenName").is(tokenName))
+                .andOperator(where("serviceName").is(serviceName))
+        ), CLASS, OAUTH_TOKEN_COLLECTION);
+    }
+
+    @Override
+    public Class<? extends OAuthTokenInfo> getType() {
+        return CLASS;
+    }
+
+    @Override
+    public OAuthTokenInfo get(String id) {
+        return template.findById(id, CLASS, OAUTH_TOKEN_COLLECTION);
+    }
+
+    @Override
+    public OAuthTokenInfo save(OAuthTokenInfo item) {
+        template.save(item, OAUTH_TOKEN_COLLECTION);
+        return item;
+    }
+
+    @Override
+    public void delete(OAuthTokenInfo item) {
+        template.remove(get(item.getId()));
+    }
+
+    public void setTemplate(MongoOperations template) {
+        this.template = template;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbOauthConsumerStoreRepository.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbOauthConsumerStoreRepository.java
new file mode 100644
index 0000000..b0dbb47
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbOauthConsumerStoreRepository.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.rave.portal.model.OAuthConsumerStore;
+import org.apache.rave.portal.model.impl.OAuthConsumerStoreImpl;
+import org.apache.rave.portal.repository.OAuthConsumerStoreRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.stereotype.Repository;
+
+import static org.apache.rave.portal.repository.util.CollectionNames.OAUTH_CONSUMER_COLLECTION;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+@Repository
+public class MongoDbOauthConsumerStoreRepository implements OAuthConsumerStoreRepository {
+    public static final Class<OAuthConsumerStoreImpl> CLASS = OAuthConsumerStoreImpl.class;
+
+    @Autowired
+    private MongoOperations template;
+
+    @Override
+    public OAuthConsumerStore findByUriAndServiceName(String gadgetUri, String serviceName) {
+        return template.findOne(query(where("gadgetUri").is(gadgetUri).andOperator(where("serviceName").is(serviceName))), CLASS, OAUTH_CONSUMER_COLLECTION);
+    }
+
+    @Override
+    public Class<? extends OAuthConsumerStore> getType() {
+        return CLASS;
+    }
+
+    @Override
+    public OAuthConsumerStore get(String id) {
+        return template.findById(id, CLASS, OAUTH_CONSUMER_COLLECTION);
+    }
+
+    @Override
+    public OAuthConsumerStore save(OAuthConsumerStore item) {
+        template.save(item, OAUTH_CONSUMER_COLLECTION);
+        return item;
+    }
+
+    @Override
+    public void delete(OAuthConsumerStore item) {
+        template.remove(get(item.getId()));
+    }
+
+    public void setTemplate(MongoOperations template) {
+        this.template = template;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbPageLayoutRepository.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbPageLayoutRepository.java
new file mode 100644
index 0000000..7d585ce
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbPageLayoutRepository.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.commons.lang.NotImplementedException;
+import org.apache.rave.portal.model.MongoDbPageLayout;
+import org.apache.rave.portal.model.PageLayout;
+import org.apache.rave.portal.repository.PageLayoutRepository;
+import org.apache.rave.util.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+import static org.apache.rave.portal.repository.util.CollectionNames.PAGE_LAYOUT_COLLECTION;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+
+@Repository
+public class MongoDbPageLayoutRepository implements PageLayoutRepository {
+    public static final Class<MongoDbPageLayout> CLASS = MongoDbPageLayout.class;
+
+    @Autowired
+    private MongoOperations template;
+
+    @Override
+    public PageLayout getByPageLayoutCode(String codename) {
+        return template.findOne(new Query(where("code").is(codename)), CLASS, PAGE_LAYOUT_COLLECTION);
+    }
+
+    @Override
+    public List<PageLayout> getAll() {
+        return CollectionUtils.<PageLayout>toBaseTypedList(template.findAll(CLASS, PAGE_LAYOUT_COLLECTION));
+    }
+
+    @Override
+    public List<PageLayout> getAllUserSelectable() {
+        List<MongoDbPageLayout> userSelectable = template.find(new Query(where("userSelectable").is(true)), CLASS, PAGE_LAYOUT_COLLECTION);
+        return CollectionUtils.<PageLayout>toBaseTypedList(userSelectable);
+    }
+
+    @Override
+    public Class<? extends PageLayout> getType() {
+        return CLASS;
+    }
+
+    @Override
+    public PageLayout get(String id) {
+        throw new NotImplementedException("No use for an id");
+    }
+
+    @Override
+    public PageLayout save(PageLayout item) {
+        MongoDbPageLayout toSave = (MongoDbPageLayout)getByPageLayoutCode(item.getCode());
+        if(toSave == null) {
+            toSave = new MongoDbPageLayout();
+        }
+        update(item, toSave);
+        template.save(toSave, PAGE_LAYOUT_COLLECTION);
+        return toSave;
+    }
+
+    @Override
+    public void delete(PageLayout item) {
+        template.remove(getByPageLayoutCode(item.getCode()));
+    }
+
+    private void update(PageLayout source, PageLayout converted) {
+        converted.setCode(source.getCode());
+        converted.setNumberOfRegions(source.getNumberOfRegions());
+        converted.setRenderSequence(source.getRenderSequence());
+        converted.setUserSelectable(source.isUserSelectable());
+    }
+
+    public void setTemplate(MongoOperations template) {
+        this.template = template;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbPageRepository.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbPageRepository.java
new file mode 100644
index 0000000..4e41c01
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbPageRepository.java
@@ -0,0 +1,268 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import com.google.common.collect.Lists;
+import org.apache.rave.portal.model.*;
+import org.apache.rave.portal.model.impl.PageImpl;
+import org.apache.rave.portal.model.impl.PageUserImpl;
+import org.apache.rave.portal.model.impl.RegionImpl;
+import org.apache.rave.portal.model.impl.RegionWidgetImpl;
+import org.apache.rave.portal.repository.MongoPageOperations;
+import org.apache.rave.portal.repository.PageRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+/**
+ */
+@Repository
+public class MongoDbPageRepository implements PageRepository {
+
+    @Autowired
+    private MongoPageOperations template;
+
+    @Override
+    public List<Page> getAllPages(String  userId, PageType pageType) {
+        return sort(template.find(query(where("pageType").is(getString(pageType)).andOperator(where("members").elemMatch(where("userId").is(userId))))), userId);
+    }
+
+    @Override
+    public int deletePages(String userId, PageType pageType) {
+        Query query = query(where("pageType").is(pageType).andOperator(where("ownerId").is(userId)));
+        int count = (int)template.count(query);
+        template.remove(query);
+        return count;
+    }
+
+    @Override
+    public Page createPageForUser(User user, PageTemplate pt) {
+        return save(convertTemplate(pt, user));
+    }
+
+    @Override
+    public boolean hasPersonPage(String userId) {
+        return template.count(query(where("pageType").is(PageType.PERSON_PROFILE).andOperator(where("ownerId").is(userId)))) > 0;
+    }
+
+    @Override
+    public List<PageUser> getPagesForUser(String userId, PageType pageType) {
+        List<Page> pages = template.find(query(where("members").elemMatch(where("userId").is(userId)).andOperator(where("pageType").is(getString(pageType)))));
+        List<PageUser> userList = Lists.newArrayList();
+        for(Page page : pages) {
+            userList.add(findPageUser(userId, page));
+        }
+        return sortUsers(userList, userId);
+    }
+
+    @Override
+    public PageUser getSingleRecord(String userId, String pageId) {
+        Page page = get(pageId);
+        for(PageUser user : page.getMembers()) {
+            if(user.getUserId().equals(userId))
+                return user;
+        }
+        return null;
+    }
+
+    @Override
+    public Class<? extends Page> getType() {
+        return MongoDbPage.class;
+    }
+
+    @Override
+    public Page get(String  id) {
+        return template.get(id);
+    }
+
+    @Override
+    public Page save(Page item) {
+        return template.save(item);
+    }
+
+    @Override
+    public void delete(Page item) {
+        template.remove(query(where("_id").is(item.getId())));
+    }
+
+    private List<Page> sort(List<Page> pages, final String  userId) {
+        Collections.sort(pages, new Comparator<Page>() {
+            @Override
+            public int compare(Page page, Page page1) {
+                return getRenderOrder(page, userId) - getRenderOrder(page1, userId);
+            }
+        });
+        return pages;
+    }
+
+    private List<PageUser> sortUsers(List<PageUser> userList, String userId) {
+        Collections.sort(userList, new Comparator<PageUser>() {
+            @Override
+            public int compare(PageUser pageUser, PageUser pageUser1) {
+                return getRenderOrder(pageUser) - getRenderOrder(pageUser1);
+            }
+        });
+        return userList;
+    }
+
+    private int getRenderOrder(PageUser pageUser) {
+        return pageUser == null || pageUser.getRenderSequence() == null ? Integer.MAX_VALUE : pageUser.getRenderSequence().intValue();
+    }
+
+    private int getRenderOrder(Page page, String  userId) {
+        for(PageUser user : page.getMembers()) {
+            if(user.getUserId().equals(userId)) {
+                return getRenderOrder(user);
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * convertTemplate: PageTemplate, User -> Page
+     * Converts the PageTemplate for Person Profiles into a Person Profile Page
+     * @param pt PageTemplate
+     * @param user User
+     * @return Page
+     */
+    private Page convertTemplate(PageTemplate pt, User user) {
+        Page p = new PageImpl();
+        p.setName(pt.getName());
+        p.setPageType(pt.getPageType());
+        p.setOwnerId(user.getId());
+        PageUser pageUser = new PageUserImpl(user.getId(), p, pt.getRenderSequence());
+        pageUser.setPageStatus(PageInvitationStatus.OWNER);
+        pageUser.setEditor(true);
+        List<PageUser> members = new ArrayList<PageUser>();
+        members.add(pageUser);
+        p.setMembers(members);
+
+        p.setPageLayout(pt.getPageLayout());
+        p.setRegions(convertRegions(pt.getPageTemplateRegions(), p));
+        p.setSubPages(convertPages(pt.getSubPageTemplates(), p));
+        return p;
+    }
+
+    /**
+     * convertRegions: List of PageTemplateRegion, Page -> List of Regions
+     * Converts the JpaRegion Templates of the Page Template to Regions for the page
+     * @param pageTemplateRegions List of PageTemplateRegion
+     * @param page Page
+     * @return list of JpaRegion
+     */
+    private List<Region> convertRegions(List<PageTemplateRegion> pageTemplateRegions, Page page){
+        List<Region> regions = new ArrayList<Region>();
+        for (PageTemplateRegion ptr : pageTemplateRegions){
+            Region region = new RegionImpl();
+            region.setRenderOrder((int) ptr.getRenderSequence());
+            region.setPage(page);
+            region.setLocked(ptr.isLocked());
+            region.setRegionWidgets(convertWidgets(ptr.getPageTemplateWidgets(), region));
+            regions.add(region);
+        }
+        return regions;
+    }
+
+    /**
+     * convertWidgets: List of PageTemplateWidget, JpaRegion -> List of RegionWidget
+     * Converts the Page Template Widgets to RegionWidgets for the given JpaRegion
+     * @param pageTemplateWidgets List of PageTemplateWidget
+     * @param region JpaRegion
+     * @return List of RegionWidget
+     */
+    private List<RegionWidget> convertWidgets(List<PageTemplateWidget> pageTemplateWidgets, Region region){
+        List<RegionWidget> widgets = new ArrayList<RegionWidget>();
+        for (PageTemplateWidget ptw : pageTemplateWidgets){
+            RegionWidget regionWidget = new RegionWidgetImpl();
+            regionWidget.setRegion(region);
+            regionWidget.setCollapsed(false);
+            regionWidget.setLocked(ptw.isLocked());
+            regionWidget.setHideChrome(ptw.isHideChrome());
+            regionWidget.setRenderOrder((int) ptw.getRenderSeq());
+            regionWidget.setWidgetId(ptw.getWidgetId());
+            widgets.add(regionWidget);
+        }
+        return widgets;
+    }
+
+    /**
+     * convertPages: List of PageTemplate, Page -> List of Page
+     * Converts the template subpages in to a list of Pages for the given page object
+     * This is a recursive function. A sub page could have a list of sub pages.
+     * @param pageTemplates List of PageTemplate
+     * @param page Page
+     * @return list of Page
+     */
+    private List<Page> convertPages(List<PageTemplate> pageTemplates, Page page){
+        List<Page> pages = new ArrayList<Page>();
+        for(PageTemplate pt : pageTemplates){
+            Page lPage = new PageImpl();
+            lPage.setName(pt.getName());
+            lPage.setPageType(pt.getPageType());
+            lPage.setOwnerId(page.getOwnerId());
+            lPage.setPageLayout(pt.getPageLayout());
+            lPage.setParentPage(page);
+            lPage.setRegions(convertRegions(pt.getPageTemplateRegions(), lPage));
+
+            // create new pageUser tuple
+            PageUser pageUser = new PageUserImpl(lPage.getOwnerId(), lPage, pt.getRenderSequence());
+            pageUser.setPageStatus(PageInvitationStatus.OWNER);
+            pageUser.setEditor(true);
+            List<PageUser> members = new ArrayList<PageUser>();
+            members.add(pageUser);
+            lPage.setMembers(members);
+            // recursive call
+            lPage.setSubPages((pt.getSubPageTemplates() == null || pt.getSubPageTemplates().isEmpty()) ? null : convertPages(pt.getSubPageTemplates(), lPage));
+            pages.add(lPage);
+        }
+        return pages;
+    }
+
+    private PageUser findPageUser(String userId, Page page) {
+        for(PageUser user : page.getMembers()) {
+            if(user.getUserId().equals(userId)) {
+                return user;
+            }
+        }
+        return null;
+    }
+
+    private String getString(PageType pageType) {
+        return pageType.getPageType().toUpperCase();
+    }
+
+    public MongoPageOperations getTemplate() {
+        return template;
+    }
+
+    public void setTemplate(MongoPageOperations template) {
+        this.template = template;
+    }
+
+
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbPageTemplateRepository.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbPageTemplateRepository.java
new file mode 100644
index 0000000..cb9539c
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbPageTemplateRepository.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.rave.portal.model.MongoDbPageTemplate;
+import org.apache.rave.portal.model.PageTemplate;
+import org.apache.rave.portal.model.PageType;
+import org.apache.rave.portal.model.conversion.HydratingConverterFactory;
+import org.apache.rave.portal.repository.PageTemplateRepository;
+import org.apache.rave.util.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+import static org.apache.rave.portal.repository.util.CollectionNames.PAGE_TEMPLATE_COLLECTION;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+
+/**
+ */
+@Repository
+public class MongoDbPageTemplateRepository implements PageTemplateRepository {
+
+    @Autowired
+    private HydratingConverterFactory converter;
+
+    @Autowired
+    private MongoOperations template;
+
+    @Override
+    public List<PageTemplate> getAll() {
+        List<MongoDbPageTemplate> templates = template.findAll(MongoDbPageTemplate.class, PAGE_TEMPLATE_COLLECTION);
+        for(MongoDbPageTemplate temp : templates) {
+            converter.hydrate(temp, PageTemplate.class);
+        }
+        return CollectionUtils.<PageTemplate>toBaseTypedList(templates);
+    }
+
+    @Override
+    public PageTemplate getDefaultPage(PageType pageType) {
+        PageTemplate temp = template.findOne(new Query(where("pageType").is(pageType.getPageType().toUpperCase()).andOperator(where("defaultTemplate").is(true))), MongoDbPageTemplate.class, PAGE_TEMPLATE_COLLECTION);
+        converter.hydrate(temp, PageTemplate.class);
+        return temp;
+    }
+
+    @Override
+    public PageTemplate save(PageTemplate pageTemplate) {
+        MongoDbPageTemplate converted = converter.convert(pageTemplate, PageTemplate.class);
+        template.save(converted, PAGE_TEMPLATE_COLLECTION);
+        converter.hydrate(converted, PageTemplate.class);
+        return converted;
+    }
+
+    public void setConverter(HydratingConverterFactory converter) {
+        this.converter = converter;
+    }
+
+    public void setTemplate(MongoOperations template) {
+        this.template = template;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbPersonRepository.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbPersonRepository.java
new file mode 100644
index 0000000..7fcb147
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbPersonRepository.java
@@ -0,0 +1,297 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.apache.commons.lang.NotImplementedException;
+import org.apache.rave.portal.model.*;
+import org.apache.rave.portal.repository.MongoPageOperations;
+import org.apache.rave.portal.repository.MongoUserOperations;
+import org.apache.rave.portal.repository.MongoWidgetOperations;
+import org.apache.rave.portal.repository.PersonRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Nullable;
+import java.util.*;
+
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+/**
+ */
+@Component
+public class MongoDbPersonRepository implements PersonRepository {
+
+    @Autowired
+    private MongoUserOperations template;
+
+    @Autowired
+    private MongoPageOperations pageTemplate;
+
+    @Autowired
+    private MongoWidgetOperations widgetOperations;
+
+    @Override
+    public Person findByUsername(String username) {
+        return template.findOne(getUsernameQuery(username)).toPerson();
+    }
+
+    @Override
+    public List<Person> findAllConnectedPeople(String username) {
+        return findFriends(username);  //TODO update when groups is implemented
+    }
+
+    @Override
+    public List<Person> findAllConnectedPeople(String username, String appId) {
+        return findFriends(username, appId);  //TODO update when groups is implemented
+    }
+
+    @Override
+    public List<Person> findAllConnectedPeopleWithFriend(String username, String friendUsername) {
+        return findFriendsWithFriend(username, friendUsername); //TODO update when groups is implemented
+    }
+
+    @Override
+    public List<Person> findFriends(String username) {
+        MongoDbUser user = (MongoDbUser) template.findOne(getUsernameQuery(username));
+        return Lists.transform(filterByRequestType(user.getFriends(), FriendRequestStatus.ACCEPTED), new Function<MongoDbPersonAssociation, Person>() {
+            @Override
+            public Person apply(@Nullable MongoDbPersonAssociation input) {
+                return input == null ? null : template.get(input.getPersonId()).toPerson();
+            }
+        });
+    }
+
+    @Override
+    public List<Person> findFriends(String username, String appId) {
+        MongoDbUser user = (MongoDbUser) template.findOne(getUsernameQuery(username));
+        Widget w = widgetOperations.findOne(query(where("url").is(appId)));
+        Query q = query(where("ownerId").in(getFriendIds(user.getFriends())).and("regions").elemMatch(where("regionWidgets").elemMatch(where("widgetId").is(w.getId()))));
+        List<Page> pages = pageTemplate.find(q);
+        return getPersonListFromPages(pages);
+    }
+
+    @Override
+    public List<Person> findFriendsWithFriend(String username, String friendUsername) {
+        MongoDbUser follower = (MongoDbUser) template.findOne(getUsernameQuery(username));
+        MongoDbUser followed = (MongoDbUser) template.findOne(getUsernameQuery(friendUsername));
+        List<String> commonFriends = getCommonFriends(follower, followed);
+        return Lists.transform(commonFriends, new Function<String, Person>() {
+            @Override
+            public Person apply(@Nullable String id) {
+                return id == null ? null : template.get(id).toPerson();
+            }
+        });
+    }
+
+    @Override
+    public List<Person> findByGroup(String groupId) {
+        throw new NotImplementedException(); //TODO build query
+    }
+
+    @Override
+    public List<Person> findByGroup(String groupId, String appId) {
+        throw new NotImplementedException();  //TODO build query
+    }
+
+    @Override
+    public List<Person> findByGroupWithFriend(String groupId, String friendUsername) {
+        throw new NotImplementedException();  //TODO build query
+    }
+
+    @Override
+    public boolean addFriend(String friendUsername, String username) {
+        MongoDbUser follower = (MongoDbUser) template.findOne(getUsernameQuery(username));
+        MongoDbUser followed = (MongoDbUser) template.findOne(getUsernameQuery(friendUsername));
+
+        MongoDbPersonAssociation outgoing = new MongoDbPersonAssociation(followed.getId(), FriendRequestStatus.SENT, MongoDbPersonAssociation.Direction.OUTGOING);
+        MongoDbPersonAssociation incoming = new MongoDbPersonAssociation(follower.getId(), FriendRequestStatus.RECEIVED, MongoDbPersonAssociation.Direction.INCOMING);
+
+        follower.getFriends().add(outgoing);
+        followed.getFriends().add(incoming);
+
+        template.save(followed);
+        template.save(follower);
+        return true;
+    }
+
+    @Override
+    public void removeFriend(String friendUsername, String username) {
+        MongoDbUser follower = (MongoDbUser) template.findOne(getUsernameQuery(username));
+        MongoDbUser followed = (MongoDbUser) template.findOne(getUsernameQuery(friendUsername));
+        removeAssociation(follower, followed);
+        removeAssociation(followed, follower);
+        template.save(follower);
+        template.save(followed);
+    }
+
+    @Override
+    public HashMap<String, List<Person>> findFriendsAndRequests(String username) {
+        HashMap<String, List<Person>> friendsAndRequests = new HashMap<String, List<Person>>();
+        friendsAndRequests.put(FriendRequestStatus.ACCEPTED.toString(), findFriends(username));
+        friendsAndRequests.put(FriendRequestStatus.SENT.toString(), findFriendRequestsSent(username));
+        friendsAndRequests.put(FriendRequestStatus.RECEIVED.toString(), findFriendRequestsReceived(username));
+        return friendsAndRequests;
+    }
+
+    @Override
+    public boolean acceptFriendRequest(String friendUsername, String username) {
+        MongoDbUser follower = (MongoDbUser) template.findOne(getUsernameQuery(username));
+        MongoDbUser followed = (MongoDbUser) template.findOne(getUsernameQuery(friendUsername));
+        setAccepted(follower, followed);
+        setAccepted(followed, follower);
+        template.save(follower);
+        template.save(followed);
+        return true;
+    }
+
+    @Override
+    public List<Person> findFriendRequestsReceived(String username) {
+        MongoDbUser followed = (MongoDbUser) template.findOne(getUsernameQuery(username));
+        return getPersonListFromAssociations(followed, FriendRequestStatus.RECEIVED);
+    }
+
+    @Override
+    public List<Person> findFriendRequestsSent(String username) {
+        MongoDbUser follower = (MongoDbUser) template.findOne(getUsernameQuery(username));
+        return getPersonListFromAssociations(follower, FriendRequestStatus.SENT);
+    }
+
+    @Override
+    public int removeAllFriendsAndRequests(String userid) {
+        MongoDbUser person = (MongoDbUser)template.get(userid);
+        int count = person.getFriends().size();
+        person.setFriends(Lists.<MongoDbPersonAssociation>newArrayList());
+        save(person);
+        return count;
+    }
+
+    @Override
+    public Class<? extends Person> getType() {
+        return Person.class;
+    }
+
+    @Override
+    public Person get(String id) {
+        return template.get(id);
+    }
+
+    @Override
+    public Person save(Person item) {
+        //TODO Support saving people other than users
+        return item instanceof User ? template.save((User) item) : null;
+    }
+
+    @Override
+    public void delete(Person item) {
+        template.remove(getUsernameQuery(item.getUsername()));
+    }
+
+    private List<Person> getPersonListFromAssociations(MongoDbUser follower, FriendRequestStatus status) {
+        return Lists.transform(filterByRequestType(follower.getFriends(), status), new Function<MongoDbPersonAssociation, Person>() {
+            @Override
+            public Person apply(@Nullable MongoDbPersonAssociation input) {
+                return input == null ? null : template.get(input.getPersonId()).toPerson();
+            }
+        });
+    }
+
+    private List<Person> getPersonListFromPages(List<Page> pages) {
+        return Lists.transform(pages, new Function<Page, Person>() {
+            @Override
+            public Person apply(@Nullable Page input) {
+                return input == null ? null : template.get(input.getOwnerId()).toPerson();
+            }
+        });
+    }
+
+    private List<String> getFriendIds(List<MongoDbPersonAssociation> friends) {
+        List<String> ids = Lists.newArrayList();
+        for (MongoDbPersonAssociation friend : friends) {
+            if (friend.getRequestStatus().equals(FriendRequestStatus.ACCEPTED)) {
+                ids.add(friend.getPersonId());
+            }
+        }
+        return ids;
+    }
+
+    private Query getUsernameQuery(String username) {
+        return query(where("username").is(username));
+    }
+
+    private List<MongoDbPersonAssociation> filterByRequestType(List<MongoDbPersonAssociation> friends, FriendRequestStatus received) {
+        List<MongoDbPersonAssociation> filtered = Lists.newArrayList();
+        for (MongoDbPersonAssociation association : friends) {
+            if (association.getRequestStatus().equals(received)) {
+                filtered.add(association);
+            }
+        }
+        return filtered;
+    }
+
+    private void removeAssociation(MongoDbUser friend, MongoDbUser person) {
+        for (MongoDbPersonAssociation association : person.getFriends()) {
+            if (association.getPersonId().equals(friend.getId())) {
+                person.getFriends().remove(association);
+                break;
+            }
+        }
+    }
+
+    private void setAccepted(MongoDbUser friend, MongoDbUser person) {
+        for (MongoDbPersonAssociation association : person.getFriends()) {
+            if (association.getPersonId().equals(friend.getId())) {
+                association.setRequestStatus(FriendRequestStatus.ACCEPTED);
+            }
+        }
+    }
+
+    private List<String> getCommonFriends(MongoDbUser follower, MongoDbUser followed) {
+        List<String> ids = Lists.newArrayList();
+        Map<String, MongoDbPersonAssociation> friendHash = Maps.newHashMap();
+        for (MongoDbPersonAssociation association : follower.getFriends()) {
+            friendHash.put(association.getPersonId(), association);
+        }
+        for (MongoDbPersonAssociation friendAssociation : followed.getFriends()) {
+            if (friendHash.containsKey(friendAssociation.getPersonId()) &&
+                    friendHash.get(friendAssociation.getPersonId()).getRequestStatus().equals(FriendRequestStatus.ACCEPTED) &&
+                    friendAssociation.getRequestStatus().equals(FriendRequestStatus.ACCEPTED)) {
+                ids.add(friendAssociation.getPersonId());
+            }
+        }
+        return ids;
+    }
+
+    public void setTemplate(MongoUserOperations template) {
+        this.template = template;
+    }
+
+    public void setPageTemplate(MongoPageOperations pageTemplate) {
+        this.pageTemplate = pageTemplate;
+    }
+
+    public void setWidgetOperations(MongoWidgetOperations widgetOperations) {
+        this.widgetOperations = widgetOperations;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbPortalPreferenceRepository.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbPortalPreferenceRepository.java
new file mode 100644
index 0000000..777009f
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbPortalPreferenceRepository.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.rave.portal.model.MongoDbPortalPreference;
+import org.apache.rave.portal.model.PortalPreference;
+import org.apache.rave.portal.model.conversion.HydratingConverterFactory;
+import org.apache.rave.portal.model.impl.PortalPreferenceImpl;
+import org.apache.rave.portal.repository.PortalPreferenceRepository;
+import org.apache.rave.util.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+import static org.apache.rave.portal.repository.util.CollectionNames.PREFERENCE_COLLECTION;
+
+@Repository
+public class MongoDbPortalPreferenceRepository implements PortalPreferenceRepository {
+
+
+    public static final Class<PortalPreferenceImpl> CLASS = PortalPreferenceImpl.class;
+
+    @Autowired
+    private MongoOperations template;
+
+    @Autowired
+    private HydratingConverterFactory converter;
+
+    @Override
+    public List<PortalPreference> getAll() {
+        return CollectionUtils.<PortalPreference>toBaseTypedList(template.findAll(CLASS, PREFERENCE_COLLECTION));
+    }
+
+    @Override
+    public PortalPreference getByKey(String key) {
+        return template.findOne(query(where("key").is(key)), CLASS, PREFERENCE_COLLECTION);
+    }
+
+    @Override
+    public Class<? extends PortalPreference> getType() {
+        return CLASS;
+    }
+
+    @Override
+    public PortalPreference get(String id) {
+        return template.findById(id, CLASS, PREFERENCE_COLLECTION);
+    }
+
+    @Override
+    public PortalPreference save(PortalPreference item) {
+        PortalPreference fromDb = getByKey(item.getKey());
+        MongoDbPortalPreference converted = converter.convert(item, PortalPreference.class);
+        if(fromDb != null) {
+            converted.setId(((MongoDbPortalPreference)fromDb).getId());
+        }
+        template.save(converted, PREFERENCE_COLLECTION);
+        converter.hydrate(converted, PortalPreference.class);
+        return converted;
+    }
+
+    @Override
+    public void delete(PortalPreference item) {
+        template.remove(getByKey(item.getKey()), PREFERENCE_COLLECTION);
+    }
+
+    public void setTemplate(MongoOperations template) {
+        this.template = template;
+    }
+
+    public void setConverter(HydratingConverterFactory converter) {
+        this.converter = converter;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbRegionRepository.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbRegionRepository.java
new file mode 100644
index 0000000..350fd9a
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbRegionRepository.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.rave.portal.model.Page;
+import org.apache.rave.portal.model.Region;
+import org.apache.rave.portal.model.impl.RegionImpl;
+import org.apache.rave.portal.repository.MongoPageOperations;
+import org.apache.rave.portal.repository.RegionRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ */
+@Repository
+public class MongoDbRegionRepository implements RegionRepository {
+
+    @Autowired
+    private MongoPageOperations template;
+
+
+    @Override
+    public Class<? extends Region> getType() {
+        return RegionImpl.class;
+    }
+
+    @Override
+    public Region get(String  id) {
+        Page page = getPageByRegionId(id);
+        for(Region region : page.getRegions()) {
+            if(region.getId().equals(id)) {
+                return region;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Region save(Region item) {
+        Page page;
+        int index;
+
+        if(item.getId() == null) {
+            page = getPageFromRepository(item);
+            page.getRegions().add(item);
+            index = page.getRegions().size()-1;
+        } else {
+            page = getPageByRegionId(item.getId());
+            index = replaceRegion(page, item);
+        }
+        Page saved = template.save(page);
+        return saved.getRegions().get(index);
+    }
+
+    @Override
+    public void delete(Region item) {
+        Page page;
+
+        if(item.getId() == null) {
+            throw new IllegalStateException("Unidentifiable region (null id)");
+        } else {
+            page = getPageByRegionId(item.getId());
+            removeRegion(page, item);
+        }
+        template.save(page);
+    }
+
+    private void removeRegion(Page page, Region item) {
+        Iterator<Region> iterator = page.getRegions().iterator();
+        while(iterator.hasNext()) {
+            Region region = iterator.next();
+            if(region.getId().equals(item.getId())) {
+                iterator.remove();
+                return;
+            }
+        }
+    }
+
+    private int replaceRegion(Page page, Region item) {
+        List<Region> regions = page.getRegions();
+        for(int i=0; i < regions.size(); i++) {
+            if(regions.get(i).getId().equals(item.getId())) {
+                regions.remove(i);
+                regions.add(i, item);
+                return i;
+            }
+        }
+        return 0;
+    }
+
+    private Page getPageFromRepository(Region item) {
+        if(item.getPage() != null && item.getPage().getId() != null) {
+            return template.get(item.getPage().getId());
+        }
+        else {
+            throw new IllegalStateException("Unable to find page for region");
+        }
+    }
+
+    private Page getPageByRegionId(String  id) {
+        return template.findOne(new Query(Criteria.where("regions").elemMatch(Criteria.where("_id").is(id))));
+    }
+
+
+    public MongoPageOperations getTemplate() {
+        return template;
+    }
+
+    public void setTemplate(MongoPageOperations template) {
+        this.template = template;
+    }
+
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbRegionWidgetRepository.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbRegionWidgetRepository.java
new file mode 100644
index 0000000..2d696c5
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbRegionWidgetRepository.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.rave.portal.model.Page;
+import org.apache.rave.portal.model.Region;
+import org.apache.rave.portal.model.RegionWidget;
+import org.apache.rave.portal.model.impl.RegionWidgetImpl;
+import org.apache.rave.portal.repository.MongoPageOperations;
+import org.apache.rave.portal.repository.RegionWidgetRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+
+@Repository
+public class MongoDbRegionWidgetRepository implements RegionWidgetRepository {
+
+    @Autowired
+    private MongoPageOperations template;
+
+    @Override
+    public Class<? extends RegionWidget> getType() {
+        return RegionWidgetImpl.class;
+    }
+
+    @Override
+    public RegionWidget get(String id) {
+        Page page = getPageByRegionWidgetId(id);
+        return getRegionWidgetById(page, id);
+    }
+
+    @Override
+    public RegionWidget save(RegionWidget item) {
+        return item.getId() == null ? addNewRegionWidget(item) : updateRegionWidget(item);
+    }
+
+    @Override
+    public void delete(RegionWidget item) {
+        Page page = getPageByRegionWidgetId(item.getId());
+        replaceOrRemoveWidget(page, item, false);
+        template.save(page);
+    }
+
+    private RegionWidget updateRegionWidget(RegionWidget item) {
+        RegionWidget savedWidget;
+        Page page = getPageByRegionWidgetId(item.getId());
+        replaceOrRemoveWidget(page, item, true);
+        Page saved = template.save(page);
+        savedWidget = getRegionWidgetById(saved, item.getId());
+        return savedWidget;
+    }
+
+    private RegionWidget addNewRegionWidget(RegionWidget item) {
+        Page page = getPageFromRepository(item);
+        Region parent = getRegionById(item.getRegion().getId(), page.getRegions());
+        if(parent == null) throw new IllegalStateException("Unable to find parent for page");
+        parent.getRegionWidgets().add(item);
+        Page saved = template.save(page);
+        return getRegionById(parent.getId(), saved.getRegions()).getRegionWidgets().get(parent.getRegionWidgets().size() -1);
+    }
+
+    private RegionWidget getRegionWidgetById(Page page, String id) {
+        for(Region region : page.getRegions()) {
+            for(RegionWidget widget : region.getRegionWidgets()) {
+                if(widget.getId().equals(id)) {
+                    return widget;
+                }
+            }
+        }
+        return null;
+    }
+
+    private int replaceOrRemoveWidget(Page page, RegionWidget item, boolean replace) {
+        for(Region region : page.getRegions()) {
+            List<RegionWidget> regionWidgets = region.getRegionWidgets();
+            for(int i=0; i< regionWidgets.size(); i++) {
+                if(regionWidgets.get(i).getId().equals(item.getId())) {
+                    regionWidgets.remove(i);
+                    if(replace) {
+                        regionWidgets.add(i, item);
+                    }
+                    return i;
+                }
+            }
+        }
+        throw new IllegalStateException("Widget does not exist in parent page regions");
+    }
+
+    private Region getRegionById(String id, List<Region> regions) {
+        for(Region region: regions) {
+            if(id.equals(region.getId())) {
+                return region;
+            }
+        }
+        return null;
+    }
+
+    private Page getPageFromRepository(RegionWidget item) {
+        if(item.getRegion() != null && item.getRegion().getPage() != null && item.getRegion().getPage().getId() != null) {
+            return template.get(item.getRegion().getPage().getId());
+        }
+        else {
+            throw new IllegalStateException("Unable to find page for region");
+        }
+    }
+
+    private Page getPageByRegionWidgetId(String id) {
+        return template.findOne(new Query(where("regions").elemMatch(where("regionWidgets").elemMatch(where("_id").is(id)))));
+    }
+
+    public void setTemplate(MongoPageOperations template) {
+        this.template = template;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbTagRepository.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbTagRepository.java
new file mode 100644
index 0000000..64fb4b7
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbTagRepository.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+
+import org.apache.rave.portal.model.Tag;
+import org.apache.rave.portal.model.impl.TagImpl;
+import org.apache.rave.portal.repository.MongoTagOperations;
+import org.apache.rave.portal.repository.TagRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+import static org.bson.types.ObjectId.massageToObjectId;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+@Repository
+public class MongoDbTagRepository implements TagRepository {
+
+    @Autowired
+    private MongoTagOperations template;
+
+    @Override
+    public List<Tag> getAll() {
+        return template.find(new Query());
+    }
+
+    @Override
+    public int getCountAll() {
+        return (int)template.count(new Query());
+    }
+
+    @Override
+    public Tag getByKeyword(String keyword) {
+        return template.findOne(query(where("keyword").is(keyword)));
+    }
+
+    @Override
+    public Class<? extends Tag> getType() {
+        return TagImpl.class;
+    }
+
+    @Override
+    public Tag get(String id) {
+        return template.get(id);
+    }
+
+    @Override
+    public Tag save(Tag item) {
+        return template.count(query(where("keyword").is(item.getKeyword()))) == 0 ? template.save(item) : item;
+    }
+
+    @Override
+    public void delete(Tag item) {
+        template.remove(query(where("_id").is(item.getId())));
+    }
+
+    public void setWidgetTemplate(MongoTagOperations tagTemplate) {
+        this.template = tagTemplate;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbUserRepository.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbUserRepository.java
new file mode 100644
index 0000000..4d5c157
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbUserRepository.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import com.google.common.collect.Lists;
+import org.apache.rave.portal.model.MongoDbUser;
+import org.apache.rave.portal.model.User;
+import org.apache.rave.portal.repository.MongoUserOperations;
+import org.apache.rave.portal.repository.StatisticsAggregator;
+import org.apache.rave.portal.repository.UserRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Order;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+
+/**
+ */
+@Repository
+public class MongoDbUserRepository implements UserRepository {
+
+    @Autowired
+    private MongoUserOperations template;
+
+    @Autowired
+    private StatisticsAggregator statisticsAggregator;
+
+    @Override
+    public User getByUsername(String username) {
+        return template.findOne(query(where("username").is(username)));
+    }
+
+    @Override
+    public User getByUserEmail(String userEmail) {
+        return template.findOne(query(where("email").is(userEmail)));
+    }
+
+    @Override
+    public User getByOpenId(String openId) {
+        return template.findOne(query(where("openId").is(openId)));
+    }
+
+    @Override
+    public List<User> getLimitedList(int offset, int pageSize) {
+        Query query = new Query().skip(offset).limit(pageSize);
+        return template.find(addSort(query));
+    }
+
+    @Override
+    public int getCountAll() {
+        return (int)template.count(new Query());
+    }
+
+    @Override
+    public List<User> findByUsernameOrEmail(String searchTerm, int offset, int pageSize) {
+        return template.find(addSort(getSearchQuery(searchTerm).skip(offset).limit(pageSize)));
+    }
+
+    @Override
+    public int getCountByUsernameOrEmail(String searchTerm) {
+        return (int)template.count(getSearchQuery(searchTerm));
+    }
+
+    @Override
+    public List<User> getAllByAddedWidget(String  widgetId) {
+        return getUsersById(statisticsAggregator.getUsersWithWidget(widgetId));
+    }
+
+    @Override
+    public User getByForgotPasswordHash(String hash) {
+        return template.findOne(query(where("forgotPasswordHash").is(hash)));
+    }
+
+    @Override
+    public Class<? extends User> getType() {
+        return MongoDbUser.class;
+    }
+
+    @Override
+    public User get(String  id) {
+        return template.get(id);
+    }
+
+    @Override
+    public User save(User item) {
+        return template.save(item);
+    }
+
+    @Override
+    public void delete(User item) {
+        template.remove(query(where("_id").is(item.getId())));
+    }
+
+    private List<User> getUsersById(Collection<String> userIds) {
+        List<User> users = Lists.newArrayList();
+        for(String userId : userIds) {
+            users.add(template.get(userId));
+        }
+        return users;
+    }
+
+    private Query getSearchQuery(String searchTerm) {
+        Pattern p = Pattern.compile(".*" + searchTerm  +".*", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
+        return query(new Criteria().orOperator(where("username").regex(p), where("email").regex(p)));
+    }
+
+    private Query addSort(Query query) {
+        query.sort().on("username", Order.ASCENDING);
+        return query;
+    }
+
+    public void setTemplate(MongoUserOperations template) {
+        this.template = template;
+    }
+
+    public void setStatisticsAggregator(StatisticsAggregator statisticsAggregator) {
+        this.statisticsAggregator = statisticsAggregator;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbWidgetRepository.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbWidgetRepository.java
new file mode 100644
index 0000000..0bd48fb
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoDbWidgetRepository.java
@@ -0,0 +1,523 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import com.google.common.collect.Maps;
+import org.apache.rave.exception.NotSupportedException;
+import org.apache.rave.portal.model.*;
+import org.apache.rave.portal.model.util.WidgetStatistics;
+import org.apache.rave.portal.repository.MongoTagOperations;
+import org.apache.rave.portal.repository.MongoWidgetOperations;
+import org.apache.rave.portal.repository.StatisticsAggregator;
+import org.apache.rave.portal.repository.WidgetRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Order;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import static org.bson.types.ObjectId.massageToObjectId;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+import static org.springframework.data.mongodb.core.query.Update.update;
+
+
+/**
+ */
+@Repository
+public class MongoDbWidgetRepository implements WidgetRepository {
+
+    @Autowired
+    private MongoWidgetOperations template;
+
+    @Autowired
+    private MongoTagOperations tagTemplate;
+
+    @Autowired
+    private StatisticsAggregator statsAggregator;
+
+    @Override
+    public List<Widget> getAll() {
+        return template.find(addSort(new Query()));
+    }
+
+    @Override
+    public List<Widget> getLimitedList(int offset, int pageSize) {
+        return template.find(addSort(new Query().skip(offset).limit(pageSize)));
+    }
+
+    @Override
+    public int getCountAll() {
+        return (int) template.count(new Query());
+    }
+
+    @Override
+    public List<Widget> getByFreeTextSearch(String searchTerm, int offset, int pageSize) {
+        Query query = new Query(addFreeTextClause(searchTerm, new Criteria())).skip(offset).limit(pageSize);
+        return template.find(addSort(query));
+    }
+
+    @Override
+    public int getCountFreeTextSearch(String searchTerm) {
+        return (int) template.count(new Query(addFreeTextClause(searchTerm, new Criteria())));
+    }
+
+    @Override
+    public List<Widget> getByStatus(WidgetStatus widgetStatus, int offset, int pageSize) {
+        Query query = new Query(where("widgetStatus").is(getWidgetStatusString(widgetStatus))).skip(offset).limit(pageSize);
+        return template.find(addSort(query));
+    }
+
+    @Override
+    public int getCountByStatus(WidgetStatus widgetStatus) {
+        return (int) template.count(new Query(where("widgetStatus").is(getWidgetStatusString(widgetStatus))));
+    }
+
+    @Override
+    public List<Widget> getByStatusAndTypeAndFreeTextSearch(WidgetStatus widgetStatus, String type, String searchTerm, int offset, int pageSize) {
+        Query query = getWidgetStatusFreeTextQuery(widgetStatus, type, searchTerm).limit(pageSize).skip(offset);
+        return template.find(addSort(query));
+    }
+
+    @Override
+    public int getCountByStatusAndTypeAndFreeText(WidgetStatus widgetStatus, String type, String searchTerm) {
+        return (int) template.count(getWidgetStatusFreeTextQuery(widgetStatus, type, searchTerm));
+    }
+
+    @Override
+    public List<Widget> getByOwner(User owner, int offset, int pageSize) {
+        Query query = getQueryByOwner(owner).skip(offset).limit(pageSize);
+        return template.find(addSort(query));
+    }
+
+    @Override
+    public int getCountByOwner(User owner, int offset, int pageSize) {
+        return (int) template.count(getQueryByOwner(owner));
+    }
+
+    @Override
+    public Widget getByUrl(String widgetUrl) {
+        return template.findOne(new Query(where("url").is(widgetUrl)));
+    }
+
+    @Override
+    public WidgetStatistics getWidgetStatistics(String widget_id, String user_id) {
+        return statsAggregator.getWidgetStatistics(widget_id, user_id);
+    }
+
+    @Override
+    public Map<String, WidgetStatistics> getAllWidgetStatistics(String userId) {
+        return statsAggregator.getAllWidgetStatistics(userId);
+    }
+
+    @Override
+    public Map<String, WidgetRating> getUsersWidgetRatings(String userId) {
+        Query q = query(where("ratings").elemMatch(where("userId").is(userId)));
+        List<Widget> widgets = template.find(q);
+        Map<String, WidgetRating> ratings = Maps.newHashMap();
+        for (Widget widget : widgets) {
+            for (WidgetRating rating : widget.getRatings()) {
+                if (rating.getUserId().equals(userId)) {
+                    ratings.put(widget.getId(), rating);
+                    break;
+                }
+            }
+        }
+        return ratings;
+    }
+
+    @Override
+    public List<Widget> getWidgetsByTag(String tagKeyWord, int offset, int pageSize) {
+        return template.find(addSort(getTagQuery(tagKeyWord).limit(pageSize).skip(offset)));
+    }
+
+    @Override
+    public int getCountByTag(String tagKeyword) {
+        return (int) template.count(getTagQuery(tagKeyword));
+    }
+
+    @Override
+    public int unassignWidgetOwner(String userId) {
+        Query query = query(where("ownerId").is(userId));
+        return template.update(query, update("ownerId", null));
+    }
+
+    @Override
+    public Class<? extends Widget> getType() {
+        return MongoDbWidget.class;
+    }
+
+    @Override
+    public Widget get(String id) {
+        return template.get(id);
+    }
+
+    @Override
+    public Widget save(Widget item) {
+        return template.save(item);
+    }
+
+    @Override
+    public void delete(Widget item) {
+        template.remove(new Query(where("_id").is(item.getId())));
+    }
+
+    /*
+     * Begin WidgetRatingRepository Methods
+     *
+     */
+    @Override
+    public WidgetRating getWidgetRatingsByWidgetIdAndUserId(String widgetId, String userId) {
+        Widget widget = template.get(widgetId);
+        return getRatingByUserId(widget, userId);
+    }
+
+    @Override
+    public int deleteAllWidgetRatings(String userId) {
+        int count = 0;
+        List<Widget> widgets = template.find(query(where("ratings").elemMatch(where("userId").is(userId))));
+        for (Widget widget : widgets) {
+            count += removeUserRatings(userId, widget);
+        }
+        return count;
+    }
+
+    @Override
+    public WidgetRating getRatingById(String widgetId, String id) {
+        Widget widget = template.get(widgetId);
+        return getWidgetRatingById(widget, id);
+    }
+
+    @Override
+    public WidgetRating createWidgetRating(String widgetId, WidgetRating rating) {
+        Widget widget = template.get(widgetId);
+        widget.getRatings().add(rating);
+        save(widget);
+        return rating;
+    }
+
+    @Override
+    public WidgetRating updateWidgetRating(String widgetId, WidgetRating rating) {
+        Widget widget = template.get(widgetId);
+        WidgetRating updated = updateRating(widget, rating);
+        save(widget);
+        return updated;
+    }
+
+    @Override
+    public void deleteWidgetRating(String widgetId, WidgetRating item) {
+        Widget widget = template.get(widgetId);
+        removeRating(item.getId(), widget);
+        template.save(widget);
+    }
+
+    private WidgetRating updateRating(Widget widget, WidgetRating rating) {
+        for(WidgetRating currentRating : widget.getRatings()) {
+            if(currentRating.getId().equals(rating.getId())) {
+                currentRating.setScore(rating.getScore());
+                currentRating.setUserId(rating.getUserId());
+                return currentRating;
+            }
+        }
+        return null;
+    }
+
+    private void removeRating(String ratingId, Widget widget) {
+        Iterator<WidgetRating> iterator = widget.getRatings().iterator();
+        while (iterator.hasNext()) {
+            WidgetRating comment = iterator.next();
+            if (comment.getId().equals(ratingId)) {
+                iterator.remove();
+                return;
+            }
+        }
+    }
+
+    private WidgetRating getWidgetRatingById(Widget widget, String id) {
+        for (WidgetRating rating : widget.getRatings()) {
+            if (rating.getId().equals(id)) {
+                return rating;
+            }
+        }
+        return null;
+    }
+
+    private int removeUserRatings(String userId, Widget widget) {
+        int count = 0;
+        Iterator<WidgetRating> iterator = widget.getRatings().iterator();
+        while (iterator.hasNext()) {
+            WidgetRating rating = iterator.next();
+            if (rating.getUserId().equals(userId)) {
+                iterator.remove();
+                count++;
+            }
+        }
+        if (count > 0) {
+            template.save(widget);
+        }
+        return count;
+    }
+
+    private WidgetRating getRatingByUserId(Widget widget, String userId) {
+        for (WidgetRating rating : widget.getRatings()) {
+            if (rating.getUserId().equals(userId)) {
+                return rating;
+            }
+        }
+        return null;
+    }
+
+    /*
+     * End WidgetRating Repository Methods
+     */
+
+    /*
+     * Begin WidgetTagRepository Methods
+     */
+    @Override
+    public WidgetTag getTagByWidgetIdAndKeyword(String widgetId, String keyword) {
+        Widget widget = template.get(widgetId);
+        return getTagByKeyword(keyword, widget);
+    }
+
+    @Override
+    public WidgetTag getTagById(String id) {
+        throw new NotSupportedException("Widget tags are not stored by ID");
+    }
+
+    @Override
+    public WidgetTag saveWidgetTag(String widgetId, WidgetTag item) {
+        Widget widget = template.get(widgetId);
+        updateOrAddTag(widget, item);
+        Widget saved = template.save(widget);
+        return getWidgetTagByTagId(saved, item.getTagId());
+    }
+
+    @Override
+    public void deleteWidgetTag(WidgetTag item) {
+        List<Widget> widgets = template.find(query(where("tags").elemMatch(where("tagId").is(item.getTagId()).and("userId").is(item.getUserId()).and("createdDate").is(item.getCreatedDate()))));
+        if(widgets.size() > 1 || widgets.size() == 0) {
+            throw new IllegalArgumentException("Unable to delete tag.  Indistinguishable from a tag on another widget or the tag doesn't exist");
+        } else {
+            Widget widget = widgets.get(0);
+            removeTag(item.getTagId(), widget);
+            save(widget);
+        }
+    }
+
+    private void updateOrAddTag(Widget widget, WidgetTag item) {
+        //Tags can only be created once.  No reason to update the tag if it has already been made.
+        WidgetTag tag = getWidgetTagByTagId(widget, item.getTagId());
+        if (tag == null) {
+            widget.getTags().add(item);
+        }
+    }
+
+    private void removeTag(String id, Widget widget) {
+        Iterator<WidgetTag> iterator = widget.getTags().iterator();
+        while (iterator.hasNext()) {
+            WidgetTag widgetTag = iterator.next();
+            if (widgetTag.getTagId().equals(id)) {
+                iterator.remove();
+                return;
+            }
+        }
+    }
+
+    private WidgetTag getTagByKeyword(String keyword, Widget widget) {
+        Tag tag = getTag(keyword);
+        return tag == null ? null : getWidgetTagByTagId(widget, tag.getId());
+    }
+
+    private Tag getTag(String keyword) {
+        return tagTemplate.findOne(query(where("keyword").is(keyword)));
+    }
+
+    private WidgetTag getWidgetTagByTagId(Widget widget, String tagId) {
+        for (WidgetTag widgetTag : widget.getTags()) {
+            if (widgetTag.getTagId().equals(tagId)) {
+                return widgetTag;
+            }
+        }
+        return null;
+    }
+
+    /*
+     * End WidgetTag Repository Methods
+     */
+
+    /*
+     * WidgetComment Repository
+     */
+    @Override
+    public WidgetComment getCommentById(String widgetId, String id) {
+        return getCommentById(template.get(widgetId), id);
+    }
+
+    @Override
+    public WidgetComment createWidgetComment(String widgetId, WidgetComment comment) {
+        Widget widget = template.get(widgetId);
+        widget.getComments().add(comment);
+        widget = save(widget);
+        return findCommentByProperties(widget, comment);
+    }
+
+    @Override
+    public WidgetComment updateWidgetComment(String widgetId, WidgetComment comment) {
+        Widget widget = template.get(widgetId);
+        updateComment(widget, comment);
+        return getCommentById(save(widget), comment.getId());
+    }
+
+    @Override
+    public void deleteWidgetComment(String widgetId, WidgetComment comment) {
+        Widget widget = template.get(widgetId);
+        removeComment(comment.getId(), widget);
+        template.save(widget);
+    }
+
+    @Override
+    public int deleteAllWidgetComments(String userId) {
+        int count = 0;
+        List<Widget> widgets = template.find(query(where("comments").elemMatch(where("userId").is(userId))));
+        for (Widget widget : widgets) {
+            count += updateWidget(userId, widget);
+        }
+        return count;
+    }
+
+    private void removeComment(String commentId, Widget widget) {
+        Iterator<WidgetComment> iterator = widget.getComments().iterator();
+        while (iterator.hasNext()) {
+            WidgetComment comment = iterator.next();
+            if (comment.getId().equals(commentId)) {
+                iterator.remove();
+                return;
+            }
+        }
+    }
+
+    private int updateWidget(String userId, Widget widget) {
+        int count = 0;
+
+        Iterator<WidgetComment> iterator = widget.getComments().iterator();
+        while (iterator.hasNext()) {
+            WidgetComment comment = iterator.next();
+            if (comment.getUserId().equals(userId)) {
+                iterator.remove();
+                count++;
+            }
+        }
+        if (count > 0) {
+            template.save(widget);
+        }
+        return count;
+    }
+
+    private WidgetComment getCommentById(Widget widget, String id) {
+        if (widget != null) {
+            for (WidgetComment comment : widget.getComments()) {
+                if (comment.getId().equals(id)) {
+                    return comment;
+                }
+            }
+        }
+        return null;
+    }
+
+    private WidgetComment updateComment(Widget widget, WidgetComment item) {
+        for (WidgetComment comment : widget.getComments()) {
+            if (comment.getId().equals(item.getId())) {
+                comment.setLastModifiedDate(new Date());
+                comment.setText(item.getText());
+                comment.setUserId(item.getUserId());
+                return comment;
+            }
+        }
+        return null;
+    }
+
+    /*
+     * End WidgetComment Repository
+     */
+    private Query getWidgetStatusFreeTextQuery(WidgetStatus widgetStatus, String type, String searchTerm) {
+        Criteria criteria = addFreeTextClause(searchTerm, new Criteria());
+        if (type != null && !type.isEmpty()) {
+            criteria.and("type").is(type);
+        }
+        if (widgetStatus != null) {
+            criteria.and("widgetStatus").is(getWidgetStatusString(widgetStatus));
+        }
+        return query(criteria);
+    }
+
+    private Criteria addFreeTextClause(String searchTerm, Criteria criteria) {
+        Pattern p = Pattern.compile(".*" + searchTerm + ".*", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
+        criteria.orOperator(where("title").regex(p), (where("description").regex(p)));
+        return criteria;
+    }
+
+    private Query getQueryByOwner(User owner) {
+        return query(where("ownerId").is(owner.getId()));
+    }
+
+    private Query getTagQuery(String tagKeyWord) {
+        Tag tag = getTag(tagKeyWord);
+        return query(where("tags").elemMatch(where("tagId").is(tag.getId())));
+    }
+
+    private String getWidgetStatusString(WidgetStatus widgetStatus) {
+        return widgetStatus.getWidgetStatus().toUpperCase();
+    }
+
+    private Query addSort(Query query) {
+        query.sort().on("featured", Order.DESCENDING).on("title", Order.ASCENDING);
+        return query;
+    }
+
+    private WidgetComment findCommentByProperties(Widget widget, WidgetComment comment) {
+        for(WidgetComment c : widget.getComments()) {
+            if(c.getUserId().equals(comment.getUserId()) &&
+                    c.getText().equals(comment.getText()) &&
+                    c.getCreatedDate().equals(comment.getCreatedDate())) {
+                return c;
+            }
+        }
+        return null;
+    }
+
+    public void setTemplate(MongoWidgetOperations template) {
+        this.template = template;
+    }
+
+    public void setStatsAggregator(StatisticsAggregator statsAggregator) {
+        this.statsAggregator = statsAggregator;
+    }
+
+    public void setTagTemplate(MongoTagOperations tagTemplate) {
+        this.tagTemplate = tagTemplate;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoModelTemplate.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoModelTemplate.java
new file mode 100644
index 0000000..d6dcf15
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoModelTemplate.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import com.mongodb.WriteResult;
+import org.apache.rave.portal.model.conversion.HydratingConverterFactory;
+import org.apache.rave.portal.repository.MongoModelOperations;
+import org.apache.rave.util.CollectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.mapreduce.MapReduceResults;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.core.query.Update;
+
+import java.util.List;
+
+/**
+ */
+public class MongoModelTemplate<T, E extends T> implements MongoModelOperations<T> {
+
+    private static final Logger logger = LoggerFactory.getLogger(MongoModelTemplate.class);
+
+    @Autowired
+    protected MongoOperations mongoTemplate;
+
+    @Autowired
+    protected HydratingConverterFactory converter;
+    
+    protected final Class<T> type;
+    protected final Class<E> dbType;
+    protected final String collection;
+    
+    public MongoModelTemplate(Class<T> type, Class<E> dbType, String collection) {
+        this.type = type;
+        this.dbType = dbType;
+        this.collection = collection;
+    } 
+
+    @Override
+    public long count(Query query) {
+        return mongoTemplate.count(query, collection);
+    }
+
+    @Override
+    public void remove(Query query) {
+        mongoTemplate.remove(query, collection);
+    }
+
+    @Override
+    public T get(String id) {
+        E fromDb = mongoTemplate.findById(id, dbType, collection);
+        if(fromDb == null) {
+            logger.warn(String.format("Could not find requested %2$s instance: %1$s", id, dbType));
+        }
+        return hydrate(fromDb);
+    }
+
+    @Override
+    public T save(T item) {
+        E converted = converter.convert(item, type);
+        mongoTemplate.save(converted, collection);
+        converter.hydrate(converted, type);
+        return converted;
+    }
+
+    @Override
+    public T findOne(Query query) {
+        return hydrate(mongoTemplate.findOne(query, dbType, collection));
+    }
+
+    @Override
+    public List<T> find(Query query) {
+        return hydrate(mongoTemplate.find(query, dbType, collection));
+    }
+
+    @Override
+    public int update(Query query, Update update) {
+        WriteResult result = mongoTemplate.updateMulti(query, update, collection);
+        return result.getN();
+    }
+
+    @Override
+    public <E> MapReduceResults<E> mapReduce(String mapFunction, String reduceFunction, Class<E> entityClass) {
+        return mongoTemplate.mapReduce(collection, mapFunction, reduceFunction, entityClass);
+    }
+
+    @Override
+    public <E> MapReduceResults<E> mapReduce(Query query, String mapFunction, String reduceFunction, Class<E> entityClass) {
+        return mongoTemplate.mapReduce(query, collection, mapFunction, reduceFunction, entityClass);
+    }
+
+    private List<T> hydrate(List<E> mongoDbTs) {
+        for(E p : mongoDbTs) {
+            hydrate(p);
+        }
+        return CollectionUtils.<T>toBaseTypedList(mongoDbTs);
+    }
+
+    private T hydrate(E page) {
+        converter.hydrate(page, type);
+        return page;
+    }
+
+    public void setMongoTemplate(MongoOperations mongoTemplate) {
+        this.mongoTemplate = mongoTemplate;
+    }
+
+    public void setConverter(HydratingConverterFactory converter) {
+        this.converter = converter;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoPageTemplate.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoPageTemplate.java
new file mode 100644
index 0000000..a3ebc4f
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoPageTemplate.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.rave.portal.model.MongoDbPage;
+import org.apache.rave.portal.model.Page;
+import org.apache.rave.portal.repository.MongoPageOperations;
+import org.springframework.stereotype.Component;
+
+import static org.apache.rave.portal.repository.util.CollectionNames.PAGE_COLLECTION;
+
+/**
+ */
+@Component
+public class MongoPageTemplate extends MongoModelTemplate<Page, MongoDbPage> implements MongoPageOperations {
+
+    public MongoPageTemplate() {
+        super(Page.class, MongoDbPage.class, PAGE_COLLECTION);
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoTagTemplate.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoTagTemplate.java
new file mode 100644
index 0000000..a58dabb
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoTagTemplate.java
@@ -0,0 +1,18 @@
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.rave.portal.model.Tag;
+import org.apache.rave.portal.model.impl.TagImpl;
+import org.apache.rave.portal.repository.MongoTagOperations;
+import org.springframework.stereotype.Component;
+
+import static org.apache.rave.portal.repository.util.CollectionNames.TAG_COLLECTION;
+
+/**
+ *
+ */
+@Component
+public class MongoTagTemplate extends MongoModelTemplate<Tag, TagImpl> implements MongoTagOperations {
+    public MongoTagTemplate() {
+        super(Tag.class, TagImpl.class, TAG_COLLECTION);
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoUserTemplate.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoUserTemplate.java
new file mode 100644
index 0000000..5147844
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoUserTemplate.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.rave.portal.model.MongoDbUser;
+import org.apache.rave.portal.model.User;
+import org.apache.rave.portal.repository.MongoUserOperations;
+import org.springframework.stereotype.Component;
+import static org.apache.rave.portal.repository.util.CollectionNames.USER_COLLECTION;
+
+@Component
+public class MongoUserTemplate extends MongoModelTemplate<User, MongoDbUser> implements MongoUserOperations {
+
+    public MongoUserTemplate() {
+        super(User.class, MongoDbUser.class, USER_COLLECTION);
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoWidgetTemplate.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoWidgetTemplate.java
new file mode 100644
index 0000000..c34551d
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/impl/MongoWidgetTemplate.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.rave.portal.model.MongoDbWidget;
+import org.apache.rave.portal.model.Widget;
+import org.apache.rave.portal.repository.MongoWidgetOperations;
+import org.springframework.stereotype.Component;
+
+import static org.apache.rave.portal.repository.util.CollectionNames.WIDGET_COLLECTION;
+
+/**
+ */
+@Component
+public class MongoWidgetTemplate extends MongoModelTemplate<Widget, MongoDbWidget> implements MongoWidgetOperations {
+    
+    public MongoWidgetTemplate() {
+        super(Widget.class, MongoDbWidget.class, WIDGET_COLLECTION);
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/util/CollectionNames.java b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/util/CollectionNames.java
new file mode 100644
index 0000000..6c12f63
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/java/org/apache/rave/portal/repository/util/CollectionNames.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.util;
+
+public class CollectionNames {
+
+    private CollectionNames() {}
+
+    public static final String WIDGET_COLLECTION = "widget";
+    public static final String TAG_COLLECTION = "tag";
+    public static final String USER_COLLECTION = "person";
+    public static final String PERSON_COLLECTION = USER_COLLECTION;
+    public static final String PAGE_COLLECTION = "page";
+    public static final String PREFERENCE_COLLECTION = "portalPreference";
+    public static final String PAGE_TEMPLATE_COLLECTION = "pageTemplate";
+    public static final String APP_DATA_COLLECTION = "appData";
+    public static final String AUTHORITY_COLLECTION = "authority";
+    public static final String CATEGORY_COLLECTION = "category";
+    public static final String OAUTH_CONSUMER_COLLECTION = "oauthConsumerStore";
+    public static final String OAUTH_TOKEN_COLLECTION = "oauthTokenInfo";
+    public static final String PAGE_LAYOUT_COLLECTION = "pageLayout";
+    public static final String WIDGET_RATINGS = "rating_statistics";
+    public static final String WIDGET_USERS = "user_statistics";
+    public static final String OPERATIONS = "ops";
+}
diff --git a/rave-components/rave-mongodb/src/main/resources/org/apache/rave/WidgetRatingsMap.js b/rave-components/rave-mongodb/src/main/resources/org/apache/rave/WidgetRatingsMap.js
new file mode 100644
index 0000000..4bf03e3
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/resources/org/apache/rave/WidgetRatingsMap.js
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+function () {
+    if (this.ratings) {
+        var self = this;
+        this.ratings.forEach(function(rating){
+            var userMap = {};
+            userMap[rating.userId] = rating.score;
+            emit(self._id, {
+                like:rating.score == 10 ? 1 : 0,
+                dislike:rating.score == 0 ? 1 : 0,
+                userRatings:userMap
+            });
+        });
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/resources/org/apache/rave/WidgetRatingsReduce.js b/rave-components/rave-mongodb/src/main/resources/org/apache/rave/WidgetRatingsReduce.js
new file mode 100644
index 0000000..d2c1dcd
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/resources/org/apache/rave/WidgetRatingsReduce.js
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+function(key, values) {
+    var result = {
+            like : 0,
+            dislike : 0,
+            userRatings : {}
+    };
+    values.forEach(function(value) {
+        result.like += value.like;
+        result.dislike += value.dislike;
+        for(var userRating in value.userRatings) {
+            result.userRatings[userRating] = value.userRatings[userRating];
+        }
+    });
+    return result;
+
+}
diff --git a/rave-components/rave-mongodb/src/main/resources/org/apache/rave/WidgetUsersMap.js b/rave-components/rave-mongodb/src/main/resources/org/apache/rave/WidgetUsersMap.js
new file mode 100644
index 0000000..f8e6310
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/resources/org/apache/rave/WidgetUsersMap.js
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+function () {
+    var widgetMap = {};
+    var self = this;
+
+    var mapPage = function (page) {
+        if (page.regions) {
+            page.regions.forEach(function (region) {
+                if (region.regionWidgets) {
+                    region.regionWidgets.forEach(function (regionWidget) {
+                        if (!widgetMap[regionWidget.widgetId]) {
+                            widgetMap[regionWidget.widgetId] = true;
+                            var userMap = {};
+                            userMap[self.ownerId] = 1;
+                            emit(regionWidget.widgetId, userMap);
+                        }
+                    })
+                }
+            })
+        }
+    };
+
+    mapPage(this);
+    if (this.subPages) {
+        this.subPages.forEach(function (p) {
+            mapPage(p)
+        })
+    }
+}
diff --git a/rave-components/rave-mongodb/src/main/resources/org/apache/rave/WidgetUsersReduce.js b/rave-components/rave-mongodb/src/main/resources/org/apache/rave/WidgetUsersReduce.js
new file mode 100644
index 0000000..d0e605d
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/resources/org/apache/rave/WidgetUsersReduce.js
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+function (key, values) {
+    var result={};
+    values.forEach(function(item){
+        for(var i in item) {
+            result[i] = item[i];
+        }
+    });
+    return result;
+}
diff --git a/rave-components/rave-mongodb/src/main/resources/org/apache/rave/marshaller-applicationContext.xml b/rave-components/rave-mongodb/src/main/resources/org/apache/rave/marshaller-applicationContext.xml
new file mode 100644
index 0000000..9b4cadc
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/resources/org/apache/rave/marshaller-applicationContext.xml
@@ -0,0 +1,38 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~  or more contributor license agreements.  See the NOTICE file
+  ~  distributed with this work for additional information
+  ~  regarding copyright ownership.  The ASF licenses this file
+  ~  to you under the Apache License, Version 2.0 (the
+  ~  "License"); you may not use this file except in compliance
+  ~  with the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing,
+  ~  software distributed under the License is distributed on an
+  ~  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~  KIND, either express or implied.  See the License for the
+  ~  specific language governing permissions and limitations
+  ~  under the License.
+  -->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:oxm="http://www.springframework.org/schema/oxm"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+
+        http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd">
+
+
+    <oxm:jaxb2-marshaller id="xmlMarshaller">
+        <oxm:class-to-be-bound name="org.apache.rave.portal.model.MongoDbUser"/>
+        <oxm:class-to-be-bound name="org.apache.rave.portal.model.MongoDbPage"/>
+        <oxm:class-to-be-bound name="org.apache.rave.portal.model.impl.RegionImpl"/>
+        <oxm:class-to-be-bound name="org.apache.rave.portal.model.impl.RegionWidgetImpl"/>
+        <oxm:class-to-be-bound name="org.apache.rave.portal.model.impl.RegionWidgetPreferenceImpl"/>
+        <oxm:class-to-be-bound name="org.apache.rave.portal.model.MongoDbWidget"/>
+        <oxm:class-to-be-bound name="org.apache.rave.portal.web.model.RegionWidgetPreferenceListWrapper"/>
+    </oxm:jaxb2-marshaller>
+
+</beans>
\ No newline at end of file
diff --git a/rave-components/rave-mongodb/src/main/resources/org/apache/rave/persistence-applicationContext.xml b/rave-components/rave-mongodb/src/main/resources/org/apache/rave/persistence-applicationContext.xml
new file mode 100644
index 0000000..3069c2f
--- /dev/null
+++ b/rave-components/rave-mongodb/src/main/resources/org/apache/rave/persistence-applicationContext.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~  or more contributor license agreements.  See the NOTICE file
+  ~  distributed with this work for additional information
+  ~  regarding copyright ownership.  The ASF licenses this file
+  ~  to you under the Apache License, Version 2.0 (the
+  ~  "License"); you may not use this file except in compliance
+  ~  with the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing,
+  ~  software distributed under the License is distributed on an
+  ~  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~  KIND, either express or implied.  See the License for the
+  ~  specific language governing permissions and limitations
+  ~  under the License.
+  -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:tx="http://www.springframework.org/schema/tx"
+       xmlns:p="http://www.springframework.org/schema/p"
+       xmlns:aop="http://www.springframework.org/schema/aop"
+       xmlns:mongo="http://www.springframework.org/schema/data/mongo"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                           http://www.springframework.org/schema/beans/spring-beans.xsd
+        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
+        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd">
+
+    <mongo:db-factory id="mongoFactory"
+                      host="${mongo.host}"
+                      port="${mongo.port}"
+                      dbname="${mongo.database}"
+                      username="${mongo.username}"
+                      password="${mongo.password}"/>
+
+    <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
+        <constructor-arg name="mongoDbFactory" ref="mongoFactory"/>
+    </bean>
+
+</beans>
\ No newline at end of file
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbAuthorityTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbAuthorityTest.java
new file mode 100644
index 0000000..728e81a
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbAuthorityTest.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model;
+
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * User: DSULLIVAN
+ * Date: 12/10/12
+ * Time: 10:42 AM
+ */
+public class MongoDbAuthorityTest {
+    @Test
+    public void testAuthority(){
+        Authority auth = new MongoDbAuthority();
+        String id = "123";
+        ((MongoDbAuthority)auth).setId(id);
+        assertThat(((MongoDbAuthority) auth).getId(), is(equalTo(id)));
+    }
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbCategoryTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbCategoryTest.java
new file mode 100644
index 0000000..4776415
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbCategoryTest.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model;
+
+import org.apache.rave.portal.repository.MongoWidgetOperations;
+import org.apache.rave.portal.repository.UserRepository;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.assertThat;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+/**
+ * User: DSULLIVAN
+ * Date: 12/10/12
+ * Time: 12:03 PM
+ */
+public class MongoDbCategoryTest {
+    public static final String ID_1 = "123";
+    public static final String ID_2 = "321";
+    private MongoDbCategory category;
+    private UserRepository userRepository;
+    private MongoWidgetOperations widgetOperations;
+
+    @Before
+    public void setup() {
+        category = new MongoDbCategory();
+        userRepository = createMock(UserRepository.class);
+        widgetOperations = createMock(MongoWidgetOperations.class);
+        category.setWidgetRepository(widgetOperations);
+    }
+
+    @Test
+    public void testCategory() {
+
+        String lastModifiedUserId = ID_1;
+        String createdUserId = ID_2;
+        category.setLastModifiedUserId(lastModifiedUserId);
+        category.setCreatedUserId(createdUserId);
+
+        assertThat(category.getLastModifiedUserId(), is(equalTo(ID_1)));
+        assertThat(category.getCreatedUserId(), is(equalTo(ID_2)));
+        assertThat(category.getWidgetRepository(), is(sameInstance(widgetOperations)));
+    }
+
+    @Test
+    public void getWidgets_Widgets_Null() {
+        List<Widget> widgets = new ArrayList<Widget>();
+        expect(widgetOperations.find(query(where("categoryIds").is(category.getId())))).andReturn(widgets);
+        replay(widgetOperations);
+
+        assertThat(category.getWidgets(), is(sameInstance(widgets)));
+    }
+
+    @Test
+    public void getWidgets_Widgets_Set() {
+        List<Widget> widgets = new ArrayList<Widget>();
+        category.setWidgets(widgets);
+
+        assertThat(category.getWidgets(), is(sameInstance(widgets)));
+    }
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbPageLayoutTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbPageLayoutTest.java
new file mode 100644
index 0000000..f6c2f08
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbPageLayoutTest.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * User: DSULLIVAN
+ * Date: 12/10/12
+ * Time: 12:39 PM
+ */
+public class MongoDbPageLayoutTest {
+    private MongoDbPageLayout pageLayout;
+    private String id;
+
+    @Before
+    public void setup(){
+        pageLayout = new MongoDbPageLayout();
+        id = "123";
+        pageLayout.setId(id);
+    }
+
+    @Test
+    public void equals_Same(){
+          assertTrue(pageLayout.equals(pageLayout));
+    }
+
+    @Test
+    public void equals_Diff_Instance(){
+        Object o = new Object();
+        assertFalse(pageLayout.equals(o));
+    }
+
+    @Test
+    public void equals_Super(){
+        PageLayout p = new MongoDbPageLayout();
+        p.setCode("code");
+        assertFalse(pageLayout.equals(p));
+    }
+
+    @Test
+    public void equals_Null_Id(){
+        MongoDbPageLayout p_1 = new MongoDbPageLayout();
+        MongoDbPageLayout p_2 = new MongoDbPageLayout();
+        p_1.setId("321");
+        assertFalse(p_1.equals(p_2));
+        assertFalse(p_2.equals(p_1));
+    }
+
+    @Test
+    public void equals_Both_Null(){
+        pageLayout.setId(null);
+        MongoDbPageLayout p = new MongoDbPageLayout();
+        assertTrue(pageLayout.equals(p));
+    }
+
+    @Test
+    public void equals_Same_Id(){
+        MongoDbPageLayout p_1 = new MongoDbPageLayout();
+        MongoDbPageLayout p_2 = new MongoDbPageLayout();
+        p_1.setId("321");
+        p_2.setId("321");
+        assertTrue(p_1.equals(p_2));
+    }
+
+    @Test
+    public void hashCode_Valid(){
+        assertNotNull(pageLayout.hashCode());
+    }
+
+    @Test
+    public void hashCode_Id_Null(){
+        pageLayout.setId(null);
+        assertNotNull(pageLayout.hashCode());
+    }
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbPageTemplateTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbPageTemplateTest.java
new file mode 100644
index 0000000..f8cbfec
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbPageTemplateTest.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model;
+
+import org.apache.rave.portal.model.impl.PageLayoutImpl;
+import org.apache.rave.portal.repository.PageLayoutRepository;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.junit.Assert.assertThat;
+
+/**
+ * User: DSULLIVAN
+ * Date: 12/10/12
+ * Time: 2:46 PM
+ */
+public class MongoDbPageTemplateTest {
+    private MongoDbPageTemplate template;
+    private PageLayoutRepository pageLayoutRepository;
+
+    @Before
+    public void setup(){
+        template = new MongoDbPageTemplate();
+        pageLayoutRepository = createMock(PageLayoutRepository.class);
+        template.setPageLayoutRepository(pageLayoutRepository);
+    }
+
+    @Test
+    public void getPageLayout(){
+        PageLayout p = new PageLayoutImpl();
+         template.setPageLayoutCode("stinky");
+        expect(pageLayoutRepository.getByPageLayoutCode("stinky")).andReturn(p);
+        replay(pageLayoutRepository);
+
+        assertThat(template.getPageLayout(), is(sameInstance(p)));
+    }
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbPersonAssociationTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbPersonAssociationTest.java
new file mode 100644
index 0000000..68d2df2
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbPersonAssociationTest.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model;
+
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * User: DSULLIVAN
+ * Date: 12/10/12
+ * Time: 1:37 PM
+ */
+public class MongoDbPersonAssociationTest {
+
+    @Test
+    public void testPersonAssociation(){
+
+        MongoDbPersonAssociation personAssociation = new MongoDbPersonAssociation();
+        personAssociation.setRequestStatus(FriendRequestStatus.ACCEPTED);
+        personAssociation.setPersonId("46765");
+
+        assertThat(personAssociation.getRequestStatus(), is(equalTo(FriendRequestStatus.ACCEPTED)));
+        assertThat(personAssociation.getPersonId(), is(equalTo("46765")));
+
+    }
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbPortalPreferenceTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbPortalPreferenceTest.java
new file mode 100644
index 0000000..b6ca3d4
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbPortalPreferenceTest.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model;
+
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * User: DSULLIVAN
+ * Date: 12/10/12
+ * Time: 3:37 PM
+ */
+public class MongoDbPortalPreferenceTest {
+    @Test
+    public void testPortalPreference(){
+        MongoDbPortalPreference pp = new MongoDbPortalPreference();
+        String id = "123";
+        pp.setId(id);
+
+        assertThat(pp.getId(), is(equalTo(id)));
+    }
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbUserTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbUserTest.java
new file mode 100644
index 0000000..76ddc5e
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbUserTest.java
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model;
+
+import org.apache.rave.portal.model.impl.AuthorityImpl;
+import org.apache.rave.portal.model.impl.PageLayoutImpl;
+import org.apache.rave.portal.repository.PageLayoutRepository;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.security.core.GrantedAuthority;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.junit.Assert.*;
+
+/**
+ * User: DSULLIVAN
+ * Date: 12/10/12
+ * Time: 1:49 PM
+ */
+public class MongoDbUserTest {
+
+    private MongoDbUser user;
+    private PageLayoutRepository pageLayoutRepository;
+
+    @Before
+    public void setup(){
+        user = new MongoDbUser();
+        pageLayoutRepository = createMock(PageLayoutRepository.class);
+        user.setPageLayoutRepository(pageLayoutRepository);
+    }
+
+    @Test
+    public void setAuthorities_Null(){
+        ArrayList<String> array = new ArrayList<String>();
+        array.add("string");
+        user.setAuthorityCodes(array);
+           user.setAuthorities(null);
+        assertTrue(user.getAuthorityCodes().isEmpty());
+    }
+
+    @Test
+    public void setAuthorities_Valid(){
+        Authority auth = new AuthorityImpl();
+        auth.setAuthority("auth");
+        user.setAuthorities(Arrays.asList(auth));
+
+        assertNotNull(user.getAuthorityCodes());
+        assertThat(user.getAuthorityCodes().get(0), is(sameInstance(auth.getAuthority())));
+    }
+
+    @Test
+    public void equals_Same(){
+        assertTrue(user.equals(user));
+    }
+
+    @Test
+    public void equals_Not_Same_Instance(){
+        Object o = new Object();
+        assertFalse(user.equals(o));
+
+    }
+
+    @Test
+    public void equals_Null_Id(){
+        user.setId("123");
+        MongoDbUser r = new MongoDbUser();
+        assertFalse(user.equals(r));
+        assertFalse(r.equals(user));
+
+    }
+
+    @Test
+    public void equals_Valid(){
+        user.setId("123");
+        MongoDbUser r = new MongoDbUser();
+        r.setId("123");
+        assertTrue(user.equals(r));
+    }
+
+    @Test
+    public void equals_Same_Null(){
+        user.setId(null);
+        MongoDbUser r = new MongoDbUser();
+        assertTrue(user.equals(r));
+    }
+
+    @Test
+    public void hashCode_Valid(){
+        user.setId("123");
+        assertNotNull(user.hashCode());
+    }
+
+    @Test
+    public void hashCode_Null(){
+        assertNotNull(user.hashCode());
+    }
+
+    @Test
+    public void getAuthorities_Valid(){
+        ArrayList<String> array = new ArrayList<String>();
+        array.add("string");
+        user.setAuthorityCodes(array);
+
+        Collection<GrantedAuthority> granted = user.getAuthorities();
+
+        assertTrue(granted.size() == 1);
+    }
+
+    @Test
+    public void addAuthority_Valid(){
+        Authority authority = new AuthorityImpl();
+        authority.setAuthority("auth");
+        user.addAuthority(authority);
+        assertTrue(user.getAuthorityCodes().contains(authority.getAuthority()));
+    }
+
+    @Test
+    public void addAuthority_Contains(){
+        Authority authority = new AuthorityImpl();
+        authority.setAuthority("auth");
+        List<String> authorityCodes = Arrays.asList(authority.getAuthority());
+        user.setAuthorityCodes(authorityCodes);
+        user.addAuthority(authority);
+    }
+
+    @Test
+    public void removeAuthority_Valid(){
+        Authority auth = new AuthorityImpl();
+        auth.setAuthority("stinky");
+        user.setAuthorityCodes(new ArrayList<String>());
+        user.getAuthorityCodes().add("stinky");
+
+        user.removeAuthority(auth);
+
+        assertFalse(user.getAuthorityCodes().contains("stinky"));
+    }
+
+    @Test
+    public void removeAuthority_NotContain(){
+        Authority auth = new AuthorityImpl();
+        user.removeAuthority(auth);
+        assertNotNull(user.getAuthorityCodes());
+    }
+
+    @Test
+    public void getDefaultPageLayout_Valid(){
+        PageLayout layout = new PageLayoutImpl();
+        user.setDefaultPageLayoutCode("dingus");
+        expect(pageLayoutRepository.getByPageLayoutCode("dingus")).andReturn(layout);
+        replay(pageLayoutRepository);
+
+        assertThat(user.getDefaultPageLayout(), is(sameInstance(layout)));
+    }
+
+    @Test
+    public void getDefaultPageLayout_Null(){
+        PageLayout layout = new PageLayoutImpl();
+        user.setDefaultPageLayout(layout);
+        assertThat(layout, is(sameInstance(user.getDefaultPageLayout())));
+    }
+
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbWidgetTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbWidgetTest.java
new file mode 100644
index 0000000..c144ea3
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/MongoDbWidgetTest.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model;
+
+import org.apache.rave.portal.model.impl.CategoryImpl;
+import org.apache.rave.portal.repository.CategoryRepository;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.junit.Assert.*;
+
+/**
+ * User: DSULLIVAN
+ * Date: 12/10/12
+ * Time: 1:49 PM
+ */
+public class MongoDbWidgetTest {
+
+    public static final String ID_1 = "123";
+    public static final String ID_2 = "321";
+    private MongoDbWidget widget;
+    private CategoryRepository categoryRepository;
+
+    @Before
+    public void setup(){
+        widget = new MongoDbWidget();
+        categoryRepository = createMock(CategoryRepository.class);
+        widget.setCategoryRepository(categoryRepository);
+    }
+
+    @Test
+    public void getCategories_Valid(){
+        List<String> categoryIds = Arrays.asList(ID_1, ID_2);
+        expect(categoryRepository.get(ID_1)).andReturn(null);
+        Category category = new CategoryImpl();
+        expect(categoryRepository.get(ID_2)).andReturn(category);
+        replay(categoryRepository);
+        widget.setCategoryIds(categoryIds);
+        List<Category> result = widget.getCategories();
+        assertNotNull(result);
+        assertTrue(result.contains(category));
+    }
+
+    @Test
+    public void getCategories_Null(){
+        List<Category> categoryList = new ArrayList<Category>();
+        widget.setCategories(categoryList);
+        assertNotNull(widget.getCategories());
+    }
+
+    @Test
+    public void getCategories_Null_Categories_Full(){
+        List<Category> categoryList = new ArrayList<Category>();
+        categoryList.add(new CategoryImpl());
+        widget.setCategories(categoryList);
+        assertThat(categoryList, is(sameInstance(widget.getCategories())));
+    }
+
+    @Test
+    public void equals_Same(){
+        assertTrue(widget.equals(widget));
+    }
+
+    @Test
+    public void equals_Not_Same_Instance(){
+        Object o = new Object();
+        assertFalse(widget.equals(o));
+
+    }
+
+    @Test
+    public void equals_Null_Id(){
+        widget.setId(ID_1);
+        Widget r = new MongoDbWidget();
+        assertFalse(widget.equals(r));
+        assertFalse(r.equals(widget));
+
+    }
+
+    @Test
+    public void equals_Valid(){
+        widget.setId(ID_1);
+        Widget r = new MongoDbWidget();
+        ((MongoDbWidget)r).setId(ID_1);
+        assertTrue(widget.equals(r));
+    }
+
+    @Test
+    public void equals_Null(){
+        widget.setId(null);
+        Widget r = new MongoDbWidget();
+        ((MongoDbWidget)r).setId(null);
+        assertTrue(widget.equals(r));
+    }
+
+    @Test
+    public void hashCode_Valid(){
+        assertNotNull(widget.hashCode());
+    }
+
+    @Test
+    public void hashCode_Null(){
+        widget.setId(ID_1);
+        assertNotNull(widget.hashCode());
+    }
+
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongDbConverterTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongDbConverterTest.java
new file mode 100644
index 0000000..0331671
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongDbConverterTest.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model.conversion.impl;
+
+import org.apache.rave.model.ModelConverter;
+import org.apache.rave.portal.model.conversion.HydratingModelConverter;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.junit.Assert.assertThat;
+
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: dsullivan
+ * Date: 11/16/12
+ * Time: 4:01 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class MongDbConverterTest {
+    private MongoDbConverter converter;
+    private ModelConverter mock1;
+    private ModelConverter mock2;
+    private List<HydratingModelConverter> converterList;
+
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
+    @Before
+    public void setup(){
+        converter = new MongoDbConverter();
+        mock1 = createMock(HydratingModelConverter.class);
+        mock2 = createMock(HydratingModelConverter.class);
+        converterList = Arrays.asList(
+                (HydratingModelConverter)mock1,
+                (HydratingModelConverter)mock2
+        );
+
+        expect(mock1.getSourceType()).andReturn(String.class);
+        expect(mock2.getSourceType()).andReturn(Integer.class);
+    }
+
+    @Test
+    public void hydrate_Valid(){
+        String source = "blah";
+        Class<String> clazz = String.class;
+        ((HydratingModelConverter)mock1).hydrate(source);
+        expectLastCall();
+        replay(mock1);
+        converter.setConverters(converterList);
+
+        converter.hydrate(source, clazz);
+        verify(mock1);
+
+
+    }
+
+    @Test
+    public void hydrate_Null(){
+        converter.setConverters(converterList);
+        long exceptionSource = 432;
+        Class<Long> exceptionClass = Long.class;
+
+        thrown.expect(IllegalArgumentException.class);
+        thrown.expectMessage("No ModelConverter found for type "+exceptionClass);
+
+        converter.hydrate(exceptionSource, exceptionClass);
+
+    }
+
+    @Test
+    public void convert_Valid(){
+        String source = "blah";
+        Class<String> clazz = String.class;
+        long returned = 123;
+
+        expect(mock1.convert(source)).andReturn(returned);
+        replay(mock1);
+        converter.setConverters(converterList);
+
+        assertThat(converter.<String, Long>convert(source, clazz),is(sameInstance(returned)));
+    }
+
+    @Test
+    public void convert_Exception(){
+        long exceptionSource = 432;
+        Class<Long> exceptionClass = Long.class;
+
+        converter.setConverters(converterList);
+
+        thrown.expect(IllegalArgumentException.class);
+        thrown.expectMessage("No ModelConverter found for type "+exceptionClass);
+
+        converter.convert(exceptionSource, exceptionClass);
+    }
+
+    @Test
+    public void getConverter_Valid(){
+        replay(mock1,mock2);
+        converter.setConverters(converterList);
+        assertThat(converter.getConverter(String.class), is(sameInstance(mock1)));
+        assertThat(converter.getConverter(Integer.class), is(sameInstance(mock2)));
+    }
+
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongoDbAuthorityConverterTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongoDbAuthorityConverterTest.java
new file mode 100644
index 0000000..a160f46
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongoDbAuthorityConverterTest.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model.conversion.impl;
+
+import org.apache.rave.portal.model.Authority;
+import org.apache.rave.portal.model.MongoDbAuthority;
+import org.apache.rave.portal.model.impl.AuthorityImpl;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+
+/**
+ * A test for the MongoDbAuthorityCoverter.java
+ * To change this template use File | Settings | File Templates.
+ */
+public class MongoDbAuthorityConverterTest {
+    private MongoDbAuthorityConverter authorityConverter;
+
+    @Before
+    public void setup(){
+        authorityConverter = new MongoDbAuthorityConverter();
+    }
+
+    @Test
+    public void hydrate_Valid(){
+        MongoDbAuthority authority = new MongoDbAuthority();
+        authorityConverter.hydrate(authority);
+        assertNotNull(authority);
+    }
+
+    @Test
+    public void convert_Valid(){
+        Authority authority = new AuthorityImpl();
+        authority.setAuthority("asd;lkfjlkj");
+        authority.setDefaultForNewUser(true);
+
+        MongoDbAuthority converted = authorityConverter.convert(authority);
+        assertNotNull(converted.getAuthority());
+        //assertNotNull(converted.getId());
+        assertThat(converted.getAuthority(), is(sameInstance(authority.getAuthority())));
+        assertThat(converted.isDefaultForNewUser(), is(sameInstance(authority.isDefaultForNewUser())));
+
+        Authority authorityMongo = new MongoDbAuthority();
+        authorityMongo.setAuthority("authority");
+        authorityMongo.setDefaultForNewUser(true);
+        MongoDbAuthority mongoConverted = authorityConverter.convert(authorityMongo);
+        assertThat(mongoConverted, is(sameInstance(authorityMongo)));
+        assertThat(mongoConverted.getAuthority(), is(sameInstance(authorityMongo.getAuthority())));
+        assertThat(mongoConverted.isDefaultForNewUser(), is(sameInstance(authorityMongo.isDefaultForNewUser())));
+    }
+
+    @Test
+    public void getSourceType_Valid(){
+        assertNotNull(authorityConverter.getSourceType());
+    }
+
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongoDbCategoryConverterTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongoDbCategoryConverterTest.java
new file mode 100644
index 0000000..bdb311f
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongoDbCategoryConverterTest.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model.conversion.impl;
+
+import com.google.common.collect.Lists;
+import org.apache.rave.portal.model.Category;
+import org.apache.rave.portal.model.MongoDbCategory;
+import org.apache.rave.portal.model.Widget;
+import org.apache.rave.portal.model.impl.CategoryImpl;
+import org.apache.rave.portal.repository.MongoWidgetOperations;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Date;
+
+import static org.easymock.EasyMock.createNiceMock;
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+
+/**
+ * This is a test class for MongoDb Category Converter
+ */
+public class MongoDbCategoryConverterTest {
+
+    public static final String  USER1ID = "1234";
+    public static final String USER2ID = "1333";
+    public static final Date DATE1 = new Date();
+    public static final Date DATE2 = new Date();
+    private MongoDbCategoryConverter converter;
+    private MongoWidgetOperations mongoWidgetOperations;
+
+
+    @Before
+    public void setup(){
+        converter = new MongoDbCategoryConverter();
+        mongoWidgetOperations = createNiceMock(MongoWidgetOperations.class);
+        converter.setMongoWidgetOperations(mongoWidgetOperations);
+    }
+
+
+    @Test
+    public void hydrate_valid(){
+        MongoDbCategory category = new MongoDbCategory();
+
+        converter.hydrate(category);
+
+        assertThat(category.getWidgetRepository(),is(sameInstance(mongoWidgetOperations)));
+
+    }
+
+    @Test
+    public void hydrate_null(){
+        converter.hydrate(null);
+        assertThat(true, is(true));
+    }
+
+
+    @Test
+    public void convert_valid(){
+        Category c = new CategoryImpl();
+        c.setCreatedDate(DATE1);
+        c.setCreatedUserId(USER1ID);
+        c.setId(USER1ID);
+        c.setLastModifiedUserId(USER2ID);
+        c.setText("asdf");
+        c.setWidgets(Lists.<Widget>newArrayList());
+        c.setLastModifiedDate(DATE2);
+
+        MongoDbCategory mongoC = converter.convert(c);
+        assertThat(mongoC.getCreatedDate(), is(equalTo(DATE1)));
+        assertThat(mongoC.getCreatedUserId(), is(equalTo(USER1ID)));
+        assertThat(mongoC.getId(), is(equalTo(USER1ID)));
+        assertThat(mongoC.getLastModifiedUserId(), is(equalTo(USER2ID)));
+        assertThat(mongoC.getWidgetRepository(), is(nullValue()));
+        assertThat(mongoC.getText(), is("asdf"));
+        assertThat(c.getWidgets().size(), is(0));
+
+    }//end convert_valid
+
+    @Test
+    public void convert_Null(){
+        Category source = new CategoryImpl();
+
+        MongoDbCategory converted = converter.convert(source);
+
+        assertNull(converted.getLastModifiedUserId());
+        assertNull(converted.getCreatedUserId());
+        assertNotNull(converted.getId());
+    }
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongoDbPageConverterTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongoDbPageConverterTest.java
new file mode 100644
index 0000000..2c08460
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongoDbPageConverterTest.java
@@ -0,0 +1,303 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model.conversion.impl;
+
+import com.google.common.collect.Lists;
+import org.apache.rave.portal.model.*;
+import org.apache.rave.portal.model.impl.*;
+import org.apache.rave.portal.repository.PageLayoutRepository;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+
+/**
+ * Test class for MongoDb Page Converter
+ */
+public class MongoDbPageConverterTest {
+
+    private PageLayoutRepository pageLayoutRepository;
+
+    private MongoDbPageConverter converter;
+    public static final String USER1ID = "1234";
+    public static final String USER2ID = "1222";
+    public static final String PAGEID = "1234";
+
+    @Before
+    public void setup() {
+        converter = new MongoDbPageConverter();
+        pageLayoutRepository = createNiceMock(PageLayoutRepository.class);
+        converter.setPageLayoutRepository(pageLayoutRepository);
+
+    }
+
+    @Test
+    public void convertPage_valid() {
+
+        MongoDbPage results;
+        PageUser pageUser = new PageUserImpl(USER1ID);
+        Page sourcePage = new PageImpl();
+        pageUser.setUserId(USER2ID);
+
+        List<PageUser> pageMembers = Lists.newArrayList();
+        pageMembers.add(pageUser);
+        sourcePage.setMembers(pageMembers);
+
+        Region region = new RegionImpl();
+        region.setRegionWidgets(Lists.<RegionWidget>newLinkedList());
+        RegionWidgetImpl rw = new RegionWidgetImpl();
+        rw.setId("2222");
+        rw.setWidgetId("3333");
+        rw.setPreferences(Lists.<RegionWidgetPreference>newLinkedList());
+
+        region.getRegionWidgets().add(rw);
+        sourcePage.setRegions(Lists.<Region>newLinkedList());
+        sourcePage.getRegions().add(region);
+
+        Page parentPage = new PageImpl();
+        PageLayout pagelayout = new PageLayoutImpl();
+        pagelayout.setCode("asdf");
+
+        sourcePage.setId(PAGEID);
+        sourcePage.setOwnerId(USER2ID);
+        sourcePage.setPageLayout(pagelayout);
+        sourcePage.setName("Carol");
+        sourcePage.setParentPage(parentPage);
+        sourcePage.setPageType(PageType.USER);
+
+        results = converter.convert(sourcePage);
+
+        assertThat(results.getName(), is(equalTo("Carol")));
+        assertThat(results.getPageType(), is(PageType.USER));
+        assertThat(results.getRegions().size(), is(1));
+        assertNotNull(results.getRegions().get(0).getId());
+        assertNull(results.getRegions().get(0).getPage());
+        assertThat(results.getPageLayout(), is(nullValue(PageLayout.class)));
+        assertThat(results.getParentPage(), is(nullValue()));
+        assertThat(results.getMembers().size(), is(1));
+        assertThat(results.getRegions().get(0).getRegionWidgets().get(0), is(instanceOf(RegionWidgetImpl.class)));
+        assertNotNull(results.getRegions().get(0).getRegionWidgets().get(0).getId());
+        assertNull(results.getRegions().get(0).getRegionWidgets().get(0).getRegion());
+        assertThat(results.getRegions().get(0).getRegionWidgets().get(0).getPreferences(), is(equalTo(sourcePage.getRegions().get(0).getRegionWidgets().get(0).getPreferences())));
+
+    }//end convert page test
+
+    @Test
+    public void convertPage_Id_Null(){
+        Page sourcePage = new MongoDbPage();
+        RegionImpl region = new RegionImpl();
+        region.setId("123");
+        sourcePage.setRegions(Arrays.<Region>asList(region));
+        sourcePage.setPageLayout(new PageLayoutImpl());
+        sourcePage.setOwnerId(USER1ID);
+        sourcePage.setMembers(new ArrayList<PageUser>());
+
+
+        Page subPage = new MongoDbPage();
+        List<Page> subPages = Arrays.asList(subPage);
+        subPage.setPageLayout(new PageLayoutImpl());
+        subPage.setOwnerId(USER1ID);
+        subPage.setId("321");
+        subPage.setMembers(new ArrayList<PageUser>());
+        subPage.setRegions(new ArrayList<Region>());
+        sourcePage.setSubPages(subPages);
+
+
+        MongoDbPage converted = converter.convert(sourcePage);
+
+        assertTrue(converted.getSubPages().get(0).getId().equals(sourcePage.getSubPages().get(0).getId()));
+        assertTrue(converted.getRegions().get(0).equals(region));
+
+    }
+
+
+    //Convert user test
+    @Test
+    public void convertUser_valid() {
+
+        PageUserImpl mongoUser;
+        PageUser sourceUser = new PageUserImpl(USER1ID);
+        sourceUser.setUserId(USER2ID);
+        sourceUser.setEditor(true);
+        sourceUser.setPageStatus(PageInvitationStatus.OWNER);
+        sourceUser.setRenderSequence(1234L);
+
+        mongoUser = converter.convert(sourceUser);
+        assertThat(mongoUser.getId(), is(equalTo(USER1ID)));
+        assertThat(mongoUser.getUserId(), is(equalTo(USER2ID)));
+        assertTrue(mongoUser.isEditor());
+        assertThat(mongoUser.getPageStatus(), is(PageInvitationStatus.OWNER));
+        assertThat(mongoUser.getRenderSequence(), is(equalTo(1234L)));
+        assertThat(mongoUser.getPage(), is(nullValue()));
+
+    }//end convertUser_valid
+
+    @Test
+    public void convertUser_MongoInstance(){
+        PageUser sourceUser = new PageUserImpl();
+        sourceUser.setUserId("1234");
+
+        PageUserImpl converted = converter.convert(sourceUser);
+        assertNotNull(converted.getId());
+    }
+
+    //Convert Widget test
+    @Test
+    public void convertWidget_valid() {
+
+        RegionWidgetImpl rw = new RegionWidgetImpl();
+        RegionWidgetImpl rwResults;
+
+        rw.setPreferences(Lists.<RegionWidgetPreference>newLinkedList());
+        RegionWidgetPreference preference = new RegionWidgetPreferenceImpl();
+        preference.setName("name");
+        preference.setValue("value");
+        rw.setWidgetId("1234L");
+        rw.getPreferences().add(preference);
+        rw.setLocked(false);
+        rw.setCollapsed(false);
+        rw.setHideChrome(false);
+        rw.setRenderPosition("test");
+        rw.setRenderOrder(1);
+
+        rwResults = converter.convert(rw);
+
+        assertThat(rwResults.getWidgetId(), is(equalTo("1234L")));
+        assertNotNull(rwResults.getId());
+        assertThat(rwResults.getPreferences().get(0), is(equalTo(preference)));
+        assertThat(rwResults.isCollapsed(), is(false));
+        assertThat(rwResults.isHideChrome(), is(false));
+        assertThat(rwResults.isLocked(), is(false));
+        assertThat(rwResults.getRenderPosition(), is(equalTo("test")));
+        assertThat(rwResults.getRenderOrder(), is(1));
+        assertThat(rwResults.getRegion(), is(nullValue()));
+
+    }//end convertRegion_valid
+
+    @Test
+    public void convertWidget_NullPreferences(){
+        RegionWidgetImpl rw = new RegionWidgetImpl();
+        RegionWidgetImpl rwResults;
+
+        rw.setWidgetId("1234L");
+        rw.setLocked(false);
+        rw.setCollapsed(false);
+        rw.setHideChrome(false);
+        rw.setRenderPosition("test");
+        rw.setRenderOrder(1);
+
+        rwResults = converter.convert(rw);
+
+        assertThat(rwResults.getWidgetId(), is(equalTo("1234L")));
+        assertNotNull(rwResults.getId());
+        assertNotNull(rwResults.getPreferences());
+        assertThat(rwResults.isCollapsed(), is(false));
+        assertThat(rwResults.isHideChrome(), is(false));
+        assertThat(rwResults.isLocked(), is(false));
+        assertThat(rwResults.getRenderPosition(), is(equalTo("test")));
+        assertThat(rwResults.getRenderOrder(), is(1));
+        assertThat(rwResults.getRegion(), is(nullValue()));
+    }
+
+    @Test
+    public void hydratePage_valid() {
+
+        MongoDbPage page = new MongoDbPage();
+        page.setRegions(Lists.<Region>newLinkedList());
+        Region region1 = new RegionImpl();
+        Region region2 = new RegionImpl();
+
+        region1.setRegionWidgets(Lists.<RegionWidget>newLinkedList());
+        region2.setRegionWidgets(Lists.<RegionWidget>newLinkedList());
+        RegionWidget rw1 = new RegionWidgetImpl();
+        region1.getRegionWidgets().add(rw1);
+
+        RegionWidget rw2 = new RegionWidgetImpl();
+        region2.getRegionWidgets().add(rw2);
+
+        page.getRegions().add(region1);
+        page.getRegions().add(region2);
+
+        page.setMembers(Lists.<PageUser>newLinkedList());
+        PageUserImpl member1 = new PageUserImpl();
+        PageUser member2 = new PageUserImpl();
+        page.getMembers().add(member1);
+        page.getMembers().add(member2);
+
+        Region subRegion = new RegionImpl();
+        subRegion.setRegionWidgets(Lists.<RegionWidget>newLinkedList());
+        RegionWidget subRegionWidget = new RegionWidgetImpl();
+        subRegion.getRegionWidgets().add(subRegionWidget);
+
+        page.setSubPages(Lists.<Page>newLinkedList());
+        MongoDbPage subPage1 = new MongoDbPage();
+        PageUserImpl subMember = new PageUserImpl();
+        subPage1.setMembers(Lists.<PageUser>newLinkedList());
+        subPage1.setRegions(Lists.<Region>newLinkedList());
+        subPage1.getMembers().add(subMember);
+        subPage1.getRegions().add(subRegion);
+        Page subPage2 = new PageImpl();
+        subPage2.setMembers(Lists.<PageUser>newLinkedList());
+        subPage2.setRegions(Lists.<Region>newLinkedList());
+        page.getSubPages().add(subPage1);
+        page.getSubPages().add(subPage2);
+
+        PageLayout pageLayout = new PageLayoutImpl();
+        pageLayout.setCode("asdf");
+
+        expect(pageLayoutRepository.getByPageLayoutCode(page.getPageLayoutCode())).andReturn(pageLayout);
+        replay(pageLayoutRepository);
+
+        converter.hydrate(page);
+        assertThat(page.getPageLayout(), is(sameInstance(pageLayout)));
+        assertThat(page.getMembers().get(0), is(instanceOf(PageUserImpl.class)));
+        assertThat((MongoDbPage)region1.getPage(), is(sameInstance(page)));
+        assertThat((MongoDbPage)subPage1.getParentPage(), is(sameInstance(page)));
+        assertThat((MongoDbPage)subPage2.getParentPage(), is(sameInstance(page)));
+        assertThat(page.getRegions().get(0).getRegionWidgets().get(0), is(sameInstance(rw1)));
+
+    }//end hydratePage_valid
+
+    @Test
+    public void hydrateWidgetRegion_valid() {
+
+        RegionWidgetImpl rw = new RegionWidgetImpl();
+        Region region = new RegionImpl();
+
+        converter.hydrate(rw, region);
+        assertThat(rw.getRegion(), is(sameInstance(region)));
+
+    }
+
+    @Test
+    public void hydratePage_null() {
+        MongoDbPage page = null;
+        converter.hydrate(page);
+
+        assertThat(true, is(true));
+    }
+
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongoDbPageTemplateConverterTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongoDbPageTemplateConverterTest.java
new file mode 100644
index 0000000..0fbbf2d
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongoDbPageTemplateConverterTest.java
@@ -0,0 +1,357 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model.conversion.impl;
+
+import org.apache.rave.portal.model.*;
+import org.apache.rave.portal.model.impl.*;
+import org.apache.rave.portal.repository.PageLayoutRepository;
+import org.apache.rave.portal.repository.WidgetRepository;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: dsullivan
+ * Date: 11/26/12
+ * Time: 10:01 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class MongoDbPageTemplateConverterTest {
+    private MongoDbPageTemplateConverter pageTemplateConverter;
+    private PageLayoutRepository pageLayoutRepository;
+    private WidgetRepository widgetRepository;
+
+    @Before
+    public void setup() {
+        pageLayoutRepository = createMock(PageLayoutRepository.class);
+        widgetRepository = createMock(WidgetRepository.class);
+        pageTemplateConverter = new MongoDbPageTemplateConverter();
+        pageTemplateConverter.setPageLayoutRepository(pageLayoutRepository);
+    }
+
+    @Test
+    public void getSourceType_Valid() {
+        assertThat(pageTemplateConverter.getSourceType(), equalTo(PageTemplate.class));
+    }
+
+    @Test
+    public void hydrate_Valid() {
+        MongoDbPageTemplate mongoDbPageTemplate = new MongoDbPageTemplate();
+        PageTemplateRegion ptRegion1 = new PageTemplateRegionImpl();
+        PageTemplateRegion ptRegion2 = new PageTemplateRegionImpl();
+        PageTemplateRegion ptRegion3 = new PageTemplateRegionImpl();
+        PageTemplateRegion ptRegion4 = new PageTemplateRegionImpl();
+        List<PageTemplateRegion> pageTemplateRegions1 = Arrays.asList(
+                ptRegion1,
+                ptRegion2
+        );
+        List<PageTemplateRegion> pageTemplateRegions2 = Arrays.asList(
+                ptRegion3
+        );
+        List<PageTemplateRegion> pageTemplateRegions3 = Arrays.asList(
+                ptRegion4
+        );
+        mongoDbPageTemplate.setPageTemplateRegions(pageTemplateRegions1);
+        PageTemplateWidget widget1 = new PageTemplateWidgetImpl();
+        PageTemplateWidget widget2 = new PageTemplateWidgetImpl();
+        PageTemplateWidget widget3 = new PageTemplateWidgetImpl();
+        PageTemplateWidget widget4 = new PageTemplateWidgetImpl();
+        PageTemplateWidget widget5 = new PageTemplateWidgetImpl();
+
+        PageTemplate template1 = new MongoDbPageTemplate();
+        PageTemplate template2 = new MongoDbPageTemplate();
+
+        List<PageTemplateWidget> pageTemplateWidgets1 = Arrays.asList(
+                widget1,
+                widget2
+        );
+        List<PageTemplateWidget> pageTemplateWidgets2 = Arrays.asList(
+                widget3
+        );
+        List<PageTemplateWidget> pageTemplateWidgets3 = Arrays.asList(
+                widget4
+        );
+        List<PageTemplateWidget> pageTemplateWidgets4 = Arrays.asList(
+                widget5
+        );
+        List<PageTemplate> pageTemplates = Arrays.asList(
+                template1,
+                template2
+        );
+        ptRegion1.setPageTemplateWidgets(pageTemplateWidgets1);
+        ptRegion2.setPageTemplateWidgets(pageTemplateWidgets2);
+        ptRegion3.setPageTemplateWidgets(pageTemplateWidgets3);
+        ptRegion4.setPageTemplateWidgets(pageTemplateWidgets4);
+        template1.setPageTemplateRegions(pageTemplateRegions2);
+        template2.setPageTemplateRegions(pageTemplateRegions3);
+        mongoDbPageTemplate.setSubPageTemplates(pageTemplates);
+
+        pageTemplateConverter.hydrate(mongoDbPageTemplate);
+
+        assertThat(mongoDbPageTemplate.getPageLayoutRepository(), is(sameInstance(pageLayoutRepository)));
+        assertThat((MongoDbPageTemplate) ptRegion1.getPageTemplate(), is(sameInstance(mongoDbPageTemplate)));
+        assertThat((MongoDbPageTemplate) ptRegion2.getPageTemplate(), is(sameInstance(mongoDbPageTemplate)));
+        assertThat(widget1.getPageTemplateRegion(), is(sameInstance(ptRegion1)));
+        assertThat(widget2.getPageTemplateRegion(), is(sameInstance(ptRegion1)));
+        assertThat(widget3.getPageTemplateRegion(), is(sameInstance(ptRegion2)));
+        assertThat(widget4.getPageTemplateRegion(), is(sameInstance(ptRegion3)));
+        assertThat(widget5.getPageTemplateRegion(), is(sameInstance(ptRegion4)));
+
+        assertThat((MongoDbPageTemplate) template1.getParentPageTemplate(), is(sameInstance(mongoDbPageTemplate)));
+        assertThat((MongoDbPageTemplate) template2.getParentPageTemplate(), is(sameInstance(mongoDbPageTemplate)));
+    }
+
+    @Test
+    public void hydrate_Null(){
+        pageTemplateConverter.hydrate(null);
+        assertThat(true, is(true));
+    }
+
+    @Test
+    public void convert_Not_InstanceOf(){
+        PageTemplate pageTemplate = new PageTemplateImpl();
+        pageTemplate.setPageLayout(new PageLayoutImpl());
+        MongoDbPageTemplate subPage = new MongoDbPageTemplate();
+        subPage.setPageLayout(new PageLayoutImpl());
+        ArrayList<PageTemplate> subPages = new ArrayList<PageTemplate>();
+        subPages.add(subPage);
+        pageTemplate.setSubPageTemplates(subPages);
+        PageTemplateRegion region = createNewPageTemplateRegion();
+        ArrayList<PageTemplateRegion> regions = new ArrayList<PageTemplateRegion>();
+        regions.add(region);
+        pageTemplate.setPageTemplateRegions(regions);
+
+        MongoDbPageTemplate converted = pageTemplateConverter.convert(pageTemplate);
+
+        assertNotNull(converted.getId());
+        assertNotNull(converted.getPageTemplateRegions());
+        assertNotNull(converted.getSubPageTemplates());
+    }
+
+    private PageTemplateRegion createNewPageTemplateRegion() {
+        return new PageTemplateRegion() {
+                @Override
+                public String getId() {
+                    return null;  //To change body of implemented methods use File | Settings | File Templates.
+                }
+
+                @Override
+                public long getRenderSequence() {
+                    return 0;  //To change body of implemented methods use File | Settings | File Templates.
+                }
+
+                @Override
+                public void setRenderSequence(long renderSequence) {
+                    //To change body of implemented methods use File | Settings | File Templates.
+                }
+
+                @Override
+                public PageTemplate getPageTemplate() {
+                    return null;  //To change body of implemented methods use File | Settings | File Templates.
+                }
+
+                @Override
+                public void setPageTemplate(PageTemplate pageTemplate) {
+                    //To change body of implemented methods use File | Settings | File Templates.
+                }
+
+                @Override
+                public List<PageTemplateWidget> getPageTemplateWidgets() {
+                    return null;  //To change body of implemented methods use File | Settings | File Templates.
+                }
+
+                @Override
+                public void setPageTemplateWidgets(List<PageTemplateWidget> pageTemplateWidgets) {
+                    //To change body of implemented methods use File | Settings | File Templates.
+                }
+
+                @Override
+                public boolean isLocked() {
+                    return false;  //To change body of implemented methods use File | Settings | File Templates.
+                }
+
+                @Override
+                public void setLocked(boolean locked) {
+                    //To change body of implemented methods use File | Settings | File Templates.
+                }
+            };
+    }
+
+    @Test
+    public void convert_PageTemplateWidgets_Null(){
+        PageTemplate pageTemplate = new PageTemplateImpl();
+        pageTemplate.setPageLayout(new PageLayoutImpl());
+        PageTemplateRegion pageTemplateRegion = new PageTemplateRegionImpl();
+        pageTemplate.setPageTemplateRegions(Arrays.asList(pageTemplateRegion));
+
+        MongoDbPageTemplate converted = pageTemplateConverter.convert(pageTemplate);
+
+        assertNotNull(converted.getId());
+    }
+
+    @Test
+    public void convert_Valid(){
+
+        PageTemplate mongoPageTemplate1 = new MongoDbPageTemplate();
+        PageTemplate mongoPageTemplate2 = new MongoDbPageTemplate();
+        PageLayoutRepository tempPageLayoutRepository = createMock(PageLayoutRepository.class);
+        WidgetRepository tempWidgetRepository = createMock(WidgetRepository.class);
+        ((MongoDbPageTemplate)mongoPageTemplate1).setPageLayoutRepository(tempPageLayoutRepository);
+        ((MongoDbPageTemplate)mongoPageTemplate2).setPageLayoutRepository(tempPageLayoutRepository);
+        PageTemplateRegion pageTemplateRegion = new PageTemplateRegionImpl();
+        PageTemplateWidget pageTemplateWidget = new PageTemplateWidgetImpl();
+
+        //the source PageTemplate tested in the first recursion
+        ((MongoDbPageTemplate)mongoPageTemplate1).setId("1234");
+        mongoPageTemplate1.setName("Blah");
+        mongoPageTemplate1.setDescription("Blahty Blahty Blah");
+        mongoPageTemplate1.setPageType(PageType.get("user"));
+        MongoDbPageLayout mongoDbPageLayout1 = new MongoDbPageLayout();
+        mongoDbPageLayout1.setId("7777");
+        mongoDbPageLayout1.setCode("4321");
+        mongoPageTemplate1.setPageLayout(mongoDbPageLayout1);
+        mongoPageTemplate1.setRenderSequence(9999);
+        mongoPageTemplate1.setDefaultTemplate(true);
+
+        //the PageTemplate to be inserted into the subPageTemplates array, tested in the second recursion loop
+        ((MongoDbPageTemplate)mongoPageTemplate2).setId("3232");
+        mongoPageTemplate2.setName("Yeah");
+        mongoPageTemplate2.setDescription("Yeah Yeah Ya");
+        mongoPageTemplate2.setPageType(PageType.get("user"));
+        MongoDbPageLayout mongoDbPageLayout2 = new MongoDbPageLayout();
+        mongoDbPageLayout2.setId("8888");
+        mongoDbPageLayout2.setCode("2345");
+        mongoPageTemplate2.setPageLayout(mongoDbPageLayout2);
+        mongoPageTemplate2.setRenderSequence(8787);
+        mongoPageTemplate2.setDefaultTemplate(true);
+
+        //the PageTemplateWidget to be add as a field to the pageTemplateWidgets array of the PageTemplateRegion
+        ((PageTemplateWidgetImpl)pageTemplateWidget).setId("3333");
+        pageTemplateWidget.setHideChrome(true);
+        pageTemplateWidget.setRenderSeq(3456);
+        Widget widget = new WidgetImpl();
+        ((WidgetImpl)widget).setId("87623876");
+        ((PageTemplateWidgetImpl)pageTemplateWidget).setWidgetId("4444");
+        pageTemplateWidget.setLocked(true);
+
+        //the PageTemplateRegion to be converted
+        ((PageTemplateRegionImpl)pageTemplateRegion).setId("2929");
+        pageTemplateRegion.setRenderSequence(56376);
+        pageTemplateRegion.setLocked(true);
+
+        //create and add subPageTemplate array to the first PageTemplate
+        List<PageTemplate> subPageTemplates = Arrays.asList(
+                (PageTemplate)mongoPageTemplate2
+        );
+        mongoPageTemplate1.setSubPageTemplates(subPageTemplates);
+
+        //create and add pageTemplateWidgets to the PageTemplateRegion
+        List<PageTemplateWidget> pageTemplateWidgets = Arrays.asList(
+              pageTemplateWidget
+        );
+         pageTemplateRegion.setPageTemplateWidgets(pageTemplateWidgets);
+
+        //create and add pageTemplateRegions to the first PageTemplate
+        List<PageTemplateRegion> pageTemplateRegions = Arrays.asList(
+            pageTemplateRegion
+        );
+        mongoPageTemplate1.setPageTemplateRegions(pageTemplateRegions);
+
+        expect(tempPageLayoutRepository.getByPageLayoutCode("4321")).andReturn(mongoDbPageLayout1);
+        expect(tempPageLayoutRepository.getByPageLayoutCode("2345")).andReturn(mongoDbPageLayout2);
+        expect(tempWidgetRepository.get("4444")).andReturn(widget);
+        replay(tempPageLayoutRepository, tempWidgetRepository);
+
+        MongoDbPageTemplate convertedTemplate = pageTemplateConverter.convert(mongoPageTemplate1);
+
+        //test convert made in first convert call
+        assertNotNull(convertedTemplate.getId());
+        assertThat(convertedTemplate.getName(), is(mongoPageTemplate1.getName()));
+        assertThat(convertedTemplate.getDescription(), is(mongoPageTemplate1.getDescription()));
+        assertThat(convertedTemplate.getPageType(), is(mongoPageTemplate1.getPageType()));
+        assertNull(convertedTemplate.getParentPageTemplate());
+        assertThat(convertedTemplate.getPageLayoutCode(), is(mongoPageTemplate1.getPageLayout().getCode()));
+        //assertNotNull(mongoDbPageTemplate2.getPageLayout());//This should be testing to see that the PageLayout is being properly set
+        assertThat(convertedTemplate.getRenderSequence(), is(mongoPageTemplate1.getRenderSequence()));
+        assertThat(convertedTemplate.isDefaultTemplate(), is(mongoPageTemplate1.isDefaultTemplate()));
+
+        //test converts made in second subPageTemplate loop
+        for(int i = 0; i< convertedTemplate.getSubPageTemplates().size(); i++){
+            PageTemplate source = mongoPageTemplate1.getSubPageTemplates().get(i);
+            PageTemplate converted = convertedTemplate.getSubPageTemplates().get(i);
+
+            assertNotNull(converted.getId());
+            assertThat(converted.getName(), is(source.getName()));
+            assertThat(converted.getDescription(), is(source.getDescription()));
+            assertThat(converted.getPageType(), is(source.getPageType()));
+            assertNull(converted.getParentPageTemplate());
+            assertThat(((MongoDbPageTemplate)converted).getPageLayoutCode(), is(source.getPageLayout().getCode()));
+            //assertNotNull(converted.getPageLayout());//This should be testing to see that the PageLayout is being properly set
+            assertThat(converted.getRenderSequence(), is(source.getRenderSequence()));
+            assertThat(converted.isDefaultTemplate(), is(source.isDefaultTemplate()));
+        }
+
+        //test converts made in the PageTemplateRegions loop
+        for(int i = 0; i< convertedTemplate.getPageTemplateRegions().size(); i++){
+            PageTemplateRegion source = mongoPageTemplate1.getPageTemplateRegions().get(i);
+            PageTemplateRegion converted = convertedTemplate.getPageTemplateRegions().get(i);
+
+            assertThat(converted.getId(), is(source.getId()));
+            assertThat(converted.getRenderSequence(), is(source.getRenderSequence()));
+            //assertNotNull(converted.getPageTemplate()); // this should test to make sure the PageTemplate was set
+            assertThat(converted.isLocked(), is(source.isLocked()));
+
+            //test converts made in the PageTemplateWidgets loop
+            for(int j = 0; j<converted.getPageTemplateWidgets().size(); j++){
+                PageTemplateWidget widgetSource = source.getPageTemplateWidgets().get(j);
+                PageTemplateWidget widgetConverted = converted.getPageTemplateWidgets().get(j);
+
+                assertThat(widgetConverted.getId(), is(widgetSource.getId()));
+                assertThat(widgetConverted.isHideChrome(), is(widgetSource.isHideChrome()));
+                assertThat(widgetConverted.getRenderSeq(), is(widgetSource.getRenderSeq()));
+                assertThat(((PageTemplateWidgetImpl)widgetConverted).getWidgetId(), is(((PageTemplateWidgetImpl)widgetSource).getWidgetId()));
+                //assertNotNull(widgetConverted.getWidget());//This should test to make sure the WidgetId is set
+                assertThat(widgetConverted.isLocked(), is(widgetSource.isLocked()));
+            }
+        }
+    }
+
+    @Test
+    public void convert_Valid_Null_WidgetID(){
+        PageTemplate source = new PageTemplateImpl();
+        PageTemplateRegion pageTemplateRegion = new PageTemplateRegionImpl();
+        source.setPageTemplateRegions(Arrays.asList(pageTemplateRegion));
+        PageTemplateWidget pageTemplateWidget = new PageTemplateWidgetImpl();
+        pageTemplateRegion.setPageTemplateWidgets(Arrays.asList(pageTemplateWidget));
+        source.setPageLayout(new PageLayoutImpl());
+
+        MongoDbPageTemplate converted = pageTemplateConverter.convert(source);
+        assertTrue(converted instanceof MongoDbPageTemplate);
+    }
+
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongoDbPortalPreferenceConverterTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongoDbPortalPreferenceConverterTest.java
new file mode 100644
index 0000000..434ccf3
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongoDbPortalPreferenceConverterTest.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model.conversion.impl;
+
+
+import com.google.common.collect.Lists;
+import org.apache.rave.portal.model.MongoDbPortalPreference;
+import org.apache.rave.portal.model.PortalPreference;
+import org.apache.rave.portal.model.impl.PortalPreferenceImpl;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.easymock.EasyMock.notNull;
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+
+/**
+ * Test class for MongoDb Portal Preference Converter
+ */
+
+public class MongoDbPortalPreferenceConverterTest {
+
+    private MongoDbPortalPreferenceConverter converter;
+
+    @Before
+    public void setUp(){
+
+        converter = new MongoDbPortalPreferenceConverter();
+    }
+
+    @Test
+    public void convertPreference_valid(){
+
+        PortalPreference pp = new PortalPreferenceImpl();
+        pp.setKey("key");
+        pp.setValues(Lists.<String>newLinkedList());
+        MongoDbPortalPreference converted;
+        MongoDbPortalPreference mpp = new MongoDbPortalPreference();
+        mpp.setKey("carol");
+        mpp.setValues(Lists.<String>newLinkedList());
+
+        converted = converter.convert(pp);
+
+        assertThat(converted.getKey(), is(equalTo("key")));
+        assertTrue(converted.getValues().isEmpty());
+        //assertNotNull(converted.getId());
+
+        converted = converter.convert(mpp);
+
+        assertThat(converted.getKey(), is(equalTo("carol")));
+        assertTrue(converted.getValues().isEmpty());
+        assertThat(converted, is(sameInstance(mpp)));
+        assertThat(converted.getId(), is(notNull()));
+
+    }
+
+    @Test
+    public void hydrate(){
+        MongoDbPortalPreference mpp = new MongoDbPortalPreference();
+        converter.hydrate(mpp);
+        assertNotNull(mpp);
+    }
+
+    @Test
+    public void getSourceType(){
+
+        assertThat(converter.getSourceType(), is(equalTo(PortalPreference.class)));
+    }
+
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongoDbUserConverterTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongoDbUserConverterTest.java
new file mode 100644
index 0000000..bd1119f
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongoDbUserConverterTest.java
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model.conversion.impl;
+
+import com.google.common.collect.Lists;
+import org.apache.rave.portal.model.*;
+import org.apache.rave.portal.model.impl.*;
+import org.apache.rave.portal.repository.PageLayoutRepository;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.security.core.GrantedAuthority;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: dsullivan
+ * Date: 11/28/12
+ * Time: 8:00 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class MongoDbUserConverterTest {
+    private MongoDbUserConverter userConverter;
+
+    @Before
+    public void setup() {
+        userConverter = new MongoDbUserConverter();
+        PageLayoutRepository pageLayoutRepository = createMock(PageLayoutRepository.class);
+        userConverter.setPageLayoutRepository(pageLayoutRepository);
+    }
+
+    @Test
+    public void getType_Valid(){
+        assertThat(userConverter.getSourceType(), is(equalTo(User.class)));
+    }
+
+    @Test
+    public void hydrate_Valid() {
+        MongoDbUser user = new MongoDbUser();
+        userConverter.hydrate(user);
+
+        assertNotNull(user.getFriends());
+        assertNotNull(user.getAuthorityCodes());
+        assertThat(user.getPageLayoutRepository(), is(sameInstance(userConverter.getPageLayoutRepository())));
+
+        userConverter.hydrate(null);
+        assertThat(true, is(true));
+    }
+
+    @Test
+    public void hydrate_Null(){
+        MongoDbUser user = new MongoDbUser();
+        user.setFriends(Lists.<MongoDbPersonAssociation>newArrayList());
+        user.setAuthorityCodes(Lists.<String>newArrayList());
+        userConverter.hydrate(user);
+
+        assertNotNull(user.getFriends());
+        assertNotNull(user.getAuthorityCodes());
+        assertThat(user.getPageLayoutRepository(), is(sameInstance(userConverter.getPageLayoutRepository())));
+    }
+
+    @Test
+    public void convert_Valid() {
+        User source = new MongoDbUser("1234");
+        PageLayoutRepository pageLayoutRepository = createMock(PageLayoutRepository.class);
+        ((MongoDbUser)source).setPageLayoutRepository(pageLayoutRepository);
+        expect(pageLayoutRepository.getByPageLayoutCode("User")).andReturn(new PageLayoutImpl());
+        //create dummy fields for source
+        Authority authority1 = new AuthorityImpl("Role1");
+        Authority authority2 = new AuthorityImpl("Role2");
+        Collection<Authority> authorities = Arrays.asList(
+                authority1,
+                authority2
+        );
+        source.setAuthorities(authorities);
+        source.setUsername("Stinky");
+        source.setEmail("stinky@mcdingus.com");
+        source.setDisplayName("Stinky McDingus");
+        source.setAdditionalName("Stinky-Marie");
+        source.setFamilyName("McDingus");
+        source.setGivenName("Stinkapotamus");
+        source.setHonorificPrefix("Sir");
+        source.setHonorificSuffix("Esquire");
+        source.setPreferredName("Stink");
+        source.setAboutMe("I live in the Himalayas");
+        source.setStatus("Cold up here");
+        source.setAddresses(Arrays.asList((Address) new AddressImpl("123 Mount Everest")));
+        source.setOrganizations(Arrays.asList(
+                (Organization) new OrganizationImpl(),
+                (Organization) new OrganizationImpl()
+        ));
+        source.setProperties(Arrays.asList(
+                (PersonProperty) new PersonPropertyImpl(),
+                (PersonProperty) new PersonPropertyImpl()
+        ));
+        source.setPassword("12345");
+        source.setConfirmPassword("54321");
+        source.setDefaultPageLayoutCode("PageLayout");
+        source.setEnabled(true);
+        source.setExpired(true);
+        source.setLocked(true);
+        source.setOpenId("9977");
+        source.setForgotPasswordHash("Forgotten Password");
+        source.setForgotPasswordTime(new Date());
+
+        MongoDbUser converted = userConverter.convert(source);
+
+        //Test for setting authorityCodes
+        Iterator sourceIter = source.getAuthorities().iterator();
+        Iterator convertedIter = converted.getAuthorities().iterator();
+        while (sourceIter.hasNext()) {
+            assertThat(
+                    ((GrantedAuthority)sourceIter.next()).getAuthority(),
+                    is(
+                            ((GrantedAuthority) convertedIter.next()).getAuthority()
+                    )
+            );
+        }
+
+        //Test for updateProperties
+        assertThat(converted.getId(), is(source.getId()));
+        assertThat(converted.getUsername(), is(source.getUsername()));
+        assertThat(converted.getEmail(), is(source.getEmail()));
+        assertThat(converted.getDisplayName(), is(source.getDisplayName()));
+        assertThat(converted.getAdditionalName(), is(source.getAdditionalName()));
+        assertThat(converted.getFamilyName(), is(source.getFamilyName()));
+        assertThat(converted.getGivenName(), is(source.getGivenName()));
+        assertThat(converted.getHonorificPrefix(), is(source.getHonorificPrefix()));
+        assertThat(converted.getHonorificSuffix(), is(source.getHonorificSuffix()));
+        assertThat(converted.getPreferredName(), is(source.getPreferredName()));
+        assertThat(converted.getAboutMe(), is(source.getAboutMe()));
+        assertThat(converted.getStatus(), is(source.getStatus()));
+        assertThat(converted.getStatus(), is(source.getStatus()));
+        for(int i = 0; i<converted.getAddresses().size(); i++){
+            assertThat(converted.getAddresses().get(i), is(sameInstance(source.getAddresses().get(i))));
+        }
+        for(int i = 0; i<converted.getOrganizations().size(); i++){
+            assertThat(converted.getOrganizations().get(i), is(sameInstance(source.getOrganizations().get(i))));
+        }
+        for(int i = 0; i<converted.getProperties().size(); i++){
+            assertThat(converted.getProperties().get(i), is(sameInstance(source.getProperties().get(i))));
+        }
+        assertThat(converted.getPassword(), is(source.getPassword()));
+        assertThat(converted.getConfirmPassword(), is(source.getConfirmPassword()));
+        //This method should test to ensure that the Default Page Layout has been set
+        //assertThat(converted.getDefaultPageLayout(), is(source.getDefaultPageLayout()));
+        assertThat(converted.isEnabled(), is(source.isEnabled()));
+        assertThat(converted.isExpired(), is(source.isExpired()));
+        assertThat(converted.isLocked(), is(source.isLocked()));
+        assertThat(converted.getOpenId(), is(source.getOpenId()));
+        assertThat(converted.getForgotPasswordHash(), is(source.getForgotPasswordHash()));
+        assertThat(converted.getForgotPasswordTime(), is(source.getForgotPasswordTime()));
+
+        //create UserImpl to test else block
+        source = new UserImpl();
+        PageLayout pageLayout = new PageLayoutImpl();
+        pageLayout.setCode("code");
+        source.setDefaultPageLayout(pageLayout);
+        converted = userConverter.convert(source);
+
+        //assertNotNull(converted.getId());
+        assertThat(converted.getDefaultPageLayoutCode(), is(pageLayout.getCode()));
+        assertNull(source.getDefaultPageLayout());
+
+    }
+
+    @Test
+    public void convert_Null_DefaultPageLayoutCode(){
+        User source = new UserImpl();
+
+        User converted = userConverter.convert(source);
+
+        assertNull(converted.getDefaultPageLayoutCode());
+    }
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongoDbWidgetConverterTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongoDbWidgetConverterTest.java
new file mode 100644
index 0000000..8381991
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/model/conversion/impl/MongoDbWidgetConverterTest.java
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.model.conversion.impl;
+
+import com.google.common.collect.Lists;
+import org.apache.rave.portal.model.*;
+import org.apache.rave.portal.model.impl.*;
+import org.apache.rave.portal.repository.CategoryRepository;
+import org.apache.rave.portal.repository.UserRepository;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Date;
+
+import static org.easymock.EasyMock.createNiceMock;
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+
+/**
+ * This is a test for the MongoDb Widget Converter
+ */
+public class MongoDbWidgetConverterTest {
+
+    private UserRepository userRepository;
+    private CategoryRepository categoryRepository;
+    private MongoDbWidgetConverter converter;
+    private static final String ID = "1234L";
+    public static final Date DATE = new Date();
+
+    @Before
+    public void setUp() {
+
+        userRepository = createNiceMock(UserRepository.class);
+        categoryRepository = createNiceMock(CategoryRepository.class);
+        converter = new MongoDbWidgetConverter();
+        converter.setCategoryRepository(categoryRepository);
+    }
+
+    @Test
+    public void hydrate_valid() {
+
+        MongoDbWidget dehydrated = new MongoDbWidget();
+
+        dehydrated.setComments(Lists.<WidgetComment>newLinkedList());
+        WidgetCommentImpl wc = new WidgetCommentImpl();
+        dehydrated.getComments().add(wc);
+
+        dehydrated.setTags(Lists.<WidgetTag>newLinkedList());
+        WidgetTagImpl wt = new WidgetTagImpl();
+        dehydrated.getTags().add(wt);
+
+        converter.hydrate(dehydrated);
+
+        assertThat(dehydrated.getCategoryRepository(), is(sameInstance(categoryRepository)));
+
+    }
+
+    @Test
+    public void hydrate_Tags_Null_Comments_Null() {
+        MongoDbWidget dehydrated = new MongoDbWidget();
+        converter.hydrate(dehydrated);
+        assertThat(dehydrated.getCategoryRepository(), is(sameInstance(categoryRepository)));
+    }
+
+    @Test
+    public void hydrate_null() {
+        converter.hydrate(null);
+        assertThat(true, is(true));
+    }
+
+    @Test
+    public void hydrate_NotMongoWidget_NotMongoComments() {
+        WidgetTag widgetTag = new WidgetTagImpl();
+        WidgetComment widgetComment = new WidgetCommentImpl();
+
+        MongoDbWidget widget = new MongoDbWidget();
+        widget.setComments(Arrays.asList(widgetComment));
+        widget.setTags(Arrays.asList(widgetTag));
+
+        converter.hydrate(widget);
+
+        assertTrue(widgetTag instanceof WidgetTagImpl);
+        assertTrue(widgetComment instanceof WidgetCommentImpl);
+    }
+
+    @Test
+    public void convert_widget() {
+
+        MongoDbWidget converted;
+        Widget source = new WidgetImpl(ID);
+        source.setOwnerId(ID);
+        source.setUrl("http://mitre.org");
+        source.setType("type");
+        source.setTitle("title");
+        source.setTitleUrl("http://title.org");
+        source.setThumbnailUrl("http://thumbnail.org");
+        source.setScreenshotUrl("http://screenshot.org");
+        source.setAuthor("author");
+        source.setAuthorEmail("authorEmail");
+        source.setDescription("description");
+        source.setWidgetStatus(WidgetStatus.PREVIEW);
+        source.setComments(Lists.<WidgetComment>newLinkedList());
+        source.setDisableRendering(true);
+        source.setFeatured(true);
+
+        source.setCategories(Lists.<Category>newLinkedList());
+        Category c = new CategoryImpl(ID);
+        source.getCategories().add(c);
+
+        source.setComments(Lists.<WidgetComment>newLinkedList());
+        WidgetComment wc = new WidgetCommentImpl(ID);
+        wc.setUserId(ID);
+        wc.setCreatedDate(DATE);
+        wc.setLastModifiedDate(DATE);
+        wc.setText("text");
+        source.getComments().add(wc);
+
+        source.setTags(Lists.<WidgetTag>newLinkedList());
+        WidgetTagImpl wt = new WidgetTagImpl(ID, DATE, ID);
+        source.getTags().add(wt);
+
+        source.setRatings(Lists.<WidgetRating>newLinkedList());
+        WidgetRating wr = new WidgetRatingImpl();
+        source.getRatings().add(wr);
+
+        converted = converter.convert(source);
+
+        assertThat(converted.getUrl(), is(equalTo("http://mitre.org")));
+        assertThat(converted.getType(), is(equalTo("type")));
+        assertThat(converted.getTitle(), is(equalTo("title")));
+        assertThat(converted.getTitleUrl(), is(equalTo("http://title.org")));
+        assertThat(converted.getThumbnailUrl(), is(equalTo("http://thumbnail.org")));
+        assertThat(converted.getScreenshotUrl(), is(equalTo("http://screenshot.org")));
+        assertThat(converted.getAuthor(), is(equalTo("author")));
+        assertThat(converted.getAuthorEmail(), is(equalTo("authorEmail")));
+        assertThat(converted.getDescription(), is(equalTo("description")));
+        assertThat(converted.getWidgetStatus(), is(WidgetStatus.PREVIEW));
+        assertNotNull(converted.getComments());
+
+        //Test convertCategories method
+        assertNotNull(converted.getCategoryIds());
+        assertThat(converted.getCategoryIds().get(0), is(equalTo(ID)));
+        assertNull(converted.getCategoryRepository());
+
+        //Test convertComments method
+        assertNotNull(converted.getComments());
+        assertThat(converted.getComments().get(0), is(instanceOf(WidgetCommentImpl.class)));
+        assertThat(((WidgetCommentImpl) (converted.getComments().get(0))).getUserId(), is(equalTo(ID)));
+        assertThat(converted.getComments().get(0).getId(), is(equalTo(ID)));
+        assertThat(converted.getComments().get(0).getCreatedDate(), is(equalTo(DATE)));
+        assertThat(converted.getComments().get(0).getLastModifiedDate(), is(equalTo(DATE)));
+        assertThat(converted.getComments().get(0).getText(), is(equalTo("text")));
+
+        //Test convertTags method
+        assertNotNull(converted.getTags());
+        assertThat(converted.getTags().get(0), is(instanceOf(WidgetTagImpl.class)));
+        assertNotNull(converted.getTags().get(0).getTagId());
+        assertThat(converted.getTags().get(0).getTagId(), is(equalTo(ID)));
+        assertThat(converted.getTags().get(0).getCreatedDate(), is(equalTo(DATE)));
+        assertThat(((WidgetTagImpl) (converted.getTags().get(0))).getUserId(), is(equalTo(ID)));
+
+        //Test convertRatings method
+        assertNotNull(converted.getRatings());
+        assertNotNull(converted.getRatings().get(0).getId());
+    }
+
+    @Test
+    public void convert_Null() {
+        Widget source = new WidgetImpl();
+        MongoDbWidget converted = converter.convert(source);
+
+        assertNull(converted.getOwnerId());
+        assertNotNull(converted.getCategories());//the getter sets this field
+        assertNotNull(converted.getCategoryIds());//the getter sets this field
+        assertNotNull(converted.getComments());
+        assertNotNull(converted.getTags());
+        assertNotNull(converted.getRatings());
+    }
+
+    @Test
+    public void convert_MongoInstance() {
+        Widget source = new MongoDbWidget();
+        WidgetComment comment = new WidgetCommentImpl();
+        comment.setUserId(ID);
+        source.setComments(Arrays.asList(comment));
+
+        WidgetTag tag = new WidgetTagImpl(ID, DATE, ID);
+        source.setTags(Arrays.asList(tag));
+
+        WidgetRatingImpl rating = new WidgetRatingImpl();
+        rating.setId(ID);
+        source.setRatings(Arrays.<WidgetRating>asList(rating));
+
+        Widget converted = converter.convert(source);
+
+        assertTrue(converted.getComments().get(0) instanceof WidgetCommentImpl);
+        assertTrue(converted.getTags().get(0) instanceof WidgetTagImpl);
+        assertThat(converted.getRatings().get(0).getId(), is(equalTo(ID)));
+    }
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbApplicationDataRepositoryTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbApplicationDataRepositoryTest.java
new file mode 100644
index 0000000..1c3b0f6
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbApplicationDataRepositoryTest.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.rave.portal.model.ApplicationData;
+import org.apache.rave.portal.model.impl.ApplicationDataImpl;
+import org.apache.rave.portal.repository.util.CollectionNames;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.data.mongodb.core.MongoOperations;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.assertThat;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: dsullivan
+ * Date: 11/29/12
+ * Time: 7:59 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class MongoDbApplicationDataRepositoryTest {
+    private MongoDbApplicationDataRepository applicationDataRepository;
+    private MongoOperations template;
+
+    @Before
+    public void setup() {
+        applicationDataRepository = new MongoDbApplicationDataRepository();
+        template = createMock(MongoOperations.class);
+        applicationDataRepository.setTemplate(template);
+    }
+
+    @Test
+    public void getApplicationData_Valid() {
+        List<String> userIds = Arrays.asList("123");
+        String appId = "blah";
+        List<ApplicationDataImpl> found = new ArrayList<ApplicationDataImpl>();
+
+        expect(template.find(query(where("appUrl").is(appId).andOperator(where("userId").in(userIds))), applicationDataRepository.CLASS, CollectionNames.APP_DATA_COLLECTION)).andReturn(found);
+        replay(template);
+        List<ApplicationData> appData = applicationDataRepository.getApplicationData(userIds, appId);
+    }
+
+    @Test
+    public void getApplicationData_Single_Valid_(){
+        String personId = "personid";
+        String appId = "appId";
+        ApplicationDataImpl found = new ApplicationDataImpl();
+        expect(template.findOne(query(where("appUrl").is(appId).andOperator(where("userId").is(personId))),applicationDataRepository.CLASS, CollectionNames.APP_DATA_COLLECTION )).andReturn(found);
+        replay(template);
+
+        assertThat((ApplicationDataImpl)applicationDataRepository.getApplicationData(personId, appId), is(sameInstance(found)));
+    }
+
+    @Test
+    public void getType_Valid(){
+        assertThat((Class<ApplicationDataImpl>)applicationDataRepository.getType(), is(equalTo(ApplicationDataImpl.class)));
+    }
+
+    @Test
+    public void get_Valid(){
+        String id = "123";
+        ApplicationDataImpl found = new ApplicationDataImpl();
+        expect(template.findById(id, applicationDataRepository.CLASS, CollectionNames.APP_DATA_COLLECTION)).andReturn(found);
+        replay(template);
+
+        assertThat(found, is(sameInstance(applicationDataRepository.get(id))));
+    }
+
+    @Test
+    public void save_Valid(){
+        ApplicationData item = new ApplicationDataImpl();
+
+        template.save(item, CollectionNames.APP_DATA_COLLECTION);
+        expectLastCall();
+        replay(template);
+
+        ApplicationData saved = applicationDataRepository.save(item);
+        verify(template);
+    }
+
+    @Test
+    public void save_Id_Set(){
+         ApplicationData item = new ApplicationDataImpl();
+        item.setId("123");
+
+        template.save(item, CollectionNames.APP_DATA_COLLECTION);
+        expectLastCall();
+        replay(template);
+
+        ApplicationData saved = applicationDataRepository.save(item);
+        assertThat(saved, is(sameInstance(item)));
+    }
+
+    @Test
+    public void delete_Valid(){
+        ApplicationData item = new ApplicationDataImpl();
+
+        template.remove(item, CollectionNames.APP_DATA_COLLECTION);
+        expectLastCall();
+        replay(template);
+
+        applicationDataRepository.delete(item);
+        verify(template);
+    }
+}
+
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbAuthorityRepositoryTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbAuthorityRepositoryTest.java
new file mode 100644
index 0000000..41491fd
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbAuthorityRepositoryTest.java
@@ -0,0 +1,223 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import com.google.common.collect.Lists;
+import org.apache.rave.portal.model.Authority;
+import org.apache.rave.portal.model.MongoDbAuthority;
+import org.apache.rave.portal.model.conversion.HydratingConverterFactory;
+import org.apache.rave.util.CollectionUtils;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.data.mongodb.core.MongoOperations;
+
+import java.util.List;
+
+import static org.apache.rave.portal.repository.util.CollectionNames.AUTHORITY_COLLECTION;
+import static org.easymock.EasyMock.*;
+import static org.easymock.EasyMock.isA;
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+/**
+ * Test for MongoDb Authority Repository class
+ */
+public class MongoDbAuthorityRepositoryTest {
+
+    private MongoOperations template;
+    private MongoDbAuthorityRepository repo;
+    private HydratingConverterFactory converter;
+    public static final Class<MongoDbAuthority> CLASS = MongoDbAuthority.class;
+
+    @Before
+    public void setup() {
+        template = createMock(MongoOperations.class);
+        converter = createNiceMock(HydratingConverterFactory.class);
+        repo = new MongoDbAuthorityRepository();
+        repo.setTemplate(template);
+        repo.setConverter(converter);
+
+    }
+
+    @Test
+    public void save_validNew(){
+        Authority returnedAuth;
+        Authority savedAuth = new MongoDbAuthority();
+        savedAuth.setAuthority("test");
+
+        template.save(isA(Authority.class), eq(AUTHORITY_COLLECTION));
+        expectLastCall();
+        expect(template.findOne(query(where("authority").is("test")), CLASS, AUTHORITY_COLLECTION)).andReturn(null);
+        replay(template);
+        expect(converter.convert(savedAuth, Authority.class)).andReturn(savedAuth);
+        replay(converter);
+
+        returnedAuth = repo.save(savedAuth);
+        assertNotNull(template);
+        assertThat(returnedAuth, is(equalTo(savedAuth)));
+        verify(template);
+    }
+
+    @Test
+    public void save_valid(){
+        Authority savedAuth = new MongoDbAuthority();
+        Authority returnedAuth;
+        savedAuth.setAuthority("test");
+
+        expect(template.findOne(query(where("authority").is("test")), CLASS, AUTHORITY_COLLECTION)).andReturn((MongoDbAuthority)savedAuth);
+        template.save(isA(Authority.class), eq(AUTHORITY_COLLECTION));
+        expectLastCall();
+
+        replay(template);
+
+        returnedAuth = repo.save(savedAuth);
+        assertThat(savedAuth.isDefaultForNewUser(), is(equalTo(returnedAuth.isDefaultForNewUser())));
+        assertNotNull(template);
+        assertThat(savedAuth, is(sameInstance(returnedAuth)));
+        verify(template);
+
+    }
+
+    @Test
+    public void delete(){
+        Authority deleted = new MongoDbAuthority();
+        deleted.setAuthority("deleted");
+
+        template.remove(isA(Authority.class), eq(AUTHORITY_COLLECTION));
+        expectLastCall();
+        expect(template.findOne(query(where("authority").is("deleted")), CLASS, AUTHORITY_COLLECTION)).andReturn((MongoDbAuthority)deleted);
+        replay(template);
+
+        repo.delete(deleted);
+
+        verify(template);
+    }
+
+    @Test
+    public void getByAuthority(){
+        Authority authority = new MongoDbAuthority();
+        authority.setAuthority("test");
+        Authority result;
+        template.save(authority, AUTHORITY_COLLECTION);
+
+        expect(template.findOne(query(where("authority").is("test")), CLASS, AUTHORITY_COLLECTION)).andReturn((MongoDbAuthority)authority);
+        replay(template);
+
+        result = repo.getByAuthority("test");
+        assertThat(result, is(sameInstance(authority)));
+
+    }
+
+
+    @Test
+    public void getAll(){
+        List<Authority> allAuth = Lists.newLinkedList();
+        Authority authority = new MongoDbAuthority();
+        authority.setAuthority("test");
+        allAuth.add(authority);
+
+        expect(CollectionUtils.<Authority>toBaseTypedList(template.findAll(CLASS, AUTHORITY_COLLECTION))).andReturn(allAuth);
+        replay(template);
+
+        List<Authority> result;
+
+        result = repo.getAll();
+        assertThat(result.size(), is(1));
+        assertThat(result.get(0), is(sameInstance(authority)));
+
+    }
+
+    @Test
+    public void getAllDefault(){
+        List<Authority> allDefaultAuth = Lists.newLinkedList();
+        Authority authority = new MongoDbAuthority();
+        authority.setAuthority("test");
+        authority.setDefaultForNewUser(true);
+        allDefaultAuth.add(authority);
+
+        expect(CollectionUtils.<Authority>toBaseTypedList(template.find(query(where("defaultForNewUser").is(true)), CLASS, AUTHORITY_COLLECTION))).andReturn(allDefaultAuth);
+        replay(template);
+
+        List<Authority> result;
+
+        result = repo.getAllDefault();
+        assertThat(result.size(), is(1));
+        assertThat(result.get(0), is(sameInstance(authority)));
+        assertThat(result.get(0).getAuthority(), is(equalTo("test")));
+
+    }
+
+
+    @Test
+    public void getAllDefault_false(){
+        List<Authority> allDefaultAuth = Lists.newLinkedList();
+        Authority authority = new MongoDbAuthority();
+        authority.setDefaultForNewUser(false);
+        allDefaultAuth.add(authority);
+
+        expect(CollectionUtils.<Authority>toBaseTypedList(template.find(query(where("defaultForNewUser").is(true)), CLASS, AUTHORITY_COLLECTION))).andReturn(null);
+        replay(template);
+
+        List<Authority> result;
+
+        result = repo.getAllDefault();
+        assertNull(result);
+    }
+
+
+    @Test
+    public void getTemplate(){
+        MongoOperations temp1;
+
+        temp1 = repo.getTemplate();
+        assertThat(temp1, is(sameInstance(template)));
+    }
+
+    @Test
+    public void setTemplate(){
+        MongoOperations temp1 = createNiceMock(MongoOperations.class);
+
+        repo.setTemplate(temp1);
+        assertThat(repo.getTemplate(), is(sameInstance(temp1)));
+
+    }
+
+    @Test
+    public void getConverter(){
+        HydratingConverterFactory converter1;
+
+        converter1 = repo.getConverter();
+        assertThat(converter1, is(sameInstance(converter)));
+    }
+
+    @Test
+    public void setConverter(){
+        HydratingConverterFactory converter1 = createNiceMock(HydratingConverterFactory.class);
+
+        repo.setConverter(converter1);
+        assertThat(repo.getConverter(), is(sameInstance(converter1)));
+
+    }
+
+
+
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbCategoryRepositoryTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbCategoryRepositoryTest.java
new file mode 100644
index 0000000..e5ee63e
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbCategoryRepositoryTest.java
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.rave.portal.model.Category;
+import org.apache.rave.portal.model.MongoDbCategory;
+import org.apache.rave.portal.model.conversion.HydratingConverterFactory;
+import org.apache.rave.portal.repository.util.CollectionNames;
+import org.apache.rave.util.CollectionUtils;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.query.Criteria;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+/**
+ * User: DSULLIVAN
+ * Date: 12/10/12
+ * Time: 7:55 AM
+ */
+public class MongoDbCategoryRepositoryTest {
+    private MongoDbCategoryRepository categoryRepository;
+    private MongoOperations template;
+    private HydratingConverterFactory converter;
+
+    @Before
+    public void setup(){
+        categoryRepository = new MongoDbCategoryRepository();
+        template = createMock(MongoOperations.class);
+        converter = createMock(HydratingConverterFactory.class);
+        categoryRepository.setConverter(converter);
+        categoryRepository.setTemplate(template);
+    }
+
+    @Test
+    public void getAll_Valid(){
+        List<MongoDbCategory> categoryList = new ArrayList<MongoDbCategory>();
+        MongoDbCategory category = new MongoDbCategory();
+        categoryList.add(category);
+        expect(template.findAll(categoryRepository.CLASS, CollectionNames.CATEGORY_COLLECTION)).andReturn(categoryList);
+        converter.hydrate(category, Category.class);
+        expectLastCall();
+        replay(template, converter);
+
+        assertThat(CollectionUtils.<Category>toBaseTypedList(categoryList), is(sameInstance(categoryRepository.getAll())));
+    }
+
+    @Test
+    public void removeFromCreatedOrModifiedFields_Valid(){
+        List<MongoDbCategory> categoryList = new ArrayList<MongoDbCategory>();
+        MongoDbCategory category = new MongoDbCategory();
+        categoryList.add(category);
+        String userId = "123";
+        category.setCreatedUserId(userId);
+        category.setLastModifiedUserId(userId);
+        MongoDbCategory converted = new MongoDbCategory();
+
+        expect(template.find(query(Criteria.where("lastModifiedUserId").is(userId).orOperator(Criteria.where("createdUserId").is(userId))), categoryRepository.CLASS, CollectionNames.CATEGORY_COLLECTION)).andReturn(categoryList);
+        expect(converter.convert(category, Category.class)).andReturn(converted);
+        template.save(converted, CollectionNames.CATEGORY_COLLECTION);
+        expectLastCall();
+        converter.hydrate(category, Category.class);
+        expectLastCall();
+        replay(template, converter);
+
+        int count = categoryRepository.removeFromCreatedOrModifiedFields(userId);
+        assertNull(category.getCreatedUserId());
+        assertNull(category.getLastModifiedUserId());
+        assertThat(count, is(equalTo(1)));
+
+    }
+
+    @Test
+    public void removeFromCreatedOrModifiedFields_NotUpdated(){
+        String userId = "54321";
+        MongoDbCategory category = new MongoDbCategory();
+        List<MongoDbCategory> categories = Arrays.asList(category);
+        category.setCreatedUserId("234");
+        category.setLastModifiedUserId("234");
+        expect(template.find(query(Criteria.where("lastModifiedUserId").is(userId).orOperator(Criteria.where("createdUserId").is(userId))), categoryRepository.CLASS, CollectionNames.CATEGORY_COLLECTION)).andReturn(categories);
+        replay(template);
+
+        int count = categoryRepository.removeFromCreatedOrModifiedFields(userId);
+        assertThat(count, is(equalTo(0)));
+    }
+
+    @Test
+    public void getType_Valid(){
+        assertThat((Class<MongoDbCategory>)categoryRepository.getType(), is(equalTo(categoryRepository.CLASS)));
+    }
+
+    @Test
+    public void get_Valid(){
+        String id = "123";
+        MongoDbCategory category = new MongoDbCategory();
+        expect(template.findById(id, categoryRepository.CLASS, CollectionNames.CATEGORY_COLLECTION)).andReturn(category);
+        converter.hydrate(category, Category.class);
+        expectLastCall();
+        replay(template, converter);
+
+        assertThat(category, is(sameInstance(categoryRepository.get(id))));
+
+    }
+
+    @Test
+    public void save_Valid(){
+        MongoDbCategory converted = new MongoDbCategory();
+        Category item = new MongoDbCategory();
+
+        expect(converter.convert(item, Category.class)).andReturn(converted);
+        template.save(converted, CollectionNames.CATEGORY_COLLECTION);
+        expectLastCall();
+        converter.hydrate(converted, Category.class);
+        expectLastCall();
+        replay(converter, template);
+
+        assertThat(converted, is(sameInstance(categoryRepository.save(item))));
+    }
+
+    @Test
+    public void delete_Valid(){
+        Category item = new MongoDbCategory();
+        String id = "123";
+        item.setId(id);
+        MongoDbCategory hydrate = new MongoDbCategory();
+
+        expect(template.findById(id, categoryRepository.CLASS, CollectionNames.CATEGORY_COLLECTION)).andReturn(hydrate);
+        template.remove(hydrate, CollectionNames.CATEGORY_COLLECTION);
+        expectLastCall();
+        converter.hydrate(hydrate, Category.class);
+        expectLastCall();
+        replay(template, converter);
+
+        categoryRepository.delete(item);
+
+        verify(converter, template);
+    }
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbOAuthTokenInfoRepositoryTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbOAuthTokenInfoRepositoryTest.java
new file mode 100644
index 0000000..2994515
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbOAuthTokenInfoRepositoryTest.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.rave.portal.model.OAuthTokenInfo;
+import org.apache.rave.portal.model.impl.OAuthTokenInfoImpl;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.data.mongodb.core.MongoOperations;
+
+import static org.apache.rave.portal.repository.util.CollectionNames.OAUTH_TOKEN_COLLECTION;
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+/**
+ * Test for MongoDb OAuthTokenInfo Repository class.
+ */
+public class MongoDbOAuthTokenInfoRepositoryTest {
+
+    private MongoOperations template;
+    private MongoDbOAuthTokenInfoRepository repo;
+    private static final Class<OAuthTokenInfo> CLASS1 = OAuthTokenInfo.class;
+    public static final Class<OAuthTokenInfoImpl> CLASS2 = OAuthTokenInfoImpl.class;
+
+    @Before
+    public void setUp(){
+        template = createMock(MongoOperations.class);
+        repo = new MongoDbOAuthTokenInfoRepository();
+        repo.setTemplate(template);
+    }
+
+    @Test
+    public void findOAuthTokenInfo(){
+        OAuthTokenInfo info = new OAuthTokenInfoImpl();
+        String userId = "1234";
+        String appUrl = "www.test.com";
+        String moduleId = "2222";
+        String tokenName = "token";
+        String serviceName = "service";
+        info.setUserId(userId);
+        info.setAppUrl(appUrl);
+        info.setModuleId(moduleId);
+        info.setTokenName(tokenName);
+        info.setServiceName(serviceName);
+        expect(template.findOne(query(where("userId").is(userId)
+                .andOperator(where("appUrl").is(appUrl))
+                .andOperator(where("moduleId").is(moduleId))
+                .andOperator(where("tokenName").is(tokenName))
+                .andOperator(where("serviceName").is(serviceName))
+        ), CLASS1, OAUTH_TOKEN_COLLECTION)).andReturn(info);
+        replay(template);
+
+    }
+
+    @Test
+    public void save_null(){
+        OAuthTokenInfo info = new OAuthTokenInfoImpl();
+        OAuthTokenInfo result;
+
+        template.save(isA(OAuthTokenInfo.class), eq(OAUTH_TOKEN_COLLECTION));
+        expectLastCall();
+        replay(template);
+
+        result = repo.save(info);
+        verify(template);
+
+    }
+
+    @Test
+    public void save(){
+        OAuthTokenInfo item = new OAuthTokenInfoImpl("appUrl", "serviceName",
+                "tokenName", "accessToken", "sessionHandle",
+                "tokenSecret", "userId", 1111L);
+        OAuthTokenInfo result;
+        item.setId("1234L");
+
+        template.save(isA(OAuthTokenInfo.class), eq(OAUTH_TOKEN_COLLECTION));
+        expectLastCall();
+
+        result = repo.save(item);
+        assertNotNull(result.getId());
+        assertThat(result.getId(), is(equalTo("1234L")));
+
+    }
+
+    @Test
+    public void get(){
+        OAuthTokenInfo result;
+        OAuthTokenInfo item = new OAuthTokenInfoImpl("appUrl", "serviceName",
+                "tokenName", "accessToken", "sessionHandle",
+                "tokenSecret", "userId", 1111L);
+        item.setId("1234L");
+
+        expect(template.findById("1234L", CLASS2, OAUTH_TOKEN_COLLECTION)).andReturn((OAuthTokenInfoImpl)item);
+        replay(template);
+
+        result = repo.get("1234L");
+        assertThat(result.getId(), is(equalTo("1234L")));
+
+    }
+
+    @Test
+    public void delete(){
+        OAuthTokenInfo item = new OAuthTokenInfoImpl("appUrl", "serviceName",
+                "tokenName", "accessToken", "sessionHandle",
+                "tokenSecret", "userId", 1111L);
+        item.setId("1234L");
+
+        template.remove(item);
+        expectLastCall();
+        expect(template.findById("1234L", CLASS2, OAUTH_TOKEN_COLLECTION)).andReturn((OAuthTokenInfoImpl)item);
+        replay(template);
+
+        repo.delete(item);
+        verify(template);
+
+    }
+
+
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbOauthConsumerStoreRepositoryTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbOauthConsumerStoreRepositoryTest.java
new file mode 100644
index 0000000..f752499
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbOauthConsumerStoreRepositoryTest.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.rave.portal.model.OAuthConsumerStore;
+import org.apache.rave.portal.model.impl.OAuthConsumerStoreImpl;
+import org.apache.rave.portal.repository.util.CollectionNames;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.data.mongodb.core.MongoOperations;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.assertThat;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+/**
+ * User: DSULLIVAN
+ * Date: 12/5/12
+ * Time: 9:21 AM
+ */
+public class MongoDbOauthConsumerStoreRepositoryTest {
+    private MongoDbOauthConsumerStoreRepository oauthConsumerStoreRepository;
+    private MongoOperations template;
+
+    @Before
+    public void setup() {
+        oauthConsumerStoreRepository = new MongoDbOauthConsumerStoreRepository();
+        template = createMock(MongoOperations.class);
+        oauthConsumerStoreRepository.setTemplate(template);
+    }
+
+    @Test
+    public void findUriAndServiceNameValid() {
+        String gadgetUri = "gadgetUri";
+        String serviceName = "serviceName";
+        OAuthConsumerStoreImpl found = new OAuthConsumerStoreImpl();
+        expect(template.findOne(query(where("gadgetUri").is(gadgetUri).andOperator(where("serviceName").is(serviceName))), MongoDbOauthConsumerStoreRepository.CLASS, CollectionNames.OAUTH_CONSUMER_COLLECTION)).andReturn(found);
+        replay(template);
+
+        OAuthConsumerStore returned = oauthConsumerStoreRepository.findByUriAndServiceName(gadgetUri, serviceName);
+
+        assertThat((OAuthConsumerStoreImpl) returned, is(sameInstance(found)));
+    }
+
+    @Test
+    public void getType_Valid() {
+        assertThat((Class<OAuthConsumerStoreImpl>) oauthConsumerStoreRepository.getType(), is(equalTo(OAuthConsumerStoreImpl.class)));
+    }
+
+    @Test
+    public void get_Valid() {
+        String id = "123";
+        OAuthConsumerStoreImpl found = new OAuthConsumerStoreImpl();
+        expect(template.findById(id, oauthConsumerStoreRepository.CLASS, CollectionNames.OAUTH_CONSUMER_COLLECTION)).andReturn(found);
+        replay(template);
+
+        assertThat(found, is(sameInstance(oauthConsumerStoreRepository.get(id))));
+    }
+
+    @Test
+    public void save_Valid(){
+        OAuthConsumerStore item = new OAuthConsumerStoreImpl();
+        template.save(item, CollectionNames.OAUTH_CONSUMER_COLLECTION);
+        expectLastCall();
+        replay(template);
+
+        OAuthConsumerStore returned = oauthConsumerStoreRepository.save(item);
+
+        verify(template);
+    }
+
+    @Test
+    public void save_Null_Id(){
+        OAuthConsumerStore item = new OAuthConsumerStoreImpl();
+        item.setId("1232");
+        template.save(item, CollectionNames.OAUTH_CONSUMER_COLLECTION);
+        expectLastCall();
+        replay(template);
+
+        OAuthConsumerStore returned = oauthConsumerStoreRepository.save(item);
+
+        assertThat(item, is(sameInstance(returned)));
+    }
+
+    @Test
+    public void delete_Valid() {
+        OAuthConsumerStore item = new OAuthConsumerStoreImpl();
+        item.setId("123");
+
+        expect(template.findById(item.getId(), oauthConsumerStoreRepository.CLASS, CollectionNames.OAUTH_CONSUMER_COLLECTION)).andReturn((OAuthConsumerStoreImpl)item);
+        template.remove(item);
+        expectLastCall();
+        replay(template);
+
+        oauthConsumerStoreRepository.delete(item);
+        verify(template);
+    }
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbPageLayoutRepositoryTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbPageLayoutRepositoryTest.java
new file mode 100644
index 0000000..0ca702b
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbPageLayoutRepositoryTest.java
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.commons.lang.NotImplementedException;
+import org.apache.rave.portal.model.MongoDbPageLayout;
+import org.apache.rave.portal.model.PageLayout;
+import org.apache.rave.portal.repository.util.CollectionNames;
+import org.apache.rave.util.CollectionUtils;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.query.Query;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.easymock.EasyMock.*;
+import static org.easymock.EasyMock.isA;
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.assertThat;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+
+/**
+ * User: DSULLIVAN
+ * Date: 12/5/12
+ * Time: 11:17 AM
+ */
+public class MongoDbPageLayoutRepositoryTest {
+    private MongoDbPageLayoutRepository pageLayoutRepository;
+    private MongoOperations template;
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
+    @Before
+    public void setup() {
+        pageLayoutRepository = new MongoDbPageLayoutRepository();
+        template = createMock(MongoOperations.class);
+        pageLayoutRepository.setTemplate(template);
+    }
+
+    @Test
+    public void getByPageLayoutCode_Valid() {
+        String codename = "codename";
+        MongoDbPageLayout found = new MongoDbPageLayout();
+        expect(template.findOne(new Query(where("code").is(codename)), MongoDbPageLayoutRepository.CLASS, CollectionNames.PAGE_LAYOUT_COLLECTION)).andReturn(found);
+        replay(template);
+
+        assertThat((MongoDbPageLayout) pageLayoutRepository.getByPageLayoutCode(codename), is(sameInstance(found)));
+    }
+
+    @Test
+    public void getAll_Valid() {
+        List<MongoDbPageLayout> found = new ArrayList<MongoDbPageLayout>();
+        expect(template.findAll(pageLayoutRepository.CLASS, CollectionNames.PAGE_LAYOUT_COLLECTION)).andReturn(found);
+        replay(template);
+
+        assertThat(pageLayoutRepository.getAll(), is(sameInstance(CollectionUtils.<PageLayout>toBaseTypedList(found))));
+    }
+
+    @Test
+    public void getAllUserSelectable_Valid() {
+        List<MongoDbPageLayout> userSelectable = new ArrayList<MongoDbPageLayout>();
+        expect(template.find(new Query(where("userSelectable").is(true)), pageLayoutRepository.CLASS, CollectionNames.PAGE_LAYOUT_COLLECTION)).andReturn(userSelectable);
+        replay(template);
+
+        List<PageLayout> returned = pageLayoutRepository.getAllUserSelectable();
+
+        assertThat(returned, is(sameInstance(CollectionUtils.<PageLayout>toBaseTypedList(userSelectable))));
+    }
+
+    @Test
+    public void getType_Valid() {
+        assertThat((Class<MongoDbPageLayout>) pageLayoutRepository.getType(), is(equalTo(MongoDbPageLayout.class)));
+    }
+
+    @Test
+    public void get_Valid() {
+        String id = "123";
+
+        thrown.expect(NotImplementedException.class);
+        thrown.expectMessage("No use for an id");
+        pageLayoutRepository.get(id);
+    }
+
+    @Test
+    public void save_Valid() {
+        PageLayout item1 = new MongoDbPageLayout();
+        item1.setCode("blah1");
+        expect(template.findOne(new Query(where("code").is(item1.getCode())), pageLayoutRepository.CLASS, CollectionNames.PAGE_LAYOUT_COLLECTION)).andReturn(null);
+        template.save(isA(MongoDbPageLayout.class), eq(CollectionNames.PAGE_LAYOUT_COLLECTION));
+        expectLastCall();
+        replay(template);
+
+        PageLayout saved = pageLayoutRepository.save(item1);
+
+        assertThat(saved, is(instanceOf(MongoDbPageLayout.class)));
+        assertThat(saved.getCode(), is(sameInstance(item1.getCode())));
+        assertThat(saved.getNumberOfRegions(), is(sameInstance(item1.getNumberOfRegions())));
+        assertThat(saved.getRenderSequence(), is(sameInstance(item1.getRenderSequence())));
+        assertThat(saved.isUserSelectable(), is(sameInstance(item1.isUserSelectable())));
+    }
+
+    @Test
+    public void save_Null(){
+        PageLayout item1 = new MongoDbPageLayout();
+        item1.setCode("blah1");
+        item1.setNumberOfRegions((long)123);
+        item1.setRenderSequence((long)432);
+        item1.setUserSelectable(true);
+        MongoDbPageLayout toSave = new MongoDbPageLayout();
+        expect(template.findOne(new Query(where("code").is(item1.getCode())), pageLayoutRepository.CLASS, CollectionNames.PAGE_LAYOUT_COLLECTION)).andReturn(toSave);
+        template.save(isA(MongoDbPageLayout.class), eq(CollectionNames.PAGE_LAYOUT_COLLECTION));
+        expectLastCall();
+        replay(template);
+
+        PageLayout saved = pageLayoutRepository.save(item1);
+
+        assertThat(saved.getCode(), is(sameInstance(item1.getCode())));
+        assertThat(saved.getNumberOfRegions(), is(sameInstance(item1.getNumberOfRegions())));
+        assertThat(saved.getRenderSequence(), is(sameInstance(item1.getRenderSequence())));
+        assertThat(saved.isUserSelectable(), is(sameInstance(item1.isUserSelectable())));
+    }
+
+    @Test
+    public void delete_Valid(){
+        PageLayout item = new MongoDbPageLayout();
+        item.setCode("123");
+        expect(template.findOne(new Query(where("code").is(item.getCode())), pageLayoutRepository.CLASS, CollectionNames.PAGE_LAYOUT_COLLECTION)).andReturn((MongoDbPageLayout)item);
+
+          template.remove(item);
+        expectLastCall();
+        replay(template);
+
+        pageLayoutRepository.delete(item);
+        verify(template);
+    }
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbPageRepositoryTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbPageRepositoryTest.java
new file mode 100644
index 0000000..e5058e9
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbPageRepositoryTest.java
@@ -0,0 +1,341 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import com.google.common.collect.Lists;
+import org.apache.rave.portal.model.*;
+import org.apache.rave.portal.model.impl.*;
+import org.apache.rave.portal.repository.*;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.data.mongodb.core.query.Query;
+
+import java.util.List;
+
+import static org.easymock.EasyMock.*;
+import static org.easymock.EasyMock.isA;
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+public class MongoDbPageRepositoryTest {
+
+    private MongoPageOperations template;
+    private MongoDbPageRepository repo;
+
+
+    @Before
+    public void setUp(){
+        template = createMock(MongoPageOperations.class);
+        repo = new MongoDbPageRepository();
+        repo.setTemplate(template);
+    }
+
+    @Test
+    public void getAllPages(){
+        String userId = "1234L";
+        String userId1 = "9999L";
+        PageType pageType = PageType.USER;
+        PageUserImpl user = new PageUserImpl();
+        user.setId("3333L");
+        user.setUserId(userId1);
+        PageUserImpl user2 = new PageUserImpl();
+        user2.setId(userId);
+        user2.setUserId(userId);
+        List<Page> pages = Lists.newArrayList();
+        List<PageUser> page_users = Lists.newArrayList();
+        List<PageUser> page2_users = Lists.newArrayList();
+        page_users.add(user);
+        page2_users.add(user2);
+        Page page = new PageImpl();
+        page.setMembers(page_users);
+        Page page2 = new PageImpl();
+        page2.setMembers(page2_users);
+        pages.add(page);
+        pages.add(page2);
+
+        expect(template.find(isA(Query.class))).andReturn(pages);
+        replay(template);
+
+        List<Page> result = repo.getAllPages(userId, pageType);
+        assertNotNull(result);
+
+    }
+
+    @Test
+    public void getType(){
+        Class<? extends Page> result = repo.getType();
+        assertNotNull(result);
+    }
+
+    @Test
+    public void createPageForUser(){
+        Page result = new PageImpl();
+        String userId = "2424L";
+        User user = new UserImpl(userId);
+        PageTemplate pt = new PageTemplateImpl();
+        PageLayout layout = new PageLayoutImpl();
+        List<PageTemplateRegion> regions = Lists.newArrayList();
+        List<PageTemplateRegion> subRegions = Lists.newArrayList();
+        List<PageTemplateWidget> widgets = Lists.newArrayList();
+        List<PageTemplate> subPageTemplates = Lists.newArrayList();
+
+        PageTemplate sub = new PageTemplateImpl();
+        sub.setName("sub");
+        PageTemplateRegion subRegion = new PageTemplateRegionImpl();
+        subRegion.setRenderSequence(5555L);
+        subRegion.setLocked(true);
+        subRegion.setPageTemplateWidgets(widgets);
+        subRegions.add(subRegion);
+        sub.setPageTemplateRegions(subRegions);
+        sub.setName("sub");
+        sub.setPageType(PageType.SUB_PAGE);
+        sub.setPageLayout(layout);
+        sub.setPageTemplateRegions(subRegions);
+        sub.setRenderSequence(2000L);
+
+        PageTemplateWidget widget = new PageTemplateWidgetImpl();
+        Widget w = new WidgetImpl("1234");
+        widget.setLocked(true);
+        widget.setHideChrome(true);
+        widget.setRenderSeq(2000L);
+        widget.setWidgetId(w.getId());
+        widgets.add(widget);
+
+        PageTemplateRegion region = new PageTemplateRegionImpl();
+        region.setRenderSequence(1111L);
+        region.setPageTemplateWidgets(widgets);
+        region.setLocked(true);
+        regions.add(region);
+
+        pt.setName("carol");
+        pt.setPageType(PageType.USER);
+        pt.setPageLayout(layout);
+        subPageTemplates.add(sub);
+        pt.setSubPageTemplates(subPageTemplates);
+        pt.setPageTemplateRegions(regions);
+        pt.setRenderSequence(2000L);
+
+        expect(template.save(isA(Page.class))).andReturn(result);
+        replay(template);
+
+        result = repo.createPageForUser(user, pt);
+        assertNotNull(result);
+
+    }
+
+    @Test
+    public void delete(){
+        Page page = new PageImpl("1234L");
+
+        template.remove(query(where("_id").is("1234L")));
+        expectLastCall();
+        replay(template);
+
+        repo.delete(page);
+        verify(template);
+    }
+
+    @Test
+    public void deletePages(){
+        int resultCount;
+        String userID = "1111L";
+
+        expect((int)template.count(isA(Query.class))).andReturn(1);
+        template.remove(isA(Query.class));
+        expectLastCall();
+        replay(template);
+
+        resultCount = repo.deletePages(userID, PageType.USER);
+        assertThat(resultCount, is(equalTo(1)));
+        verify(template);
+    }
+
+    @Test
+    public void hasPersonPage_true(){
+        String userId = "1234L";
+        User user = new UserImpl(userId);
+        Page page = new PageImpl();
+        page.setPageType(PageType.PERSON_PROFILE);
+        page.setOwnerId(userId);
+
+        expect(template.count(query(where("pageType").is(PageType.PERSON_PROFILE).andOperator(where("ownerId").is(userId))))).andReturn(1L);
+        replay(template);
+
+        boolean result = repo.hasPersonPage(userId);
+        assertTrue(result);
+
+    }
+
+    @Test
+    public void hasPersonPage_false(){
+        String userId = "1234L";
+
+        expect(template.count(query(where("pageType").is(PageType.PERSON_PROFILE).andOperator(where("ownerId").is(userId))))).andReturn(0L);
+        replay(template);
+
+        boolean result = repo.hasPersonPage(userId);
+        assertFalse(result);
+
+    }
+
+    @Test
+    public void getPagesForUser(){
+        Page p = new PageImpl();
+        PageUser user1 = new PageUserImpl("2222L");
+        PageUser user3 = new PageUserImpl("2222L");
+        User user2 = new UserImpl("2222L");
+        user1.setUserId(user2.getId());
+        List<PageUser> pageUser = Lists.newArrayList();
+        pageUser.add(user1);
+        pageUser.add(user3);
+        p.setMembers(pageUser);
+
+        Page p2 = new PageImpl();
+        PageUser user4 = new PageUserImpl("2222L");
+        PageUser user5 = new PageUserImpl("2222L");
+        User user6 = new UserImpl("2222L");
+        user4.setUserId(user6.getId());
+        List<PageUser> pageUser2 = Lists.newArrayList();
+        pageUser.add(user4);
+        pageUser.add(user5);
+        p2.setMembers(pageUser2);
+        List<Page> pages = Lists.newArrayList(p);
+        pages.add(p2);
+
+        List<PageUser> result;
+        String userId = "2222L";
+
+        expect(template.find(query(where("members").elemMatch(where("userId").is(userId)).andOperator(where("pageType").is("USER"))))).andReturn(pages);
+        replay(template);
+        result = repo.getPagesForUser(userId, PageType.USER);
+
+        assertThat(result.get(0).getUserId(), is(equalTo(user2.getId())));
+        assertThat(result.size(), is(equalTo(2)));
+        assertThat(result.get(0).getUserId(), is(equalTo("2222L")));
+
+    }
+
+    @Test
+    public void getPagesForUser_false(){
+        Page p = new PageImpl();
+        PageUser user1 = new PageUserImpl("2222L");
+        PageUser user3 = new PageUserImpl("2222L");
+        user1.setRenderSequence(1L);
+        user3.setRenderSequence(1L);
+        User user2 = new UserImpl("2222L");
+        user1.setUserId("2222L");
+        List<PageUser> pageUser = Lists.newArrayList();
+        pageUser.add(user1);
+        pageUser.add(user3);
+        p.setMembers(pageUser);
+
+        Page p2 = new PageImpl();
+        PageUser user4 = new PageUserImpl("2222L");
+        PageUser user5 = new PageUserImpl("2222L");
+        user4.setRenderSequence(1L);
+        user5.setRenderSequence(1L);
+        user4.setUserId("2222L");
+        List<PageUser> pageUser2 = Lists.newArrayList();
+        pageUser.add(user4);
+        pageUser.add(user5);
+        p2.setMembers(pageUser2);
+        List<Page> pages = Lists.newArrayList(p);
+        pages.add(p2);
+
+        List<PageUser> result;
+        String userId = "2222L";
+
+        expect(template.find(query(where("members").elemMatch(where("userId").is(userId)).andOperator(where("pageType").is("USER"))))).andReturn(pages);
+        replay(template);
+        result = repo.getPagesForUser(userId, PageType.USER);
+
+        assertThat(result.get(0).getUserId(), is(equalTo("2222L")));
+        assertThat(result.size(), is(equalTo(2)));
+        assertThat(result.get(0).getUserId(), is(equalTo("2222L")));
+
+    }
+
+    @Test
+    public void getPagesForUser_null(){
+        Page p = new PageImpl();
+        PageUser user1 = new PageUserImpl("1111L");
+        user1.setUserId("2222L");
+        List<PageUser> pageUser = Lists.newArrayList();
+        pageUser.add(user1);
+        p.setMembers(pageUser);
+        List<Page> pages = Lists.newArrayList(p);
+
+        List<PageUser> result;
+        String userId = "3333L";
+
+        expect(template.find(query(where("members").elemMatch(where("userId").is(userId)).andOperator(where("pageType").is("USER"))))).andReturn(pages);
+        replay(template);
+
+        result = repo.getPagesForUser(userId, PageType.USER);
+        assertThat(result.size(), is(equalTo(1)));
+
+    }
+
+    @Test
+    public void getSingleRecord_valid(){
+        String userId = "1111L";
+        String pageId = "2222L";
+
+        Page testPage = new PageImpl("2222L");
+        PageUser pu = new PageUserImpl("3333L");
+        pu.setUserId("1111L");
+        List<PageUser> users = Lists.newArrayList();
+        users.add(pu);
+        testPage.setMembers(users);
+        PageUser result;
+
+        expect(template.get(pageId)).andReturn(testPage);
+        replay(template);
+
+        result = repo.getSingleRecord(userId, pageId);
+        assertThat(result, is(sameInstance(pu)));
+        assertThat(result.getId(), is(equalTo("3333L")));
+        assertThat(result.getUserId(), is(equalTo("1111L")));
+
+    }
+
+    @Test
+    public void getSingleRecord_null(){
+        String userId = "1111L";
+        String pageId = "2222L";
+
+        Page testPage = new PageImpl(pageId);
+        PageUser pu = new PageUserImpl("3333L");
+        pu.setUserId("1234L");
+        List<PageUser> users = Lists.newArrayList();
+        users.add(pu);
+        testPage.setMembers(users);
+        PageUser result;
+
+        expect(template.get(pageId)).andReturn(testPage);
+        replay(template);
+
+        result = repo.getSingleRecord(userId, pageId);
+        assertNull(result);
+    }
+
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbPageTemplateRepositoryTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbPageTemplateRepositoryTest.java
new file mode 100644
index 0000000..bd76eb8
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbPageTemplateRepositoryTest.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.rave.portal.model.MongoDbPageTemplate;
+import org.apache.rave.portal.model.PageTemplate;
+import org.apache.rave.portal.model.PageType;
+import org.apache.rave.portal.model.conversion.HydratingConverterFactory;
+import org.apache.rave.portal.model.impl.PageTemplateImpl;
+import org.apache.rave.portal.repository.util.CollectionNames;
+import org.apache.rave.util.CollectionUtils;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.query.Query;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+
+/**
+ * User: DSULLIVAN
+ * Date: 12/5/12
+ * Time: 2:46 PM
+ */
+public class MongoDbPageTemplateRepositoryTest {
+
+    private MongoDbPageTemplateRepository templateRepository;
+    private HydratingConverterFactory converter;
+    private MongoOperations template;
+
+    @Before
+    public void setup(){
+        templateRepository = new MongoDbPageTemplateRepository();
+        converter = createMock(HydratingConverterFactory.class);
+        template = createMock(MongoOperations.class);
+        templateRepository.setTemplate(template);
+        templateRepository.setConverter(converter);
+    }
+
+    @Test
+    public void getAll_Valid() {
+        List<MongoDbPageTemplate> templates = new ArrayList<MongoDbPageTemplate>();
+        PageTemplate temp = new MongoDbPageTemplate();
+        templates.add((MongoDbPageTemplate)temp);
+        expect(template.findAll(MongoDbPageTemplate.class, CollectionNames.PAGE_TEMPLATE_COLLECTION)).andReturn(templates);
+        converter.hydrate(temp, PageTemplate.class);
+        expectLastCall();
+        replay(template, converter);
+
+        List<PageTemplate> returned = templateRepository.getAll();
+        verify(converter);
+        assertThat(returned, is(sameInstance(CollectionUtils.<PageTemplate>toBaseTypedList(templates))));
+    }
+
+    @Test
+    public void getDefaultPage_Valid(){
+        PageType pageType = PageType.get("user");
+        MongoDbPageTemplate found = new MongoDbPageTemplate();
+        expect(template.findOne(new Query(where("pageType").is(pageType.getPageType().toUpperCase()).andOperator(where("defaultTemplate").is(true))), MongoDbPageTemplate.class, CollectionNames.PAGE_TEMPLATE_COLLECTION)).andReturn(found);
+        converter.hydrate(found, PageTemplate.class);
+        expectLastCall();
+        replay(converter, template);
+
+        PageTemplate returned = templateRepository.getDefaultPage(pageType);
+
+        assertThat((MongoDbPageTemplate)returned, is(sameInstance(found)));
+    }
+
+    @Test
+    public void save_Valid(){
+        PageTemplate pageTemplate = new PageTemplateImpl();
+        MongoDbPageTemplate converted = new MongoDbPageTemplate();
+
+        expect(converter.convert(pageTemplate, PageTemplate.class)).andReturn(converted);
+        template.save(converted, CollectionNames.PAGE_TEMPLATE_COLLECTION);
+        expectLastCall();
+        converter.hydrate(converted, PageTemplate.class);
+        expectLastCall();
+        replay(converter, template);
+
+        PageTemplate saved = templateRepository.save(pageTemplate);
+        assertThat(converted, is(sameInstance(saved)));
+    }
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbPersonRepositoryTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbPersonRepositoryTest.java
new file mode 100644
index 0000000..5c8c2b6
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbPersonRepositoryTest.java
@@ -0,0 +1,247 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import com.google.common.collect.Lists;
+import org.apache.rave.portal.model.*;
+import org.apache.rave.portal.model.impl.*;
+import org.apache.rave.portal.repository.MongoPageOperations;
+import org.apache.rave.portal.repository.MongoUserOperations;
+import org.apache.rave.portal.repository.MongoWidgetOperations;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.data.mongodb.core.query.Query;
+
+import java.util.HashMap;
+import java.util.List;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.*;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+/**
+ * Test for MongoDb Person Repository class
+ */
+public class MongoDbPersonRepositoryTest {
+
+    private MongoUserOperations template;
+    private MongoPageOperations pageTemplate;
+    private MongoWidgetOperations widgetOperations;
+    private MongoDbPersonRepository repo;
+
+    @Before
+    public void setUp() {
+        template = createMock(MongoUserOperations.class);
+        pageTemplate = createMock(MongoPageOperations.class);
+        widgetOperations = createMock(MongoWidgetOperations.class);
+        repo = new MongoDbPersonRepository();
+        repo.setTemplate(template);
+        repo.setPageTemplate(pageTemplate);
+        repo.setWidgetOperations(widgetOperations);
+    }
+
+    @Test
+    public void findFriends_username() {
+        String username = "username";
+        MongoDbUser user = new MongoDbUser("1234L");
+        user.setUsername(username);
+        List<MongoDbPersonAssociation> friends = Lists.newLinkedList();
+        MongoDbPersonAssociation friend1 = new MongoDbPersonAssociation("1111L", FriendRequestStatus.ACCEPTED, MongoDbPersonAssociation.Direction.INCOMING);
+        friends.add(friend1);
+        MongoDbUser friend_1 = new MongoDbUser("1111L");
+        user.setFriends(friends);
+
+        expect(template.findOne(isA(Query.class))).andReturn(user);
+        expect(template.get("1111L")).andReturn(friend_1);
+        replay(template);
+        List<Person> results = repo.findFriends(username);
+        assertNotNull(results.get(0));
+        assertThat(results.size(), is(equalTo(1)));
+
+    }
+
+
+    @Test
+    public void findFriends_appId() {
+        String username = "username";
+        String appId = "www.test.com";
+        String id = "2222L";
+        String userId = "1111L";
+        MongoDbUser user = new MongoDbUser(userId);
+        user.setUsername(username);
+        List<MongoDbPersonAssociation> friends = Lists.newLinkedList();
+        MongoDbPersonAssociation friend = new MongoDbPersonAssociation(id, FriendRequestStatus.ACCEPTED, MongoDbPersonAssociation.Direction.INCOMING);
+        friends.add(friend);
+        user.setFriends(friends);
+
+        Widget w = new WidgetImpl();
+        w.setUrl(appId);
+        Page page = new PageImpl();
+        page.setOwnerId(id);
+
+        List<Region> regions = Lists.newLinkedList();
+        Region r = new RegionImpl();
+        RegionWidget rw = new RegionWidgetImpl();
+        List<RegionWidget> regionWidgets = Lists.newLinkedList();
+        regionWidgets.add(rw);
+        r.setRegionWidgets(regionWidgets);
+        regions.add(r);
+        page.setRegions(regions);
+
+        List<Page> pages = Lists.newLinkedList();
+        pages.add(page);
+        List<String> ids = Lists.newArrayList();
+        ids.add(id);
+
+        expect(template.findOne(query(where("username").is(username)))).andReturn(user);
+        expect(template.get(id)).andReturn(new UserImpl(id));
+        replay(template);
+        expect(widgetOperations.findOne(isA(Query.class))).andReturn(w);
+        replay(widgetOperations);
+        expect(pageTemplate.find(query(where("ownerId").in(ids).and("regions").elemMatch(where("regionWidgets").elemMatch(where("widgetId").is(w.getId())))))).andReturn(pages);
+        replay(pageTemplate);
+
+
+        List<Person> results = repo.findFriends(username, appId);
+        assertThat(results.get(0).getId(), is(equalTo(id)));
+        assertThat(results.size(), is(equalTo(1)));
+    }
+
+    @Test
+    public void findFriendsWithFriend() {
+        String username = "follower";
+        String friendUsername = "followed";
+        MongoDbUser follower = new MongoDbUser("1111L");
+        MongoDbUser followed = new MongoDbUser("2222L");
+        MongoDbPersonAssociation friend = new MongoDbPersonAssociation("3333L", FriendRequestStatus.ACCEPTED, MongoDbPersonAssociation.Direction.INCOMING);
+        MongoDbPersonAssociation friend2 = new MongoDbPersonAssociation("4444L", FriendRequestStatus.ACCEPTED, MongoDbPersonAssociation.Direction.INCOMING);
+        List<MongoDbPersonAssociation> friends_follower = Lists.newLinkedList();
+        List<MongoDbPersonAssociation> friends_followed = Lists.newLinkedList();
+
+        friends_follower.add(friend);
+        friends_followed.add(friend);
+        friends_followed.add(friend2);
+        follower.setFriends(friends_follower);
+        followed.setFriends(friends_followed);
+
+        expect(template.findOne(isA(Query.class))).andReturn(follower);
+        expect(template.findOne(isA(Query.class))).andReturn(followed);
+        expect(template.get("3333L")).andReturn(follower);
+        replay(template);
+
+        List<Person> results = repo.findFriendsWithFriend(username, friendUsername);
+        assertThat(results.size(), is(equalTo(1)));
+
+    }
+
+    @Test
+    public void addFriend() {
+        String username = "Carol";
+        String friendUsername = "Amy";
+        MongoDbUser carol = new MongoDbUser("1111L");
+        MongoDbUser amy = new MongoDbUser("2222L");
+
+        List<MongoDbPersonAssociation> carols_friends = Lists.newArrayList();
+        MongoDbPersonAssociation friendC = new MongoDbPersonAssociation();
+        carols_friends.add(friendC);
+        List<MongoDbPersonAssociation> amys_friends = Lists.newArrayList();
+        MongoDbPersonAssociation friendA = new MongoDbPersonAssociation();
+        amys_friends.add(friendA);
+        carol.setFriends(carols_friends);
+        amy.setFriends(amys_friends);
+
+        expect(template.findOne(isA(Query.class))).andReturn(carol);
+        expect(template.findOne(isA(Query.class))).andReturn(amy);
+        expect(template.save(isA(MongoDbUser.class))).andReturn(amy);
+        expect(template.save(isA(MongoDbUser.class))).andReturn(carol);
+        replay(template);
+
+        boolean result = repo.addFriend(friendUsername, username);
+        assertTrue(result);
+    }
+
+    @Test
+    public void findFriendsAndRequests() {
+        HashMap<String, List<Person>> results;
+        String username = "username";
+        MongoDbUser user = new MongoDbUser();
+
+        List<MongoDbPersonAssociation> friends = Lists.newArrayList();
+        MongoDbPersonAssociation friend_accepted = new MongoDbPersonAssociation("1111L", FriendRequestStatus.ACCEPTED, MongoDbPersonAssociation.Direction.INCOMING);
+        MongoDbPersonAssociation friend_sent = new MongoDbPersonAssociation("2222L", FriendRequestStatus.SENT, MongoDbPersonAssociation.Direction.INCOMING);
+        MongoDbPersonAssociation friend_received = new MongoDbPersonAssociation("3333L", FriendRequestStatus.RECEIVED, MongoDbPersonAssociation.Direction.INCOMING);
+        MongoDbPersonAssociation friend_received2 = new MongoDbPersonAssociation("4444L", FriendRequestStatus.RECEIVED, MongoDbPersonAssociation.Direction.INCOMING);
+        MongoDbUser friend_a = new MongoDbUser("1111L");
+        MongoDbUser friend_s = new MongoDbUser("2222L");
+        MongoDbUser friend_r = new MongoDbUser("3333L");
+        MongoDbUser friend_r2 = new MongoDbUser("4444L");
+
+        friends.add(friend_sent);
+        friends.add(friend_accepted);
+        friends.add(friend_received);
+        friends.add(friend_received2);
+        user.setFriends(friends);
+
+        expect(template.findOne(isA(Query.class))).andReturn(user);
+        expect(template.get("1111L")).andReturn(friend_a);
+        expect(template.findOne(isA(Query.class))).andReturn(user);
+        expect(template.get("2222L")).andReturn(friend_s);
+        expect(template.findOne(isA(Query.class))).andReturn(user);
+        expect(template.get("3333L")).andReturn(friend_r);
+        expect(template.get("4444L")).andReturn(friend_r2);
+        replay(template);
+
+        results = repo.findFriendsAndRequests(username);
+        assertNotNull(results);
+        assertThat(results.size(), equalTo(3));
+        assertThat(results.get("received").size(), is(equalTo(2)));
+    }
+
+    @Test
+    public void acceptFriendRequest() {
+        String username = "username";
+        String friendUsername = "friendUsername";
+        MongoDbUser carol = new MongoDbUser("1111L");
+        MongoDbUser amy = new MongoDbUser("2222L");
+
+        List<MongoDbPersonAssociation> carols_friends = Lists.newArrayList();
+        MongoDbPersonAssociation friendA = new MongoDbPersonAssociation("1111L", FriendRequestStatus.SENT, MongoDbPersonAssociation.Direction.OUTGOING);
+        carols_friends.add(friendA);
+        List<MongoDbPersonAssociation> amys_friends = Lists.newArrayList();
+        MongoDbPersonAssociation friendC = new MongoDbPersonAssociation("2222L", FriendRequestStatus.RECEIVED, MongoDbPersonAssociation.Direction.INCOMING);
+
+        amys_friends.add(friendC);
+        carol.setFriends(carols_friends);
+        amy.setFriends(amys_friends);
+
+        expect(template.findOne(isA(Query.class))).andReturn(carol);
+        expect(template.findOne(isA(Query.class))).andReturn(amy);
+        expect(template.save(isA(MongoDbUser.class))).andReturn(carol);
+        expect(template.save(isA(MongoDbUser.class))).andReturn(amy);
+        replay(template);
+
+        boolean result = repo.acceptFriendRequest(friendUsername, username);
+        assertTrue(result);
+
+    }
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbPortalPreferenceRepositoryTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbPortalPreferenceRepositoryTest.java
new file mode 100644
index 0000000..f3ef60d
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbPortalPreferenceRepositoryTest.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.rave.portal.model.MongoDbPortalPreference;
+import org.apache.rave.portal.model.PortalPreference;
+import org.apache.rave.portal.model.conversion.HydratingConverterFactory;
+import org.apache.rave.portal.model.impl.PortalPreferenceImpl;
+import org.apache.rave.portal.repository.util.CollectionNames;
+import org.apache.rave.util.CollectionUtils;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.data.mongodb.core.MongoOperations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.apache.rave.portal.repository.util.CollectionNames.PREFERENCE_COLLECTION;
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+/**
+ * User: DSULLIVAN
+ * Date: 12/6/12
+ * Time: 8:01 AM
+ */
+public class MongoDbPortalPreferenceRepositoryTest {
+    private MongoDbPortalPreferenceRepository preferenceRepository;
+    private MongoOperations template;
+    private HydratingConverterFactory converter;
+
+    @Before
+    public void setup(){
+        preferenceRepository = new MongoDbPortalPreferenceRepository();
+        template = createMock(MongoOperations.class);
+        converter = createMock(HydratingConverterFactory.class);
+        preferenceRepository.setConverter(converter);
+        preferenceRepository.setTemplate(template);
+    }
+
+    @Test
+    public void getAll_Valid(){
+        List<PortalPreferenceImpl> found = new ArrayList<PortalPreferenceImpl>();
+        expect(template.findAll(preferenceRepository.CLASS, CollectionNames.PREFERENCE_COLLECTION)).andReturn(found);
+        replay(template);
+
+        assertThat(CollectionUtils.<PortalPreference>toBaseTypedList(found), is(sameInstance(preferenceRepository.getAll())));
+    }
+
+    @Test
+    public void getByKey_Valid(){
+        String key = "key";
+        PortalPreferenceImpl found = new PortalPreferenceImpl();
+        expect(template.findOne(query(where("key").is(key)), preferenceRepository.CLASS, CollectionNames.PREFERENCE_COLLECTION)).andReturn(found);
+        replay(template);
+
+        assertThat(found, is(sameInstance(preferenceRepository.getByKey(key))));
+    }
+
+    @Test
+    public void getType(){
+        assertThat((Class<PortalPreferenceImpl>)(preferenceRepository.getType()), is(equalTo(PortalPreferenceImpl.class)));
+    }
+
+    @Test
+    public void get_Valid(){
+        String id = "123";
+        PortalPreference found = new PortalPreferenceImpl();
+        expect(template.findById(id, preferenceRepository.CLASS, CollectionNames.PREFERENCE_COLLECTION)).andReturn((PortalPreferenceImpl)found);
+        replay(template);
+
+        assertThat(found, is(sameInstance(preferenceRepository.get(id))));
+    }
+
+    @Test
+    public void save_Valid(){
+        PortalPreference item = new PortalPreferenceImpl();
+        item.setKey("123");
+        PortalPreference fromDb = new MongoDbPortalPreference();
+        ((MongoDbPortalPreference)fromDb).setId("123");
+        PortalPreference converted = new MongoDbPortalPreference();
+        expect(converter.convert(item, PortalPreference.class)).andReturn(converted);
+        expect(template.findOne(query(where("key").is("123")), preferenceRepository.CLASS, CollectionNames.PREFERENCE_COLLECTION)).andReturn((MongoDbPortalPreference)fromDb);
+        template.save(converted, CollectionNames.PREFERENCE_COLLECTION);
+        expectLastCall();
+        converter.hydrate(converted, PortalPreference.class);
+        expectLastCall();
+        replay(template, converter);
+
+        PortalPreference result = preferenceRepository.save(item);
+        assertNotNull(((MongoDbPortalPreference) converted).getId());
+        assertThat(result, is(sameInstance(converted)));
+    }
+
+    @Test
+    public void save_Null(){
+        PortalPreference item = new PortalPreferenceImpl();
+        item.setKey("123");
+        PortalPreference converted = new MongoDbPortalPreference();
+        expect(template.findOne(query(where("key").is("123")), preferenceRepository.CLASS, CollectionNames.PREFERENCE_COLLECTION)).andReturn(null);
+        expect(converter.convert(item, PortalPreference.class)).andReturn(converted);
+        template.save(converted, PREFERENCE_COLLECTION);
+        expectLastCall();
+        converter.hydrate(converted, PortalPreference.class);
+        expectLastCall();
+        replay(template, converter);
+
+        PortalPreference result = preferenceRepository.save(item);
+        assertThat(result, is(sameInstance(converted)));
+    }
+
+    @Test
+    public void delete_Valid(){
+        PortalPreference item = new PortalPreferenceImpl();
+        item.setKey("123");
+        PortalPreference found = new PortalPreferenceImpl();
+        expect(template.findOne(query(where("key").is("123")), preferenceRepository.CLASS, CollectionNames.PREFERENCE_COLLECTION)).andReturn((PortalPreferenceImpl)found);
+        template.remove(found, CollectionNames.PREFERENCE_COLLECTION);
+        expectLastCall();
+        replay(template);
+
+        preferenceRepository.delete(item);
+
+        verify(template);
+    }
+}
+
+
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbRegionRepositoryTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbRegionRepositoryTest.java
new file mode 100644
index 0000000..30d16c2
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbRegionRepositoryTest.java
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import com.google.common.collect.Lists;
+import org.apache.rave.portal.model.Page;
+import org.apache.rave.portal.model.Region;
+import org.apache.rave.portal.model.impl.PageImpl;
+import org.apache.rave.portal.model.impl.RegionImpl;
+import org.apache.rave.portal.repository.MongoPageOperations;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+
+import java.util.List;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Test for MongoDb Region Repository
+ */
+public class MongoDbRegionRepositoryTest {
+
+    private MongoPageOperations template;
+    private MongoDbRegionRepository repo;
+
+    @Before
+    public void setUp(){
+        template = createMock(MongoPageOperations.class);
+        repo = new MongoDbRegionRepository();
+        repo.setTemplate(template);
+
+    }
+
+    @Test
+    public void get(){
+        String id = "1111L";
+        Page page = new PageImpl("1234L");
+        List<Region> regions = Lists.newArrayList();
+        Region region = new RegionImpl(id);
+        regions.add(region);
+        page.setRegions(regions);
+
+        expect( template.findOne(new Query(Criteria.where("regions").elemMatch(Criteria.where("_id").is(id))))).andReturn(page);
+        replay(template);
+
+        Region result = repo.get(id);
+        assertNotNull(result);
+        assertThat(result, is(equalTo(region)));
+        assertThat(result.getId(), equalTo(id));
+
+    }
+
+    @Test
+    public void get_null(){
+        Page page = new PageImpl("1234L");
+        List<Region> regions = Lists.newArrayList();
+        Region region = new RegionImpl("1111L");
+        regions.add(region);
+        page.setRegions(regions);
+
+        expect(template.findOne(new Query(Criteria.where("regions").elemMatch(Criteria.where("_id").is("2222L"))))).andReturn(page);
+        replay(template);
+
+        Region result = repo.get("2222L");
+        assertNull(result);
+
+    }
+
+    @Test
+    public void save(){
+        Page page = new PageImpl("1234L");
+        List<Region> regions = Lists.newArrayList();
+        Region item = new RegionImpl("1111L");
+        regions.add(item);
+        page.setRegions(regions);
+
+        expect(template.findOne(new Query(Criteria.where("regions").elemMatch(Criteria.where("_id").is("1111L"))))).andReturn(page);
+        expect(template.save(isA(Page.class))).andReturn(page);
+        replay(template);
+
+        Region result = repo.save(item);
+        assertThat(result.getId(), is(equalTo("1111L")));
+        assertThat(result, is(sameInstance(item)));
+
+    }
+
+    @Test
+    public void save_null(){
+        Page page = new PageImpl("1234L");
+        List<Region> regions = Lists.newArrayList();
+        Region item = new RegionImpl();
+        item.setPage(page);
+        regions.add(item);
+        page.setRegions(regions);
+
+        expect(template.get("1234L")).andReturn(page);
+        expect(template.save(isA(Page.class))).andReturn(page);
+        replay(template);
+
+        Region result = repo.save(item);
+        assertNull(result.getId());
+
+    }
+
+    @Test
+     public void delete(){
+        Page page = new PageImpl("1234L");
+        List<Region> regions = Lists.newArrayList();
+        Region item = new RegionImpl("1111L");
+        regions.add(item);
+        page.setRegions(regions);
+
+        expect(template.findOne(new Query(Criteria.where("regions").elemMatch(Criteria.where("_id").is("1111L"))))).andReturn(page);
+        expect(template.save(isA(Page.class))).andReturn(page);
+        replay(template);
+
+        repo.delete(item);
+
+    }
+
+    @Test (expected = IllegalStateException.class)
+    public void delete_null(){
+        Page page = new PageImpl("1234L");
+        List<Region> regions = Lists.newArrayList();
+        Region item = new RegionImpl();
+        regions.add(item);
+        page.setRegions(regions);
+
+        repo.delete(item);
+    }
+
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbRegionWidgetRepositoryTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbRegionWidgetRepositoryTest.java
new file mode 100644
index 0000000..d17cdad
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbRegionWidgetRepositoryTest.java
@@ -0,0 +1,330 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.rave.portal.model.MongoDbPage;
+import org.apache.rave.portal.model.Page;
+import org.apache.rave.portal.model.Region;
+import org.apache.rave.portal.model.RegionWidget;
+import org.apache.rave.portal.model.impl.PageImpl;
+import org.apache.rave.portal.model.impl.RegionImpl;
+import org.apache.rave.portal.model.impl.RegionWidgetImpl;
+import org.apache.rave.portal.repository.MongoPageOperations;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.springframework.data.mongodb.core.query.Query;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.junit.Assert.*;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+
+/**
+ * User: DSULLIVAN
+ * Date: 12/6/12
+ * Time: 9:17 AM
+ */
+public class MongoDbRegionWidgetRepositoryTest {
+    private MongoDbRegionWidgetRepository widgetRepository;
+    private MongoPageOperations template;
+
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
+    @Before
+    public void setup() {
+        widgetRepository = new MongoDbRegionWidgetRepository();
+        template = createMock(MongoPageOperations.class);
+        widgetRepository.setTemplate(template);
+    }
+
+    @Test
+    public void getType_Valid() {
+        assertThat((Class)widgetRepository.getType(), is(equalTo((Class)RegionWidgetImpl.class)));
+    }
+
+    @Test
+    public void get_DifferentId() {
+        String id = "234";
+        Page page = new PageImpl();
+        Region region = new RegionImpl();
+        RegionWidgetImpl widget = new RegionWidgetImpl();
+        widget.setId("123");
+        page.setRegions(Arrays.asList(region));
+        region.setPage(page);
+        region.setRegionWidgets(Arrays.<RegionWidget>asList(widget));
+        widget.setRegion(region);
+
+        expect(template.findOne(new Query(where("regions").elemMatch(where("regionWidgets").elemMatch(where("_id").is(id)))))).andReturn(page);
+        replay(template);
+        RegionWidget result = widgetRepository.get(id);
+        assertNull(result);
+
+    }
+
+    @Test
+    public void get_Valid() {
+        String id = "123";
+        Page found = new MongoDbPage();
+        Region region = new RegionImpl();
+        found.setRegions(Arrays.asList(region));
+        RegionWidgetImpl widget = new RegionWidgetImpl();
+        region.setRegionWidgets(Arrays.<RegionWidget>asList(widget));
+        widget.setId("123");
+        expect(template.findOne(new Query(where("regions").elemMatch(where("regionWidgets").elemMatch(where("_id").is(id)))))).andReturn(found);
+        replay(template);
+
+        assertThat(widget, is(sameInstance(widgetRepository.get(id))));
+    }
+
+    @Test
+    public void get_Null() {
+        String id = "321";
+        Page found = new MongoDbPage();
+        found.setRegions(new ArrayList<Region>());
+        expect(template.findOne(new Query(where("regions").elemMatch(where("regionWidgets").elemMatch(where("_id").is(id)))))).andReturn(found);
+        replay(template);
+        assertNull(widgetRepository.get(id));
+    }
+
+    @Test
+    public void save_Id_Valid() {
+        RegionWidgetImpl widget = new RegionWidgetImpl();
+        RegionWidgetImpl replaced = new RegionWidgetImpl();
+
+        String id = "123";
+        widget.setId(id);
+        replaced.setId(id);
+        replaced.setCollapsed(true);
+        Page parent = new PageImpl();
+        Region region = new RegionImpl();
+        List<Region> regions = new ArrayList<Region>();
+        regions.add(region);
+        List<RegionWidget> regionWidgets = new ArrayList<RegionWidget>();
+        regionWidgets.add(replaced);
+        parent.setRegions(regions);
+        region.setRegionWidgets(regionWidgets);
+
+        expect(template.findOne(new Query(where("regions").elemMatch(where("regionWidgets").elemMatch(where("_id").is(id)))))).andReturn(parent);
+        expect(template.save(parent)).andReturn(parent);
+        replay(template);
+
+        RegionWidget savedWidget = widgetRepository.save(widget);
+
+        assertTrue(region.getRegionWidgets().contains(widget));
+        assertFalse(region.getRegionWidgets().contains(replaced));
+        assertThat(savedWidget, is(sameInstance((RegionWidget)widget)));
+    }
+
+    @Test
+    public void save_Id_Valid_Page_Null() {
+        RegionWidgetImpl item = new RegionWidgetImpl();
+        String id = "123";
+        item.setId(id);
+        Page page = new PageImpl();
+        page.setRegions(new ArrayList<Region>());
+
+        expect(template.findOne(new Query(where("regions").elemMatch(where("regionWidgets").elemMatch(where("_id").is(id)))))).andReturn(page);
+        replay(template);
+
+        thrown.expect(IllegalStateException.class);
+        thrown.expectMessage("Widget does not exist in parent page regions");
+
+        widgetRepository.save(item);
+    }
+
+    @Test
+    public void save_Id_Null_Page_Valid_Regions_Valid() {
+        RegionWidgetImpl widget = new RegionWidgetImpl();
+
+        RegionImpl region = new RegionImpl();
+        Page page = new PageImpl();
+        String id = "321";
+        page.setId(id);
+        List<Region> regions = new ArrayList<Region>();
+        regions.add(region);
+        page.setRegions(regions);
+        region.setPage(page);
+        region.setId(id);
+        widget.setRegion(region);
+        List<RegionWidget> widgets = new ArrayList<RegionWidget>();
+        widgets.add(widget);
+        region.setRegionWidgets(widgets);
+
+        expect(template.get(id)).andReturn(page);
+        expect(template.save(page)).andReturn(page);
+        replay(template);
+
+        RegionWidget returned = widgetRepository.save(widget);
+        assertThat(returned, is(sameInstance((RegionWidget)widget)));
+    }
+
+    @Test
+    public void save_Id_Null_Page_Valid_Regions_Valid_Diff_Id() {
+        RegionWidget item = new RegionWidgetImpl();
+        RegionImpl region = new RegionImpl();
+        item.setRegion(region);
+        Page item_Page = new PageImpl();
+        region.setPage(item_Page);
+        item_Page.setId("3333");
+        region.setId("2222");
+
+        Page page = new PageImpl();
+        ArrayList<Region> regions = new ArrayList<Region>();
+        regions.add(new RegionImpl());
+        page.setRegions(regions);
+        expect(template.get(item.getRegion().getPage().getId())).andReturn(page);
+        replay(template);
+
+        thrown.expect(IllegalStateException.class);
+        thrown.expectMessage("Unable to find parent for page");
+
+        widgetRepository.save(item);
+    }
+
+    @Test
+    public void save_Id_Null_Page_Null_Region_Null() {
+        RegionWidget widget = new RegionWidgetImpl();
+
+        thrown.expect(IllegalStateException.class);
+        thrown.expectMessage("Unable to find page for region");
+
+        widgetRepository.save(widget);
+    }
+
+    @Test
+    public void save_Id_Null_Page_Null_Region_Valid_Page_Null() {
+        RegionWidget widget = new RegionWidgetImpl();
+        Region region = new RegionImpl();
+        widget.setRegion(region);
+
+        thrown.expect(IllegalStateException.class);
+        thrown.expectMessage("Unable to find page for region");
+
+        widgetRepository.save(widget);
+    }
+
+    @Test
+    public void save_Id_Null_Page_Null_Region_Valid_Page_Valid_Id_Null() {
+        RegionWidget widget = new RegionWidgetImpl();
+        Region region = new RegionImpl();
+        widget.setRegion(region);
+        Page page = new PageImpl();
+        region.setPage(page);
+
+        thrown.expect(IllegalStateException.class);
+        thrown.expectMessage("Unable to find page for region");
+
+        widgetRepository.save(widget);
+    }
+
+    @Test
+    public void save_Id_Null_Page_Valid_Region_Null() {
+        RegionWidget item = new RegionWidgetImpl();
+        Region region = new RegionImpl();
+        item.setRegion(region);
+        String id = "123";
+        Page page = new PageImpl();
+        region.setPage(page);
+        page.setId(id);
+        page.setRegions(new ArrayList<Region>());
+
+        thrown.expect(IllegalStateException.class);
+        thrown.expectMessage("Unable to find parent for page");
+
+        expect(template.get(id)).andReturn(page);
+        replay(template);
+
+        widgetRepository.save(item);
+    }
+
+    @Test
+    public void delete_Valid() {
+        RegionWidgetImpl widget = new RegionWidgetImpl();
+        String id = "123";
+        widget.setId(id);
+        Page found = new PageImpl();
+        Region region = new RegionImpl();
+        List<RegionWidget> regionWidgets = new ArrayList<RegionWidget>();
+        regionWidgets.add(widget);
+        List<Region> regions = new ArrayList<Region>();
+        regions.add(region);
+        found.setRegions(regions);
+        region.setRegionWidgets(regionWidgets);
+
+        expect(template.findOne(new Query(where("regions").elemMatch(where("regionWidgets").elemMatch(where("_id").is(id)))))).andReturn(found);
+        expect(template.save(found)).andReturn(null);
+        replay(template);
+
+        widgetRepository.delete(widget);
+
+        assertFalse(region.getRegionWidgets().contains(widget));
+        verify(template);
+    }
+
+    @Test
+    public void delete_Null() {
+        RegionWidgetImpl item = new RegionWidgetImpl();
+        String id = "123";
+        item.setId(id);
+        Page page = new PageImpl();
+        page.setRegions(new ArrayList<Region>());
+
+        expect(template.findOne(new Query(where("regions").elemMatch(where("regionWidgets").elemMatch(where("_id").is(id)))))).andReturn(page);
+        replay(template);
+
+        thrown.expect(IllegalStateException.class);
+        thrown.expectMessage("Widget does not exist in parent page regions");
+
+        widgetRepository.delete(item);
+    }
+
+    @Test
+    public void delete_DifferentId() {
+        RegionWidgetImpl widget = new RegionWidgetImpl();
+        Region region = new RegionImpl();
+        Page page = new PageImpl();
+        page.setRegions(Arrays.asList(region));
+        region.setRegionWidgets(Arrays.<RegionWidget>asList(widget));
+        widget.setId("345345");
+
+        RegionWidgetImpl item = new RegionWidgetImpl();
+        String id = "4344";
+        item.setId(id);
+
+        expect(template.findOne(new Query(where("regions").elemMatch(where("regionWidgets").elemMatch(where("_id").is(id)))))).andReturn(page);
+        replay(template);
+
+        thrown.expect(IllegalStateException.class);
+        thrown.expectMessage("Widget does not exist in parent page regions");
+
+        widgetRepository.delete(item);
+
+    }
+
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbTagRepositoryTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbTagRepositoryTest.java
new file mode 100644
index 0000000..ae754ae
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbTagRepositoryTest.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import com.google.common.collect.Lists;
+import org.apache.rave.portal.model.Tag;
+import org.apache.rave.portal.model.impl.TagImpl;
+import org.apache.rave.portal.repository.MongoTagOperations;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Test for MongoDb Tag Repository class
+ */
+public class MongoDbTagRepositoryTest {
+
+    private MongoTagOperations tagTemplate;
+    private MongoDbTagRepository repo;
+
+    @Before
+    public void setUp(){
+        tagTemplate = createMock(MongoTagOperations.class);
+        repo = new MongoDbTagRepository();
+        repo.setWidgetTemplate(tagTemplate);
+
+    }
+
+    @Test
+    public void getAll(){
+        List<Tag> tags = Arrays.<Tag>asList(new TagImpl(), new TagImpl());
+
+        expect(tagTemplate.find(new Query())).andReturn(tags);
+        replay(tagTemplate);
+
+        List<Tag> result = repo.getAll();
+        assertNotNull(result);
+        assertThat(result.size(), is(equalTo(tags.size())));
+
+    }
+
+    @Test
+    public void countAll(){
+
+        expect(tagTemplate.count(new Query())).andReturn(2L);
+        replay(tagTemplate);
+
+        int result = repo.getCountAll();
+        assertThat(result, is(equalTo(2)));
+
+    }
+
+    @Test
+    public void getAll_null(){
+
+        expect(tagTemplate.find(new Query())).andReturn(Lists.<Tag>newArrayList());
+        replay(tagTemplate);
+
+        List<Tag> result = repo.getAll();
+        assertThat(result.size(), is(equalTo(0)));
+
+    }
+
+    @Test
+    public void getByKeyword() {
+        String keyword = "key";
+        Tag t = new TagImpl("1", keyword);
+        expect(tagTemplate.findOne(Query.query(Criteria.where("keyword").is(keyword)))).andReturn(t);
+        replay(tagTemplate);
+
+        Tag fromRepo = repo.getByKeyword(keyword);
+        assertThat(fromRepo.getKeyword(), is(equalTo(keyword)));
+    }
+
+    @Test
+    public void get() {
+        String keyword = "key";
+        String id = "1";
+        Tag t = new TagImpl(id, keyword);
+        expect(tagTemplate.get(id)).andReturn(t);
+        replay(tagTemplate);
+
+        Tag fromRepo = repo.get(id);
+        assertThat(fromRepo.getId(), is(equalTo(id)));
+        assertThat(fromRepo.getKeyword(), is(equalTo(keyword)));
+    }
+
+    @Test
+    public void save(){
+        String keyword = "KEYWORD";
+        Tag tag = new TagImpl("ID", keyword);
+        expect(tagTemplate.count(Query.query(Criteria.where("keyword").is(keyword)))).andReturn(0L);
+        expect(tagTemplate.save(tag)).andReturn(tag);
+        replay(tagTemplate);
+        Tag returned = repo.save(tag);
+        verify(tagTemplate);
+        assertThat(returned, is(sameInstance(tag)));
+    }
+
+    @Test
+    public void save_more(){
+        String keyword = "KEYWORD";
+        Tag tag = new TagImpl("ID", keyword);
+        expect(tagTemplate.count(Query.query(Criteria.where("keyword").is(keyword)))).andReturn(1L);
+        replay(tagTemplate);
+        Tag returned = repo.save(tag);
+        verify(tagTemplate);
+        assertThat(returned, is(sameInstance(tag)));
+    }
+
+    @Test
+    public void delete(){
+        String id ="id";
+        Tag tag = new TagImpl(id, "keyword");
+        tagTemplate.remove(Query.query(Criteria.where("_id").is(id)));
+        expectLastCall();
+        replay(tagTemplate);
+
+        repo.delete(tag);
+        verify(tagTemplate);
+
+    }
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbUserRepositoryTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbUserRepositoryTest.java
new file mode 100644
index 0000000..09eaef6
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbUserRepositoryTest.java
@@ -0,0 +1,192 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import com.google.common.collect.Sets;
+import org.apache.rave.portal.model.MongoDbUser;
+import org.apache.rave.portal.model.User;
+import org.apache.rave.portal.model.impl.UserImpl;
+import org.apache.rave.portal.repository.MongoUserOperations;
+import org.apache.rave.portal.repository.StatisticsAggregator;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.data.mongodb.core.query.Query;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import static org.easymock.EasyMock.*;
+import static org.easymock.EasyMock.isA;
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+/**
+ * User: DSULLIVAN
+ * Date: 12/6/12
+ * Time: 2:13 PM
+ */
+public class MongoDbUserRepositoryTest {
+    private MongoDbUserRepository userRepository;
+    private MongoUserOperations template;
+    private StatisticsAggregator aggregator;
+
+    @Before
+    public void setup() {
+        userRepository = new MongoDbUserRepository();
+        template = createMock(MongoUserOperations.class);
+        aggregator = createMock(StatisticsAggregator.class);
+        userRepository.setTemplate(template);
+        userRepository.setStatisticsAggregator(aggregator);
+    }
+
+    @Test
+    public void getByUsername_Valid() {
+        String username = "username";
+        User found = new UserImpl();
+        expect(template.findOne(query(where("username").is(username)))).andReturn(found);
+        replay(template);
+        assertThat(found, is(sameInstance(userRepository.getByUsername(username))));
+    }
+
+    @Test
+    public void getByUserEmail_Valid(){
+        String userEmail = "userEmail";
+        User found = new UserImpl();
+        expect(template.findOne(query(where("email").is(userEmail)))).andReturn(found);
+        replay(template);
+        assertThat(found, is(sameInstance(userRepository.getByUserEmail(userEmail))));
+    }
+
+    @Test
+    public void getByOpenId_Valid(){
+        String openId = "openId";
+        User found = new UserImpl();
+        expect(template.findOne(query(where("openId").is(openId)))).andReturn(found);
+        replay(template);
+        assertThat(found, is(sameInstance(userRepository.getByOpenId(openId))));
+    }
+
+    @Test
+    public void getLimitedList_Valid(){
+        int offset = 234;
+        int pageSize = 123;
+        List<User> found = new ArrayList<User>();
+        expect(template.find(isA(Query.class))).andReturn(found);
+        replay(template);
+        assertThat(found, is(sameInstance(userRepository.getLimitedList(offset, pageSize))));
+    }
+
+    @Test
+    public void getCountAll_Valid(){
+        long doubleOseven = 007;
+        expect(template.count(new Query())).andReturn(doubleOseven);
+        replay(template);
+        assertThat((int)doubleOseven, is(sameInstance(userRepository.getCountAll())));
+    }
+
+    @Test
+    public void findByUsernameOrEmail_Valid(){
+        String searchTerm = "searchTerm";
+        int offset = 5;
+        int pageSize = 3;
+        List<User> found = new ArrayList<User>();
+        expect(template.find(isA(Query.class))).andReturn(found);
+        replay(template);
+
+        assertThat(found, is(sameInstance(userRepository.findByUsernameOrEmail(searchTerm,offset,pageSize))));
+    }
+
+    @Test
+    public void getCountByUsernameOrEmail_Valid(){
+        String searchTerm = "searchTerm";
+        long count = 70;
+        expect(template.count(isA(Query.class))).andReturn(count);
+        replay(template);
+
+        assertThat((int)count, is(sameInstance(userRepository.getCountByUsernameOrEmail(searchTerm))));
+    }
+
+    @Test
+    public void getAllByAddedWidget_Valid(){
+        String widgetId = "123";
+        String ownerId = "ABC";
+        Set<String> userIds = Sets.newHashSet();
+        userIds.add(ownerId);
+
+        expect(aggregator.getUsersWithWidget(widgetId)).andReturn(userIds);
+        UserImpl owner = new UserImpl(ownerId);
+        expect(template.get(ownerId)).andReturn(owner);
+        replay(template, aggregator);
+
+        List<User> users = userRepository.getAllByAddedWidget(widgetId);
+
+        assertTrue(users.size() == 1);
+        assertTrue(users.contains(owner));
+    }
+
+    @Test
+    public void getByForgotPasswordHash_Valid(){
+        String hash = "hashbrown";
+        User found = new UserImpl();
+        expect(template.findOne(query(where("forgotPasswordHash").is(hash)))).andReturn(found);
+        replay(template);
+
+        assertThat(found, is(sameInstance(userRepository.getByForgotPasswordHash(hash))));
+    }
+
+    @Test
+    public void getType_Valid(){
+        assertThat((Class)userRepository.getType(), is(equalTo((Class)MongoDbUser.class)));
+    }
+
+    @Test
+    public void get_Valid(){
+        String id = "123";
+        User user = new UserImpl();
+        expect(template.get(id)).andReturn(user);
+        replay(template);
+        assertThat(user, is(sameInstance(userRepository.get(id))));
+    }
+
+    @Test
+    public void save_Valid(){
+        User item = new UserImpl();
+        User saved = new UserImpl();
+        expect(template.save(item)).andReturn(saved);
+        replay(template);
+        assertThat(saved, is(sameInstance(userRepository.save(item))));
+    }
+
+    @Test
+    public void delete_Valid(){
+        User item = new UserImpl();
+        ((UserImpl)item).setId("777");
+        template.remove(query(where("_id").is(item.getId())));
+        expectLastCall();
+        replay(template);
+
+        userRepository.delete(item);
+        verify(template);
+    }
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbWidgetCommentRepositoryTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbWidgetCommentRepositoryTest.java
new file mode 100644
index 0000000..4770196
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbWidgetCommentRepositoryTest.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import com.google.common.collect.Lists;
+import org.apache.rave.portal.model.Widget;
+import org.apache.rave.portal.model.WidgetComment;
+import org.apache.rave.portal.model.impl.WidgetCommentImpl;
+import org.apache.rave.portal.model.impl.WidgetImpl;
+import org.apache.rave.portal.repository.MongoWidgetOperations;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+/**
+ * Test for MongoDb Widget Comment Repository class
+ */
+public class MongoDbWidgetCommentRepositoryTest {
+
+    private MongoWidgetOperations template;
+    private MongoDbWidgetRepository repo;
+
+    @Before
+    public void setUp(){
+        template = createMock(MongoWidgetOperations.class);
+        repo = new MongoDbWidgetRepository();
+        repo.setTemplate(template);
+
+    }
+
+    @Test
+    public void deleteAll(){
+        String userId = "1234L";
+        List<Widget> widgets = Lists.newArrayList();
+        Widget w = new WidgetImpl();
+        List<WidgetComment> comments = Lists.newArrayList();
+        WidgetComment wc1 = new WidgetCommentImpl();
+        WidgetComment wc2 = new WidgetCommentImpl();
+        wc1.setUserId(userId);
+        wc2.setUserId(userId);
+        comments.add(wc1);
+        comments.add(wc2);
+        w.setComments(comments);
+        widgets.add(w);
+
+        expect(template.find(query(where("comments").elemMatch(where("userId").is(userId))))).andReturn(widgets);
+        expect(template.save(isA(Widget.class))).andReturn(w);
+        expect(template.find(query(where("comments").elemMatch(where("userId").is(userId))))).andReturn(widgets);
+        expect(template.save(isA(Widget.class))).andReturn(w);
+        replay(template);
+
+        int count = repo.deleteAllWidgetComments(userId);
+        assertThat(count, is(equalTo(2)));
+    }
+
+    @Test
+    public void deleteAll_zero(){
+        String userId = "1234L";
+        String userId_2 = "1111L";
+        List<Widget> widgets = Lists.newArrayList();
+        Widget w = new WidgetImpl();
+        List<WidgetComment> comments = Lists.newArrayList();
+        WidgetComment wc1 = new WidgetCommentImpl();
+        WidgetComment wc2 = new WidgetCommentImpl();
+        wc1.setUserId(userId_2);
+        wc2.setUserId(userId_2);
+        comments.add(wc1);
+        comments.add(wc2);
+        w.setComments(comments);
+        widgets.add(w);
+
+        expect(template.find(query(where("comments").elemMatch(where("userId").is(userId))))).andReturn(widgets);
+        replay(template);
+
+        int count = repo.deleteAllWidgetComments(userId);
+        assertThat(count, is(equalTo(0)));
+
+    }
+
+    @Test
+    public void get(){
+        String id = "1234L";
+        String widgetId = "321L";
+        List<WidgetComment> comments = Lists.newArrayList();
+        Widget widget = new WidgetImpl(widgetId);
+        WidgetComment wc = new WidgetCommentImpl(id);
+        comments.add(wc);
+        widget.setComments(comments);
+
+        expect(template.get(widgetId)).andReturn(widget);
+        replay(template);
+
+        WidgetComment result = repo.getCommentById(widgetId, id);
+        assertThat(result.getId(), is(equalTo(id)));
+    }
+
+    @Test
+    public void get_null(){
+        String id = "1234L";
+        String widgetId = "321L";
+        List<WidgetComment> comments = Lists.newArrayList();
+        Widget widget = new WidgetImpl(widgetId);
+        WidgetComment wc = new WidgetCommentImpl("1111L");
+        comments.add(wc);
+        widget.setComments(comments);
+
+        expect(template.get(widgetId)).andReturn(widget);
+        replay(template);
+
+        WidgetComment result = repo.getCommentById(widgetId, id);
+        assertNull(result);
+
+    }
+
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbWidgetRatingRepositoryTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbWidgetRatingRepositoryTest.java
new file mode 100644
index 0000000..7fbe6e2
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbWidgetRatingRepositoryTest.java
@@ -0,0 +1,283 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.rave.portal.model.Widget;
+import org.apache.rave.portal.model.WidgetRating;
+import org.apache.rave.portal.model.impl.WidgetImpl;
+import org.apache.rave.portal.model.impl.WidgetRatingImpl;
+import org.apache.rave.portal.repository.MongoWidgetOperations;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.junit.Assert.*;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+
+/**
+ * User: DSULLIVAN
+ * Date: 12/7/12
+ * Time: 1:24 PM
+ */
+public class MongoDbWidgetRatingRepositoryTest {
+    private MongoDbWidgetRepository ratingRepository;
+    private MongoWidgetOperations template;
+
+    @Before
+    public void setup() {
+        template = createMock(MongoWidgetOperations.class);
+        ratingRepository = new MongoDbWidgetRepository();
+        ratingRepository.setTemplate(template);
+    }
+
+    @Test
+    public void getByWidgetIdAndUserId_Valid(){
+        String widgetId = "222";
+        String userId = "333";
+        Widget widget = new WidgetImpl();
+        WidgetRating widgetRating = new WidgetRatingImpl();
+        widgetRating.setUserId(userId);
+        widget.setRatings(Arrays.asList(widgetRating));
+        expect(template.get(widgetId)).andReturn(widget);
+        replay(template);
+        assertThat(ratingRepository.getWidgetRatingsByWidgetIdAndUserId(widgetId, userId), is(sameInstance(widgetRating)));
+    }
+
+    @Test
+    public void getByWidgetIdAndUserId_Null(){
+        String widgetId = "222";
+        String userId = "333";
+        Widget widget = new WidgetImpl();
+        widget.setRatings(new ArrayList<WidgetRating>());
+        expect(template.get(widgetId)).andReturn(widget);
+        replay(template);
+        assertNull(ratingRepository.getWidgetRatingsByWidgetIdAndUserId(widgetId, userId));
+    }
+
+    @Test
+    public void getByWidgetIdAndUserId_Diff_Id(){
+        String widgetId = "222";
+        String userId = "333";
+        Widget widget = new WidgetImpl();
+        WidgetRating widgetRating = new WidgetRatingImpl();
+        widgetRating.setUserId("444");
+        widget.setRatings(Arrays.asList(widgetRating));
+        expect(template.get(widgetId)).andReturn(widget);
+        replay(template);
+        assertNull(ratingRepository.getWidgetRatingsByWidgetIdAndUserId(widgetId, userId));
+    }
+
+    @Test
+    public void deleteAll_Valid(){
+        String userId = "233";
+        List<Widget> widgets = new ArrayList<Widget>();
+        Widget delete = new WidgetImpl();
+        WidgetRating rating = new WidgetRatingImpl();
+        List<WidgetRating> ratings= new ArrayList<WidgetRating>();
+        ratings.add(rating);
+        delete.setRatings(ratings);
+        rating.setUserId(userId);
+        widgets.add(delete);
+        expect(template.find(query(where("ratings").elemMatch(where("userId").is(userId))))).andReturn(widgets);
+        expect(template.save(delete)).andReturn(null);
+        replay(template);
+
+        int count = ratingRepository.deleteAllWidgetRatings(userId);
+        assertFalse(ratings.contains(rating));
+        assertThat(count, is(1));
+    }
+
+    @Test
+    public void deleteAll_Diff_Id(){
+        String userId = "111";
+        Widget widget = new WidgetImpl();
+        List<Widget> widgets = Arrays.asList(widget);
+        WidgetRating rating = new WidgetRatingImpl();
+        rating.setUserId("222");
+        widget.setRatings(Arrays.asList(rating));
+        expect(template.find(query(where("ratings").elemMatch(where("userId").is(userId))))).andReturn(widgets);
+        replay(template);
+
+        int count = ratingRepository.deleteAllWidgetRatings(userId);
+        assertThat(count, is(0));
+    }
+
+    @Test
+    public void get_Valid(){
+        String id = "342";
+        String widgetId = "243";
+        Widget found = new WidgetImpl(widgetId);
+        WidgetRatingImpl widgetRating = new WidgetRatingImpl();
+        widgetRating.setId(id);
+        found.setRatings(Arrays.asList((WidgetRating) widgetRating));
+        expect(template.get(widgetId)).andReturn(found);
+        replay(template);
+
+        assertThat(ratingRepository.getRatingById(widgetId, id), is(sameInstance((WidgetRating)widgetRating)));
+    }
+
+    @Test
+    public void get_Null(){
+        String id = "123";
+        String widgetId = "1234";
+        Widget widget = new WidgetImpl();
+        expect(template.get(widgetId)).andReturn(widget);
+        replay(template);
+        widget.setRatings(new ArrayList<WidgetRating>());
+
+        assertNull(ratingRepository.getRatingById(widgetId, id));
+    }
+
+    @Test
+    public void get_Diff_Id(){
+        String widgetId="1234";
+        Widget widget = new WidgetImpl(widgetId);
+        String id = "555";
+        WidgetRatingImpl rating = new WidgetRatingImpl();
+        rating.setId("444");
+        widget.setRatings(Arrays.asList((WidgetRating) rating));
+        expect(template.get(widgetId)).andReturn(widget);
+        replay(template);
+
+        assertNull(ratingRepository.getRatingById(widgetId, id));
+    }
+
+    @Test
+    public void save_Id_Valid(){
+        WidgetRatingImpl item = new WidgetRatingImpl();
+        WidgetRatingImpl lookup = new WidgetRatingImpl();
+        String widgetId = "2134";
+        String userId = "3245";
+        String id = "3245";
+        int score = 838;
+        item.setUserId(userId);
+        item.setScore(score);
+        item.setId(id);
+        lookup.setId(id);
+        Widget widget = new WidgetImpl();
+        widget.setRatings(Arrays.asList((WidgetRating)lookup));
+
+        expect(template.get(widgetId)).andReturn(widget);
+        expect(template.save(widget)).andReturn(widget);
+        replay(template);
+
+        WidgetRating widgetRating = ratingRepository.updateWidgetRating(widgetId, item);
+
+        assertThat(item.getScore(), is(equalTo(lookup.getScore())));
+        assertThat(item.getUserId(), is(equalTo(lookup.getUserId())));
+        assertThat(item.getScore(), is(equalTo(lookup.getScore())));
+        assertThat(widgetRating, is(sameInstance((WidgetRating)lookup)));
+    }
+
+    @Test
+    public void save_Id_Null(){
+        WidgetRating item = new WidgetRatingImpl();
+        String widgetId = "5544";
+        Widget widget = new WidgetImpl();
+        widget.setRatings(new ArrayList<WidgetRating>());
+        expect(template.get(widgetId)).andReturn(widget);
+        expect(template.save(widget)).andReturn(widget);
+        replay(template);
+
+        WidgetRating widgetRating = ratingRepository.createWidgetRating(widgetId, item);
+        assertTrue(widget.getRatings().contains(item));
+        assertThat(widgetRating, is(sameInstance(item)));
+    }
+
+    @Test
+    public void save_Null(){
+        WidgetRatingImpl item = new WidgetRatingImpl();
+        Widget widget = new WidgetImpl();
+        widget.setRatings(new ArrayList<WidgetRating>());
+        String id = "123";
+        String widgetId = "321";
+        Widget saved = new WidgetImpl();
+        saved.setRatings(new ArrayList<WidgetRating>());
+        item.setId(id);
+        expect(template.get(widgetId)).andReturn(widget);
+        expect(template.save(widget)).andReturn(saved);
+        replay(template);
+
+        assertNull(ratingRepository.updateWidgetRating(widgetId, item));
+    }
+
+    @Test
+    public void save_Diff_Id(){
+        WidgetRating item = new WidgetRatingImpl();
+        String widgetId = "3333";
+        String itemId = "123";
+        ((WidgetRatingImpl)item).setId(itemId);
+        Widget widget = new WidgetImpl();
+        WidgetRating exist = new WidgetRatingImpl();
+        ((WidgetRatingImpl)exist).setId("4444");
+        widget.setRatings(Arrays.asList(exist));
+
+        expect(template.get(widgetId)).andReturn(widget);
+        expect(template.save(widget)).andReturn(widget);
+        replay(template);
+
+        assertNull(ratingRepository.updateWidgetRating(widgetId, item));
+    }
+
+    @Test
+    public void delete_Valid(){
+        WidgetRating item = new WidgetRatingImpl();
+        String widgetId = "387383";
+        String id = "234";
+        ((WidgetRatingImpl)item).setId(id);
+        Widget widget = new WidgetImpl();
+        ArrayList<WidgetRating> ratings = new ArrayList<WidgetRating>();
+        ratings.add(item);
+        widget.setRatings(ratings);
+        expect(template.get(widgetId)).andReturn(widget);
+        expect(template.save(widget)).andReturn(null);
+        replay(template);
+
+        ratingRepository.deleteWidgetRating(widgetId, item);
+        assertFalse(ratings.contains(item));
+        verify(template);
+    }
+
+    @Test
+    public void delete_Id_Not_Equals(){
+         WidgetRating item = new WidgetRatingImpl();
+        String widgetId = "32323";
+        ((WidgetRatingImpl)item).setId("333333");
+        Widget widget = new WidgetImpl();
+        WidgetRating exist = new WidgetRatingImpl();
+        ((WidgetRatingImpl)exist).setId("323");
+        widget.setRatings(Arrays.asList(exist));
+        expect(template.get(widgetId)).andReturn(widget);
+        expect(template.save(widget)).andReturn(null);
+        replay(template);
+
+        ratingRepository.deleteWidgetRating(widgetId, item);
+        verify(template);
+    }
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbWidgetRepositoryTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbWidgetRepositoryTest.java
new file mode 100644
index 0000000..0053fd5
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbWidgetRepositoryTest.java
@@ -0,0 +1,392 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+*  or more contributor license agreements.  See the NOTICE file
+*  distributed with this work for additional information
+*  regarding copyright ownership.  The ASF licenses this file
+*  to you under the Apache License, Version 2.0 (the
+*  "License"); you may not use this file except in compliance
+*  with the License.  You may obtain a copy of the License at
+*
+*    http://www.apache.org/licenses/LICENSE-2.0
+*
+*  Unless required by applicable law or agreed to in writing,
+*  software distributed under the License is distributed on an
+*  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+*  KIND, either express or implied.  See the License for the
+*  specific language governing permissions and limitations
+*  under the License.
+*/
+
+package org.apache.rave.portal.repository.impl;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.apache.rave.portal.model.*;
+import org.apache.rave.portal.model.impl.TagImpl;
+import org.apache.rave.portal.model.impl.UserImpl;
+import org.apache.rave.portal.model.impl.WidgetImpl;
+import org.apache.rave.portal.model.impl.WidgetRatingImpl;
+import org.apache.rave.portal.model.util.WidgetStatistics;
+import org.apache.rave.portal.repository.MongoWidgetOperations;
+import org.apache.rave.portal.repository.StatisticsAggregator;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.data.mongodb.core.query.Query;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+import static org.springframework.data.mongodb.core.query.Query.query;
+
+/**
+* Test for MongoDb Widget Repository class
+*/
+
+public class MongoDbWidgetRepositoryTest {
+
+    private MongoWidgetOperations template;
+    private StatisticsAggregator statsAggregator;
+    private MongoDbWidgetRepository repo;
+
+
+
+    @Before
+    public void setUp(){
+        template = createMock(MongoWidgetOperations.class);
+        statsAggregator = createMock(StatisticsAggregator.class);
+        repo = new MongoDbWidgetRepository();
+        repo.setTemplate(template);
+        repo.setStatsAggregator(statsAggregator);
+
+    }
+
+    @Test
+    public void getAll(){
+        List<Widget> widgets = Lists.newArrayList();
+        Widget w = new WidgetImpl();
+        w.setTitle("B");
+        Widget w2 = new WidgetImpl();
+        w.setTitle("A");
+        widgets.add(w);
+        widgets.add(w2);
+
+        expect(template.find(isA(Query.class))).andReturn(widgets);
+        replay(template);
+
+        List<Widget> result = repo.getAll();
+        assertThat(result.size(), is(equalTo(2)));
+        assertThat(result.get(0), is(equalTo(w)));
+
+    }
+
+    @Test
+    public void getLimitedList(){
+        int offset = 2;
+        int pageSize = 10;
+        List<Widget> widgets = Lists.newArrayList();
+        Widget w = new WidgetImpl();
+        w.setTitle("B");
+        Widget w2 = new WidgetImpl();
+        w.setTitle("A");
+        widgets.add(w);
+        widgets.add(w2);
+
+        expect(template.find(isA(Query.class))).andReturn(widgets);
+        replay(template);
+
+        List<Widget> result = repo.getLimitedList(offset, pageSize);
+        assertThat(result.size(), is(equalTo(2)));
+
+    }
+
+    @Test
+    public void getCountAll(){
+        long count = 0;
+
+        expect(template.count(isA(Query.class))).andReturn(count);
+        replay(template);
+
+        count = repo.getCountAll();
+        assertNotNull(count);
+    }
+
+    @Test
+    public void getByFreeTextSearch(){
+        int offset = 2;
+        int pageSize = 10;
+        String searchTerm = "test";
+        List<Widget> widgets = Lists.newArrayList();
+        Widget w = new WidgetImpl();
+        w.setTitle("A");
+        w.setDescription("test");
+        widgets.add(w);
+
+        expect(template.find(isA(Query.class))).andReturn(widgets);
+        replay(template);
+
+        List<Widget> result = repo.getByFreeTextSearch(searchTerm, offset, pageSize);
+        assertNotNull(result);
+        assertThat(result.size(), is(equalTo(1)));
+    }
+
+    @Test
+    public void getCountFreeTextSearch(){
+        long count = 0;
+        String searchTerm = "test";
+        List<Widget> widgets = Lists.newArrayList();
+        Widget w = new WidgetImpl();
+        Widget w2 = new WidgetImpl();
+        w.setTitle("A");
+        w.setDescription("test");
+        widgets.add(w);
+        widgets.add(w2);
+
+        expect(template.count(isA(Query.class))).andReturn(count);
+        replay(template);
+
+        count = repo.getCountFreeTextSearch(searchTerm);
+        assertNotNull(count);
+
+    }
+
+    @Test
+    public void getByStatus(){
+        int offset = 2;
+        int pageSize = 10;
+        List<Widget> widgets = Lists.newArrayList();
+        Widget w = new WidgetImpl();
+        w.setWidgetStatus(WidgetStatus.PUBLISHED);
+        Widget w2 = new WidgetImpl();
+        w2.setWidgetStatus(WidgetStatus.PREVIEW);
+        w.setTitle("A");
+        w.setDescription("test");
+        widgets.add(w);
+        widgets.add(w2);
+
+        expect(template.find(isA(Query.class))).andReturn(widgets);
+        replay(template);
+
+        List<Widget> result = repo.getByStatus(WidgetStatus.PUBLISHED, offset, pageSize);
+        assertNotNull(result);
+
+    }
+
+    @Test
+    public void getCountByStatus(){
+        long count = 0;
+        List<Widget> widgets = Lists.newArrayList();
+        Widget w = new WidgetImpl();
+        w.setWidgetStatus(WidgetStatus.PUBLISHED);
+        Widget w2 = new WidgetImpl();
+        w2.setWidgetStatus(WidgetStatus.PREVIEW);
+        w.setTitle("A");
+        w.setDescription("test");
+        widgets.add(w);
+        widgets.add(w2);
+
+        expect(template.count(isA(Query.class))).andReturn(count);
+        replay(template);
+
+        count = repo.getCountByStatus(WidgetStatus.PUBLISHED);
+        assertNotNull(count);
+
+    }
+
+    @Test
+    public void getByStatusAndTypeAndFreeTextSearch(){
+        int offset = 2;
+        int pageSize = 10;
+        String type = "type";
+        String searchTerm = "test" ;
+        List<Widget> widgets = Lists.newArrayList();
+        Widget w = new WidgetImpl();
+        w.setWidgetStatus(WidgetStatus.PUBLISHED);
+        Widget w2 = new WidgetImpl();
+        w2.setWidgetStatus(WidgetStatus.PREVIEW);
+        w.setTitle("A");
+        w.setDescription("test");
+        w.setType(type);
+        widgets.add(w);
+        widgets.add(w2);
+
+        expect(template.find(isA(Query.class))).andReturn(widgets);
+        replay(template);
+
+        List<Widget> result = repo.getByStatusAndTypeAndFreeTextSearch(WidgetStatus.PUBLISHED, type, searchTerm, offset, pageSize);
+        assertNotNull(result);
+
+    }
+
+    @Test
+    public void getByStatusAndTypeAndFreeTextSearch_null(){
+        int offset = 2;
+        int pageSize = 10;
+        String type = "type";
+        String searchTerm = "test" ;
+        List<Widget> widgets = Lists.newArrayList();
+        Widget w = new WidgetImpl();
+        Widget w2 = new WidgetImpl();
+        widgets.add(w);
+        widgets.add(w2);
+
+        expect(template.find(isA(Query.class))).andReturn(widgets);
+        replay(template);
+
+        List<Widget> result = repo.getByStatusAndTypeAndFreeTextSearch(WidgetStatus.PUBLISHED, type, searchTerm, offset, pageSize);
+        assertNotNull(result);
+
+    }
+
+    @Test
+    public void getCountByStatusAndTypeAndFreeText(){
+        long count = 0;
+        String type = "type";
+        String searchTerm = "test" ;
+        List<Widget> widgets = Lists.newArrayList();
+        Widget w = new WidgetImpl();
+        w.setWidgetStatus(WidgetStatus.PUBLISHED);
+        Widget w2 = new WidgetImpl();
+        w2.setWidgetStatus(WidgetStatus.PREVIEW);
+        w.setTitle("A");
+        w.setDescription("test");
+        widgets.add(w);
+        widgets.add(w2);
+
+        expect(template.count(isA(Query.class))).andReturn(count);
+        replay(template);
+
+        count = repo.getCountByStatusAndTypeAndFreeText(WidgetStatus.PUBLISHED, type, searchTerm);
+        assertNotNull(count);
+
+    }
+
+    @Test
+    public void getByOwmer(){
+        int offset = 2;
+        int pageSize = 10;
+        User owner = new UserImpl("1234L");
+        List<Widget> widgets = Lists.newArrayList();
+        Widget w = new WidgetImpl();
+        w.setOwnerId(owner.getId());
+        widgets.add(w);
+
+        expect(template.find(isA(Query.class))).andReturn(widgets);
+        replay(template);
+
+        List<Widget> result = repo.getByOwner(owner, offset, pageSize);
+        assertNotNull(result);
+    }
+
+    @Test
+    public void getcountByOwner(){
+        long count = 0;
+        int offset = 2;
+        int pageSize = 10;
+        String id = "1234L";
+        User owner = new UserImpl(id);
+        List<Widget> widgets = Lists.newArrayList();
+        Widget w = new WidgetImpl();
+        w.setOwnerId(id);
+        widgets.add(w);
+
+        expect(template.count(isA(Query.class))).andReturn(count);
+        replay(template);
+
+        count = repo.getCountByOwner(owner, offset, pageSize);
+        assertNotNull(count);
+    }
+
+    @Test
+    public void getByUrl(){
+        String widgetUrl = "www.test.com";
+        Widget widget = new WidgetImpl();
+        widget.setUrl(widgetUrl);
+
+        expect(template.findOne(new Query(where("url").is(widgetUrl)))).andReturn(widget);
+        replay(template);
+
+        Widget result = repo.getByUrl(widgetUrl);
+        assertThat(result, is(equalTo(widget)));
+        assertThat(result.getUrl(), is(equalTo(widgetUrl)));
+
+    }
+
+    @Test
+    public void getWidgetStatistics(){
+        String widget_id = "1111L";
+        String user_id = "2222L";
+
+        WidgetStatistics ws = new WidgetStatistics();
+
+        expect(statsAggregator.getWidgetStatistics(widget_id, user_id)).andReturn(ws);
+        replay(statsAggregator);
+
+        ws = repo.getWidgetStatistics(widget_id, user_id);
+        assertNotNull(ws);
+
+    }
+
+    @Test
+    public void getAllWidgetStatistics(){
+        String user_id = "2222L";
+        Map<String, WidgetStatistics> ws = Maps.newHashMap();
+
+        expect(statsAggregator.getAllWidgetStatistics(user_id)).andReturn(ws);
+        replay(statsAggregator);
+
+        ws = repo.getAllWidgetStatistics(user_id);
+        assertNotNull(ws);
+
+    }
+
+    @Test
+    public void getUserWidgetRatings(){
+        String userId = "1234L";
+        Map<String, WidgetRating> wr = Maps.newHashMap();
+        List<Widget> widgets = Lists.newArrayList();
+        List<WidgetRating> widget_ratings = Lists.newArrayList();
+        Widget widget = new WidgetImpl("1111L");
+        WidgetRating rating1 = new WidgetRatingImpl();
+        WidgetRating rating2 = new WidgetRatingImpl();
+        rating1.setUserId(userId);
+        rating2.setUserId("5555L");
+        widget_ratings.add(rating1);
+        widget_ratings.add(rating2);
+        widget.setRatings(widget_ratings);
+        widgets.add(widget);
+        Query q = query(where("ratings").elemMatch(where("userId").is(userId)));
+
+        expect(template.find(q)).andReturn(widgets);
+        replay(template);
+
+        wr = repo.getUsersWidgetRatings(userId);
+        assertNotNull(wr);
+    }
+
+    @Test
+    public void getWidgetByTag(){
+        int offset = 2;
+        int pagesize = 10;
+        String tagKeyword = "test";
+        List<Widget> widgets = Lists.newArrayList();
+        Widget widget = new WidgetImpl();
+        Tag tag = new TagImpl();
+        expect(template.find(isA(Query.class))).andReturn(widgets);
+        replay(template);
+    }
+
+    public void setTemplate(MongoWidgetOperations template) {
+        this.template = template;
+    }
+
+    public void setStatsAggregator(StatisticsAggregator statsAggregator) {
+        this.statsAggregator = statsAggregator;
+    }
+
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbWidgetTagRepositoryTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbWidgetTagRepositoryTest.java
new file mode 100644
index 0000000..c7a2a9f
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MongoDbWidgetTagRepositoryTest.java
@@ -0,0 +1,211 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import org.apache.rave.portal.repository.MongoWidgetOperations;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.ExpectedException;
+
+import static org.easymock.EasyMock.createMock;
+
+/**
+ * User: DSULLIVAN
+ * Date: 12/7/12
+ * Time: 2:46 PM
+ */
+public class MongoDbWidgetTagRepositoryTest {
+    private MongoDbWidgetRepository tagRepository;
+    private MongoWidgetOperations template;
+
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
+    @Before
+    public void setup() {
+        tagRepository = new MongoDbWidgetRepository();
+        template = createMock(MongoWidgetOperations.class);
+        tagRepository.setTemplate(template);
+    }
+
+/*
+    @Test
+    public void getByWidgetIdAndTag_Valid() {
+        long widgetId = 3874;
+        String keyword = "booger";
+        Widget widget = new WidgetImpl();
+        WidgetTag widgetTag = new WidgetTagImpl();
+        Tag tag = new TagImpl();
+        tag.setKeyword(keyword);
+        widgetTag.setTag(tag);
+        widget.setTags(Arrays.asList(widgetTag));
+        expect(template.get(widgetId)).andReturn(widget);
+        replay(template);
+
+        assertThat(tagRepository.getByWidgetIdAndTag(widgetId, keyword), is(sameInstance(widgetTag)));
+    }
+
+    @Test
+    public void getByWidgetIdAndTag_Null() {
+        long widgetId = 3874;
+        String keyword = "booger";
+        Widget widget = new WidgetImpl();
+        widget.setTags(new ArrayList<WidgetTag>());
+        expect(template.get(widgetId)).andReturn(widget);
+        replay(template);
+
+        assertNull(tagRepository.getByWidgetIdAndTag(widgetId, keyword));
+    }
+
+    @Test
+    public void getByWidgetIdAndTag_Diff_Keyword(){
+        long widgetId = 3874;
+        String keyword = "booger";
+        Widget widget = new WidgetImpl();
+        WidgetTag widgetTag = new WidgetTagImpl();
+        Tag tag = new TagImpl();
+        tag.setKeyword("blah");
+        widgetTag.setTag(tag);
+        widget.setTags(Arrays.asList(widgetTag));
+        expect(template.get(widgetId)).andReturn(widget);
+        replay(template);
+
+        assertNull(tagRepository.getByWidgetIdAndTag(widgetId, keyword));
+    }
+
+    @Test
+    public void getType_Valid() {
+        assertThat((Class<WidgetTag>) tagRepository.getType(), is(equalTo(WidgetTag.class)));
+    }
+
+    @Test
+    public void get_Valid() {
+        thrown.expect(NotSupportedException.class);
+        tagRepository.get((long) 123);
+    }
+
+    @Test
+    public void save_Valid_Tag_Valid(){
+        WidgetTag item = new WidgetTagImpl();
+        item.setWidgetId((long)123);
+        Tag tag = new TagImpl();
+        String keyword = "keyword";
+        tag.setKeyword(keyword);
+        item.setTag(tag);
+        Widget widget = new WidgetImpl();
+        widget.setTags(Arrays.asList(item));
+
+        expect(template.get(item.getWidgetId())).andReturn(widget);
+        expect(template.save(widget)).andReturn(widget);
+        replay(template);
+
+        WidgetTag returned = tagRepository.save(item);
+        assertThat(returned, is(sameInstance(item)));
+    }
+
+    @Test
+    public void save_Valid_Tag_Null(){
+        WidgetTag item = new WidgetTagImpl();
+        item.setWidgetId((long)123);
+        Tag tag = new TagImpl();
+        String keyword = "keyword";
+        tag.setKeyword(keyword);
+        item.setTag(tag);
+        Widget widget = new WidgetImpl();
+        widget.setTags(new ArrayList<WidgetTag>());
+        Widget saved = new WidgetImpl();
+        saved.setTags(new ArrayList<WidgetTag>());
+
+        expect(template.get(item.getWidgetId())).andReturn(widget);
+        expect(template.save(widget)).andReturn(saved);
+        replay(template);
+
+        WidgetTag returned = tagRepository.save(item);
+        assertNull(returned);
+    }
+
+    @Test
+    public void delete_Valid(){
+        WidgetTag item = new WidgetTagImpl();
+        Tag tag = new TagImpl();
+        String keyword = "keyword";
+        tag.setKeyword(keyword);
+        item.setTag(tag);
+        Widget widget = new WidgetImpl();
+        ArrayList<WidgetTag> tags = new ArrayList<WidgetTag>();
+        tags.add(item);
+        widget.setTags(tags);
+        long widgetId = 12354;
+        item.setWidgetId(widgetId);
+
+        expect(template.get(widgetId)).andReturn(widget);
+        replay(template);
+
+        tagRepository.delete(item);
+
+        assertFalse(tags.contains(item));
+        verify(template);
+    }
+    @Test
+    public void delete_Null(){
+        WidgetTag item = new WidgetTagImpl();
+        Tag tag = new TagImpl();
+        String keyword = "keyword";
+        tag.setKeyword(keyword);
+        item.setTag(tag);
+        Widget widget = new WidgetImpl();
+        ArrayList<WidgetTag> tags = new ArrayList<WidgetTag>();
+        widget.setTags(tags);
+        long widgetId = 12354;
+        item.setWidgetId(widgetId);
+
+        expect(template.get(widgetId)).andReturn(widget);
+        replay(template);
+
+        tagRepository.delete(item);
+        verify(template);
+    }
+
+    @Test
+    public void delete_Tag_NoMatch(){
+        WidgetTag item = new WidgetTagImpl();
+        Tag tag = new TagImpl();
+        String keyword = "keyword";
+        tag.setKeyword(keyword);
+        item.setTag(tag);
+        Widget widget = new WidgetImpl();
+        ArrayList<WidgetTag> tags = new ArrayList<WidgetTag>();
+        WidgetTag extra = new WidgetTagImpl();
+        extra.setTag(new TagImpl("extra"));
+        tags.add(extra);
+        widget.setTags(tags);
+        long widgetId = 12354;
+        item.setWidgetId(widgetId);
+
+        expect(template.get(widgetId)).andReturn(widget);
+        replay(template);
+
+        tagRepository.delete(item);
+        verify(template);
+    }
+
+*/
+
+}
diff --git a/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MonogoDbMapReduceStatisticsAggregatorTest.java b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MonogoDbMapReduceStatisticsAggregatorTest.java
new file mode 100644
index 0000000..7d02393
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/java/org/apache/rave/portal/repository/impl/MonogoDbMapReduceStatisticsAggregatorTest.java
@@ -0,0 +1,340 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.rave.portal.repository.impl;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.apache.rave.portal.model.WidgetRatingsMapReduceResult;
+import org.apache.rave.portal.model.WidgetUsersMapReduceResult;
+import org.apache.rave.portal.model.util.WidgetStatistics;
+import org.apache.rave.portal.repository.StatisticsAggregator;
+import org.apache.rave.portal.repository.util.CollectionNames;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.rave.portal.repository.impl.MongoDbMapReduceStatisticsAggregator.*;
+import static org.apache.rave.portal.repository.util.CollectionNames.*;
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+public class MonogoDbMapReduceStatisticsAggregatorTest {
+
+    private MongoOperations mongoOperations;
+    private StatisticsAggregator aggregator;
+
+    @Before
+    public void setup() {
+        mongoOperations = createMock(MongoOperations.class);
+        aggregator = new MongoDbMapReduceStatisticsAggregator(mongoOperations);
+    }
+
+    @Test
+    public void getAllStatistics_valid() {
+
+        Map<String, Long> userRatings = getRatingsMap();
+        Map<String, Long> users = getUsersMap();
+
+        List<WidgetRatingsMapReduceResult> ratings = Arrays.asList(
+                new WidgetRatingsMapReduceResult("24L", new WidgetRatingsMapReduceResult.WidgetStatisticsMapReduceResult(userRatings, 2L, 0L)),
+                new WidgetRatingsMapReduceResult("25L", new WidgetRatingsMapReduceResult.WidgetStatisticsMapReduceResult(userRatings, 2L, 0L)),
+                new WidgetRatingsMapReduceResult("26L", new WidgetRatingsMapReduceResult.WidgetStatisticsMapReduceResult(userRatings, 2L, 0L))
+        );
+
+        List<WidgetUsersMapReduceResult> usersMapReduceResults = Arrays.asList(
+                new WidgetUsersMapReduceResult("24L", users),
+                new WidgetUsersMapReduceResult("25L", users),
+                new WidgetUsersMapReduceResult("26L", users)
+        );
+
+        expect(mongoOperations.findAll(WidgetRatingsMapReduceResult.class, CollectionNames.WIDGET_RATINGS)).andReturn(ratings);
+        expect(mongoOperations.findAll(WidgetUsersMapReduceResult.class, CollectionNames.WIDGET_USERS)).andReturn(usersMapReduceResults);
+        replay(mongoOperations);
+
+        Map<String, WidgetStatistics> stats = aggregator.getAllWidgetStatistics("1L");
+        assertThat(stats.size(), is(equalTo(3)));
+        assertThat(stats.get("24L").getTotalLike(), is(equalTo(2)));
+        assertThat(stats.get("24L").getTotalDislike(), is(equalTo(0)));
+        assertThat(stats.get("24L").getUserRating(), is(equalTo(10)));
+        assertThat(stats.get("24L").getTotalUserCount(), is(equalTo(users.size())));
+        assertThat(stats.get("26L").getTotalLike(), is(equalTo(2)));
+        assertThat(stats.get("26L").getTotalDislike(), is(equalTo(0)));
+        assertThat(stats.get("26L").getUserRating(), is(equalTo(10)));
+        assertThat(stats.get("26L").getTotalUserCount(), is(equalTo(users.size())));
+    }
+
+    @Test
+    public void getAllStatistics_noUserRating() {
+
+        Map<String, Long> userRatings = getRatingsMap();
+        Map<String, Long> users = getUsersMap();
+
+        List<WidgetRatingsMapReduceResult> ratings = Arrays.asList(
+                new WidgetRatingsMapReduceResult("24L", new WidgetRatingsMapReduceResult.WidgetStatisticsMapReduceResult(userRatings, 2L, 0L)),
+                new WidgetRatingsMapReduceResult("25L", new WidgetRatingsMapReduceResult.WidgetStatisticsMapReduceResult(userRatings, 2L, 0L)),
+                new WidgetRatingsMapReduceResult("26L", new WidgetRatingsMapReduceResult.WidgetStatisticsMapReduceResult(userRatings, 2L, 0L))
+        );
+
+        List<WidgetUsersMapReduceResult> usersMapReduceResults = Arrays.asList(
+                new WidgetUsersMapReduceResult("24L", users),
+                new WidgetUsersMapReduceResult("25L", users),
+                new WidgetUsersMapReduceResult("26L", users)
+        );
+
+        expect(mongoOperations.findAll(WidgetRatingsMapReduceResult.class, CollectionNames.WIDGET_RATINGS)).andReturn(ratings);
+        expect(mongoOperations.findAll(WidgetUsersMapReduceResult.class, CollectionNames.WIDGET_USERS)).andReturn(usersMapReduceResults);
+        replay(mongoOperations);
+
+        Map<String, WidgetStatistics> stats = aggregator.getAllWidgetStatistics("5L");
+        assertThat(stats.size(), is(equalTo(3)));
+        assertThat(stats.get("24L").getTotalLike(), is(equalTo(2)));
+        assertThat(stats.get("24L").getTotalDislike(), is(equalTo(0)));
+        assertThat(stats.get("24L").getUserRating(), is(equalTo(-1)));
+        assertThat(stats.get("24L").getTotalUserCount(), is(equalTo(users.size())));
+        assertThat(stats.get("26L").getTotalLike(), is(equalTo(2)));
+        assertThat(stats.get("26L").getTotalDislike(), is(equalTo(0)));
+        assertThat(stats.get("26L").getUserRating(), is(equalTo(-1)));
+        assertThat(stats.get("26L").getTotalUserCount(), is(equalTo(users.size())));
+    }
+
+    @Test
+    public void getAllStatistics_nullStats() {
+
+        Map<String, Long> userRatings = getRatingsMap();
+        Map<String, Long> users = getUsersMap();
+
+        List<WidgetRatingsMapReduceResult> ratings = Arrays.asList(
+                new WidgetRatingsMapReduceResult("24L", null),
+                new WidgetRatingsMapReduceResult("25L", null),
+                new WidgetRatingsMapReduceResult("26L", null)
+        );
+
+        List<WidgetUsersMapReduceResult> usersMapReduceResults = Arrays.asList(
+                new WidgetUsersMapReduceResult("24L", users),
+                new WidgetUsersMapReduceResult("25L", users),
+                new WidgetUsersMapReduceResult("26L", users)
+        );
+
+        expect(mongoOperations.findAll(WidgetRatingsMapReduceResult.class, CollectionNames.WIDGET_RATINGS)).andReturn(ratings);
+        expect(mongoOperations.findAll(WidgetUsersMapReduceResult.class, CollectionNames.WIDGET_USERS)).andReturn(usersMapReduceResults);
+        replay(mongoOperations);
+
+        Map<String, WidgetStatistics> stats = aggregator.getAllWidgetStatistics("5L");
+        assertThat(stats.size(), is(equalTo(3)));
+        assertThat(stats.get("24L").getTotalLike(), is(equalTo(0)));
+        assertThat(stats.get("24L").getTotalDislike(), is(equalTo(0)));
+        assertThat(stats.get("24L").getUserRating(), is(equalTo(-1)));
+        assertThat(stats.get("24L").getTotalUserCount(), is(equalTo(users.size())));
+        assertThat(stats.get("26L").getTotalLike(), is(equalTo(0)));
+        assertThat(stats.get("26L").getTotalDislike(), is(equalTo(0)));
+        assertThat(stats.get("26L").getUserRating(), is(equalTo(-1)));
+        assertThat(stats.get("26L").getTotalUserCount(), is(equalTo(users.size())));
+    }
+
+    @Test
+    public void getAllStatistics_noRatings() {
+
+        Map<String, Long> users = getUsersMap();
+
+        List<WidgetRatingsMapReduceResult> ratings = Lists.newArrayList();
+
+        List<WidgetUsersMapReduceResult> usersMapReduceResults = Arrays.asList(
+                new WidgetUsersMapReduceResult("24L", users),
+                new WidgetUsersMapReduceResult("25L", users),
+                new WidgetUsersMapReduceResult("26L", users)
+        );
+
+        expect(mongoOperations.findAll(WidgetRatingsMapReduceResult.class, CollectionNames.WIDGET_RATINGS)).andReturn(ratings);
+        expect(mongoOperations.findAll(WidgetUsersMapReduceResult.class, CollectionNames.WIDGET_USERS)).andReturn(usersMapReduceResults);
+        replay(mongoOperations);
+
+        Map<String, WidgetStatistics> stats = aggregator.getAllWidgetStatistics("5L");
+        assertThat(stats.size(), is(equalTo(3)));
+        assertThat(stats.get("24L").getTotalLike(), is(equalTo(0)));
+        assertThat(stats.get("24L").getTotalDislike(), is(equalTo(0)));
+        assertThat(stats.get("24L").getUserRating(), is(equalTo(-1)));
+        assertThat(stats.get("24L").getTotalUserCount(), is(equalTo(users.size())));
+        assertThat(stats.get("26L").getTotalLike(), is(equalTo(0)));
+        assertThat(stats.get("26L").getTotalDislike(), is(equalTo(0)));
+        assertThat(stats.get("26L").getUserRating(), is(equalTo(-1)));
+        assertThat(stats.get("26L").getTotalUserCount(), is(equalTo(users.size())));
+    }
+
+    @Test
+    public void getWidgetStatistics_valid() {
+        String widget_id = "1L";
+        Map<String, Long> userMap = Maps.newHashMap();
+        userMap.put("20L", 10L);
+        userMap.put("21L", 10L);
+        WidgetRatingsMapReduceResult.WidgetStatisticsMapReduceResult stats = new WidgetRatingsMapReduceResult.WidgetStatisticsMapReduceResult(userMap, 20L, 0L);
+        WidgetUsersMapReduceResult usersResult = new WidgetUsersMapReduceResult(widget_id, userMap);
+        WidgetRatingsMapReduceResult ratingsResult = new WidgetRatingsMapReduceResult(widget_id, stats);
+
+        expect(mongoOperations.findById(widget_id, WidgetRatingsMapReduceResult.class, WIDGET_RATINGS)).andReturn(ratingsResult);
+        expect(mongoOperations.findById(widget_id, WidgetUsersMapReduceResult.class, WIDGET_USERS)).andReturn(usersResult);
+        replay(mongoOperations);
+
+        WidgetStatistics result = aggregator.getWidgetStatistics(widget_id, "21L");
+
+        assertThat(result.getTotalDislike(), is(equalTo(0)));
+        assertThat(result.getTotalLike(), is(equalTo(20)));
+        assertThat(result.getUserRating(), is(equalTo(10)));
+        assertThat(result.getTotalUserCount(), is(equalTo(2)));
+    }
+
+    @Test
+    public void getWidgetStatistics_noUser() {
+        String widget_id = "1L";
+        Map<String, Long> userMap = Maps.newHashMap();
+        userMap.put("20L", 10L);
+        userMap.put("21L", 10L);
+        WidgetRatingsMapReduceResult.WidgetStatisticsMapReduceResult stats = new WidgetRatingsMapReduceResult.WidgetStatisticsMapReduceResult(userMap, 20L, 0L);
+        WidgetUsersMapReduceResult usersResult = new WidgetUsersMapReduceResult(widget_id, userMap);
+        WidgetRatingsMapReduceResult ratingsResult = new WidgetRatingsMapReduceResult(widget_id, stats);
+
+        expect(mongoOperations.findById(widget_id, WidgetRatingsMapReduceResult.class, WIDGET_RATINGS)).andReturn(ratingsResult);
+        expect(mongoOperations.findById(widget_id, WidgetUsersMapReduceResult.class, WIDGET_USERS)).andReturn(usersResult);
+        replay(mongoOperations);
+
+        WidgetStatistics result = aggregator.getWidgetStatistics(widget_id, "23L");
+
+        assertThat(result.getTotalDislike(), is(equalTo(0)));
+        assertThat(result.getTotalLike(), is(equalTo(20)));
+        assertThat(result.getUserRating(), is(equalTo(-1)));
+        assertThat(result.getTotalUserCount(), is(equalTo(2)));
+    }
+
+    @Test
+    public void getWidgetStatistics_nullRatings() {
+        String widget_id = "1L";
+        Map<String, Long> userMap = Maps.newHashMap();
+        userMap.put("20L", 10L);
+        userMap.put("21L", 10L);
+        WidgetUsersMapReduceResult usersResult = new WidgetUsersMapReduceResult(widget_id, userMap);
+
+        expect(mongoOperations.findById(widget_id, WidgetRatingsMapReduceResult.class, WIDGET_RATINGS)).andReturn(null);
+        expect(mongoOperations.findById(widget_id, WidgetUsersMapReduceResult.class, WIDGET_USERS)).andReturn(usersResult);
+        replay(mongoOperations);
+
+        WidgetStatistics result = aggregator.getWidgetStatistics(widget_id, "21L");
+
+        assertThat(result.getTotalDislike(), is(equalTo(0)));
+        assertThat(result.getTotalLike(), is(equalTo(0)));
+        assertThat(result.getUserRating(), is(equalTo(-1)));
+        assertThat(result.getTotalUserCount(), is(equalTo(2)));
+    }
+
+    @Test
+    public void getWidgetStatistics_nullUsers() {
+        String widget_id = "1L";
+        Map<String, Long> userMap = Maps.newHashMap();
+        userMap.put("20L", 10L);
+        userMap.put("21L", 10L);
+        WidgetRatingsMapReduceResult.WidgetStatisticsMapReduceResult stats = new WidgetRatingsMapReduceResult.WidgetStatisticsMapReduceResult(userMap, 20L, 0L);
+        WidgetRatingsMapReduceResult ratingsResult = new WidgetRatingsMapReduceResult(widget_id, stats);
+
+        expect(mongoOperations.findById(widget_id, WidgetRatingsMapReduceResult.class, WIDGET_RATINGS)).andReturn(ratingsResult);
+        expect(mongoOperations.findById(widget_id, WidgetUsersMapReduceResult.class, WIDGET_USERS)).andReturn(null);
+        replay(mongoOperations);
+
+        WidgetStatistics result = aggregator.getWidgetStatistics(widget_id, "21L");
+
+        assertThat(result.getTotalDislike(), is(equalTo(0)));
+        assertThat(result.getTotalLike(), is(equalTo(20)));
+        assertThat(result.getUserRating(), is(equalTo(10)));
+        assertThat(result.getTotalUserCount(), is(equalTo(0)));
+    }
+
+    @Test @Ignore
+    public void init_existing() {
+        expect(mongoOperations.findById(eq(ID), eq(RunStatistics.class), eq(OPERATIONS))).andReturn(new RunStatistics(ID, System.currentTimeMillis() - (DEFAULT_RESULT_VALIDITY * 1000)));
+        setMapReduceExpectations();
+        mongoOperations.save(isA(RunStatistics.class), eq(OPERATIONS));
+        expectLastCall();
+        replay(mongoOperations);
+
+        ((MongoDbMapReduceStatisticsAggregator)aggregator).buildStats();
+        verify(mongoOperations);
+    }
+
+    @Test
+    public void init_empty() {
+        expect(mongoOperations.findById(ID, RunStatistics.class, OPERATIONS)).andReturn(null);
+        setMapReduceExpectations();
+        mongoOperations.save(isA(RunStatistics.class), eq(OPERATIONS));
+        expectLastCall();
+        replay(mongoOperations);
+
+        ((MongoDbMapReduceStatisticsAggregator)aggregator).buildStats();
+        verify(mongoOperations);
+    }
+
+    @Test
+    public void init_tooEarly() {
+        expect(mongoOperations.findById(ID, RunStatistics.class, OPERATIONS)).andReturn(new RunStatistics(ID, System.currentTimeMillis() - 1000L));
+        replay(mongoOperations);
+
+        ((MongoDbMapReduceStatisticsAggregator)aggregator).buildStats();
+        verify(mongoOperations);
+    }
+
+    @Test
+    public void runStats() {
+        String id = "BOO";
+        long timestamp = 1234L;
+        RunStatistics stats = new RunStatistics();
+        stats.setId(id);
+        stats.setRefreshedTimeStamp(timestamp);
+
+        assertThat(stats.getId(), is(equalTo(id)));
+        assertThat(stats.getRefreshedTimeStamp(), is(equalTo(timestamp)));
+    }
+
+    private void setMapReduceExpectations() {
+        expect(mongoOperations.mapReduce(eq(WIDGET_COLLECTION), eq(RATINGS_MAP), eq(RATINGS_REDUCE), anyObject(MapReduceOptions.class), eq(WidgetRatingsMapReduceResult.class))).andReturn(null);
+        expect(mongoOperations.mapReduce(eq(PAGE_COLLECTION), eq(USERS_MAP), eq(USERS_REDUCE),  anyObject(MapReduceOptions.class), eq(WidgetUsersMapReduceResult.class))).andReturn(null);
+    }
+
+    private Map<String, Long> getRatingsMap() {
+        Map<String, Long> userRatings = Maps.newHashMap();
+        userRatings.put("1L", 10L);
+        userRatings.put("2L", 10L);
+        return userRatings;
+    }
+
+    private Map<String, Long> getUsersMap() {
+        Map<String, Long> users = Maps.newHashMap();
+        users.put("1L", 1L);
+        users.put("2L", 1L);
+        users.put("3L", 1L);
+        users.put("4L", 1L);
+        users.put("5L", 1L);
+        users.put("6L", 1L);
+        return users;
+    }
+}
diff --git a/rave-components/rave-mongodb/src/test/resources/portal.properties b/rave-components/rave-mongodb/src/test/resources/portal.properties
new file mode 100644
index 0000000..c14e90d
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/resources/portal.properties
@@ -0,0 +1,71 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+#
+
+#
+# These properties are used to construct the opensocial engine's URL. See
+# for example page.jsp. Changing them does not change the actual path configuration
+# of shindig.
+#
+portal.opensocial_engine.protocol=http
+portal.opensocial_engine.root=localhost:8080
+portal.opensocial_engine.gadget_path=/gadgets
+
+portal.opensocial_security.encryptionkey=classpath:security_token_encryption_key.txt
+portal.opensocial_security.container=default
+portal.opensocial_security.domain=default
+
+# the default page name to create for new users
+portal.page.default_name=Main
+
+###################################################################
+# Properties related to the Rave MongoDB implementation               #
+###################################################################
+mongo.host=localhost
+mongo.port=27017
+
+provider.wookie.wookieServerUrl=http://localhost:8080/wookie
+provider.wookie.wookieApiKey=TEST
+# captcha settings
+portal.captcha.enabled=false
+portal.captcha.key.private=
+portal.captcha.key.public=
+portal.captcha.usenoscript=false
+portal.captcha.invalid.configuration=<label class="error">ReCaptcha service is not properly configured.</label>
+
+#mail settings
+portal.mail.sender=
+portal.mail.replyto=
+portal.mail.host=
+portal.mail.password=
+portal.mail.username=
+portal.mail.protocol=smtp
+portal.mail.port=25
+portal.mail.username.subject=Rave username reminder service
+portal.mail.username.template=username_reminder.ftl
+portal.mail.passwordservice.subject=Rave password reminder service
+portal.mail.passwordservice.template=password_reminder.ftl
+portal.mail.passwordservice.valid.minutes=30
+portal.mail.service.baseurl=http://localhost:8080/portal/app/changepassword/
+
+# Account approval
+portal.user.account.needapproval=false
+portal.user.account.admin.email=
+portal.user.account.admin.subject=Rave User Approval
+portal.user.account.admin.template=admin_approval.ftl
+portal.mail.service.loginpage=http://localhost:8080/portal/
\ No newline at end of file
diff --git a/rave-components/rave-mongodb/src/test/resources/test-applicationContext.xml b/rave-components/rave-mongodb/src/test/resources/test-applicationContext.xml
new file mode 100644
index 0000000..fed6928
--- /dev/null
+++ b/rave-components/rave-mongodb/src/test/resources/test-applicationContext.xml
@@ -0,0 +1,27 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~  or more contributor license agreements.  See the NOTICE file
+  ~  distributed with this work for additional information
+  ~  regarding copyright ownership.  The ASF licenses this file
+  ~  to you under the Apache License, Version 2.0 (the
+  ~  "License"); you may not use this file except in compliance
+  ~  with the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing,
+  ~  software distributed under the License is distributed on an
+  ~  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~  KIND, either express or implied.  See the License for the
+  ~  specific language governing permissions and limitations
+  ~  under the License.
+  -->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                           http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+    <import resource="classpath:org/apache/rave/persistence-applicationContext.xml"/>
+
+</beans>
\ No newline at end of file
diff --git a/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/util/ControllerUtils.java b/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/util/ControllerUtils.java
index e0c9e34..a1c8d27 100644
--- a/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/util/ControllerUtils.java
+++ b/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/util/ControllerUtils.java
@@ -19,8 +19,6 @@
 
 package org.apache.rave.portal.web.controller.util;
 
-import javax.servlet.http.HttpServletRequest;
-
 import org.apache.rave.portal.model.User;
 import org.apache.rave.portal.web.model.NavigationItem;
 import org.apache.rave.portal.web.model.NavigationMenu;
@@ -30,6 +28,8 @@
 import org.springframework.mobile.device.DeviceUtils;
 import org.springframework.ui.Model;
 
+import javax.servlet.http.HttpServletRequest;
+
 public class ControllerUtils {
     private static final Logger log = LoggerFactory.getLogger(ControllerUtils.class);
 
diff --git a/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/tag/RegionWidgetTag.java b/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/tag/RegionWidgetTag.java
index 9aa08df..d0e5390 100644
--- a/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/tag/RegionWidgetTag.java
+++ b/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/tag/RegionWidgetTag.java
@@ -43,13 +43,12 @@
 
     // Script block for disabled gadget
     private static final String DISABLED_SCRIPT_BLOCK =
-            "<script>rave.registerWidget(%1$s, {type: 'DISABLED'," +
-            " regionWidgetId: %2$s," +
+            "<script>rave.registerWidget('%1$s', {type: 'DISABLED'," +
+            " regionWidgetId: '%2$s'," +
             " disabledMessage: '%3$s'," +
             " collapsed: %4$s," +
-            " widgetId: %5$s});</script>";
+            " widgetId: '%5$s'});</script>";
 
-    @Autowired
     public RegionWidgetTag() {
         super(RenderService.class);
     }
diff --git a/rave-integration-tests/rave-admin-tests/src/main/java/org/apache/rave/integrationtests/steps/CategoryAdminSteps.java b/rave-integration-tests/rave-admin-tests/src/main/java/org/apache/rave/integrationtests/steps/CategoryAdminSteps.java
index 7b2442c..3a93c24 100644
--- a/rave-integration-tests/rave-admin-tests/src/main/java/org/apache/rave/integrationtests/steps/CategoryAdminSteps.java
+++ b/rave-integration-tests/rave-admin-tests/src/main/java/org/apache/rave/integrationtests/steps/CategoryAdminSteps.java
@@ -29,9 +29,8 @@
 import org.openqa.selenium.WebElement;
 import org.springframework.beans.factory.annotation.Autowired;
 
-import java.util.List;
-
-import static org.hamcrest.CoreMatchers.*;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
 
 @Step
diff --git a/rave-integration-tests/rave-admin-tests/src/main/java/org/apache/rave/integrationtests/stories/AdminStories.java b/rave-integration-tests/rave-admin-tests/src/main/java/org/apache/rave/integrationtests/stories/AdminStories.java
index c7724ba..6b01a52 100644
--- a/rave-integration-tests/rave-admin-tests/src/main/java/org/apache/rave/integrationtests/stories/AdminStories.java
+++ b/rave-integration-tests/rave-admin-tests/src/main/java/org/apache/rave/integrationtests/stories/AdminStories.java
@@ -19,11 +19,10 @@
 
 package org.apache.rave.integrationtests.stories;
 
-import java.util.List;
-
 import org.jbehave.core.io.StoryFinder;
 
-import static java.util.Arrays.asList;
+import java.util.List;
+
 import static org.jbehave.core.io.CodeLocations.codeLocationFromClass;
 
 /**
diff --git a/rave-portal-dependencies/pom.xml b/rave-portal-dependencies/pom.xml
index 3a17f86..ebcbea2 100644
--- a/rave-portal-dependencies/pom.xml
+++ b/rave-portal-dependencies/pom.xml
@@ -19,7 +19,8 @@
 
   $Id$
 -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/rave-portal-resources/pom.xml b/rave-portal-resources/pom.xml
index 0f067dc..e976982 100644
--- a/rave-portal-resources/pom.xml
+++ b/rave-portal-resources/pom.xml
@@ -159,4 +159,57 @@
             </plugin>
         </plugins>
     </build>
+    <profiles>
+        <profile>
+            <id>jpa</id>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-war-plugin</artifactId>
+                        <version>${maven-war-plugin.version}</version>
+                        <configuration>
+                            <webResources>
+                                <resource>
+                                    <directory>src/main/resources_jpa</directory>
+                                    <targetPath>WEB-INF/</targetPath>
+                                    <filtering>true</filtering>
+                                    <includes>
+                                        <include>**/*</include>
+                                    </includes>
+                                </resource>
+                            </webResources>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>mongodb</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-war-plugin</artifactId>
+                        <version>${maven-war-plugin.version}</version>
+                        <configuration>
+                            <webResources>
+                                <resource>
+                                    <directory>src/main/resources_mongo</directory>
+                                    <targetPath>WEB-INF/</targetPath>
+                                    <filtering>true</filtering>
+                                    <includes>
+                                        <include>**/*</include>
+                                    </includes>
+                                </resource>
+                            </webResources>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
 </project>
diff --git a/rave-portal-resources/src/main/resources/portal.properties b/rave-portal-resources/src/main/resources/portal.properties
index e42181f..01397d7 100644
--- a/rave-portal-resources/src/main/resources/portal.properties
+++ b/rave-portal-resources/src/main/resources/portal.properties
@@ -35,23 +35,38 @@
 # the default page name to create for new users
 portal.page.default_name=Main
 
-#Default Rave Portal database settings with in memory H2 database
-# rave.database.location is replaced during the build
-portal.dataSource.url=jdbc:h2:${rave.database.location};AUTO_SERVER=TRUE
-portal.dataSource.driver=org.h2.Driver
-portal.dataSource.username=sa
-portal.dataSource.password=local
+###################################################################
+# Properties related to the Rave JPA implementation               #
+###################################################################
 
-portal.jpaDialect=org.apache.rave.persistence.jpa.impl.H2OpenJpaDialect
-portal.jpaVendorAdapter.databasePlatform=org.apache.openjpa.jdbc.sql.H2Dictionary
-portal.jpaVendorAdapter.database=H2
+# Default Rave Portal database settings with in memory H2 database
+# rave.database.location is replaced during the build
+jpa.dataSource.url=jdbc:h2:${rave.database.location};AUTO_SERVER=TRUE
+jpa.dataSource.driver=org.h2.Driver
+jpa.dataSource.username=sa
+jpa.dataSource.password=local
+
+jpa.jpaDialect=org.apache.rave.persistence.jpa.impl.H2OpenJpaDialect
+jpa.jpaVendorAdapter.databasePlatform=org.apache.openjpa.jdbc.sql.H2Dictionary
+jpa.jpaVendorAdapter.database=H2
 
 # General Rave portal database settings
-portal.jpaVendorAdapter.showSql=true
-portal.openjpa.Log=DefaultLevel=WARN, Runtime=INFO, Tool=WARN, SQL=WARN
-portal.openjpa.RuntimeUnenhancedClasses=unsupported
-portal.openjpa.jdbc.SynchronizeMappings=buildSchema(ForeignKeys=true)
-portal.openjpa.jdbc.MappingDefaults=ForeignKeyDeleteAction=restrict, JoinForeignKeyDeleteAction=restrict
+jpa.jpaVendorAdapter.showSql=true
+jpa.openjpa.Log=DefaultLevel=WARN, Runtime=WARN, Tool=WARN, SQL=WARN
+jpa.openjpa.RuntimeUnenhancedClasses=unsupported
+jpa.openjpa.jdbc.SynchronizeMappings=buildSchema(ForeignKeys=true)
+jpa.openjpa.jdbc.MappingDefaults=ForeignKeyDeleteAction=restrict, JoinForeignKeyDeleteAction=restrict
+
+
+###################################################################
+# Properties related to the Rave MongoDB implementation               #
+###################################################################
+mongo.host=localhost
+mongo.port=27017
+mongo.database=rave
+mongo.username=
+mongo.password=
+
 
 provider.wookie.wookieServerUrl=http://localhost:8080/wookie
 provider.wookie.wookieApiKey=TEST
diff --git a/rave-portal-resources/src/main/webapp/WEB-INF/dataContext.xml b/rave-portal-resources/src/main/resources_jpa/dataContext.xml
similarity index 100%
rename from rave-portal-resources/src/main/webapp/WEB-INF/dataContext.xml
rename to rave-portal-resources/src/main/resources_jpa/dataContext.xml
diff --git a/rave-portal-resources/src/main/webapp/WEB-INF/db/initial_data.sql b/rave-portal-resources/src/main/resources_jpa/db/initial_data.sql
similarity index 100%
rename from rave-portal-resources/src/main/webapp/WEB-INF/db/initial_data.sql
rename to rave-portal-resources/src/main/resources_jpa/db/initial_data.sql
diff --git a/rave-portal-resources/src/main/resources_mongo/dataContext.xml b/rave-portal-resources/src/main/resources_mongo/dataContext.xml
new file mode 100644
index 0000000..ad8f426
--- /dev/null
+++ b/rave-portal-resources/src/main/resources_mongo/dataContext.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+  -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                           http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+
+    <bean id="dataImporter" class="org.apache.rave.portal.util.data.DataImporter">
+        <property name="dataExecutor">
+            <bean class="org.apache.rave.portal.util.data.DataImporter$ExecutorImpl" />
+        </property>
+        <property name="scriptLocations">
+            <list>
+                <value>/WEB-INF/db/initial-data.json</value>
+            </list>
+        </property>
+    </bean>
+</beans>
\ No newline at end of file
diff --git a/rave-portal-resources/src/main/resources_mongo/db/initial-data.json b/rave-portal-resources/src/main/resources_mongo/db/initial-data.json
new file mode 100644
index 0000000..81daccd
--- /dev/null
+++ b/rave-portal-resources/src/main/resources_mongo/db/initial-data.json
@@ -0,0 +1,1514 @@
+{
+    "pageLayouts": [
+    {
+        "id": 1,
+        "code": "columns_1",
+        "numberOfRegions": 1,
+        "renderSequence": 0,
+        "userSelectable": true
+    },
+    {
+        "id": 2,
+        "code": "columns_2",
+        "numberOfRegions": 2,
+        "renderSequence": 1,
+        "userSelectable": true
+    },
+    {
+        "id": 3,
+        "code": "columns_2wn",
+        "numberOfRegions": 2,
+        "renderSequence": 2,
+        "userSelectable": true
+    },
+    {
+        "id": 4,
+        "code": "columns_3",
+        "numberOfRegions": 3,
+        "renderSequence": 3,
+        "userSelectable": true
+    },
+    {
+        "id": 5,
+        "code": "columns_3nwn",
+        "numberOfRegions": 3,
+        "renderSequence": 4,
+        "userSelectable": true
+    },
+    {
+        "id": 6,
+        "code": "columns_3_newuser",
+        "numberOfRegions": 3,
+        "renderSequence": 5,
+        "userSelectable": true
+    },
+    {
+        "id": 7,
+        "code": "columns_4",
+        "numberOfRegions": 4,
+        "renderSequence": 6,
+        "userSelectable": true
+    },
+    {
+        "id": 8,
+        "code": "columns_3nwn_1_bottom",
+        "numberOfRegions": 4,
+        "renderSequence": 7,
+        "userSelectable": true
+    },
+    {
+        "id": 9,
+        "code": "person_profile",
+        "numberOfRegions": 1,
+        "renderSequence": 8,
+        "userSelectable": false
+    }
+],
+    "users": [
+    {
+        "id": 1,
+        "username": "canonical",
+        "email": "canonical@example.com",
+        "displayName": "Canonical User",
+        "additionalName": null,
+        "familyName": "User",
+        "givenName": "Canonical",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$TkEgze5kLy9nRlfd8PT1zunh6P1ND8WPjLojFjAMNgZMu1D9D1n4.",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 2,
+                "authority": "ROLE_ADMIN",
+                "users": [],
+                "defaultForNewUser": false
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 1,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 2,
+        "username": "john.doe",
+        "email": "john.doe@example.com",
+        "displayName": "John Doe",
+        "additionalName": null,
+        "familyName": "Doe",
+        "givenName": "John",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$8Dir7boy3UyVqy6erfj6WuQXUTf.ejTldPSsVIty7.pPT3Krkly26",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 2,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 3,
+        "username": "jane.doe",
+        "email": "jane.doe@example.net",
+        "displayName": "Jane Doe",
+        "additionalName": null,
+        "familyName": "Doe",
+        "givenName": "Jane",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$YP9cjZEA.gG/ng2YwTBIyucMpuiQ7Fvz0K8rOt14rIBhVwlOrh1tu",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 3,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 4,
+        "username": "george.doe",
+        "email": "george.doe@example.org",
+        "displayName": "George Doe",
+        "additionalName": null,
+        "familyName": "Doe",
+        "givenName": "George",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$0bcOUkQgAwE/qmdc1NcUveNzx/IYIcOUu4ydyT8DEicTCxGJF/vcW",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 4,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 5,
+        "username": "mario.rossi",
+        "email": "mario.rossi@example.com",
+        "displayName": "Mario Rossi",
+        "additionalName": null,
+        "familyName": "Rossi",
+        "givenName": "Mario",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$HZ6WHAKQCs8waLooL98l6.fLzwh3D8u/V0.UebIjojawfXJhX1DQ2",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 5,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 6,
+        "username": "maija.m",
+        "email": "maijam@example.com",
+        "displayName": "Maija M",
+        "additionalName": null,
+        "familyName": "M",
+        "givenName": "Maija",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$3feYdjrW40hkqP4/xupKP.YMgdYmDsZZus./vK4FbBs9QZG2.FuNC",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 6,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 7,
+        "username": "one.col",
+        "email": "one.col@example.com",
+        "displayName": null,
+        "additionalName": null,
+        "familyName": "Column",
+        "givenName": "One",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$5VqE2YEqT75pCVjKqjP2b.gNGly9fsTVUOMQR/JEjkHSbqvA3A6IO",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 7,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 8,
+        "username": "twown.col",
+        "email": "twown.col@example.com",
+        "displayName": null,
+        "additionalName": null,
+        "familyName": "Column",
+        "givenName": "Two",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$Inpufv82TRUGYoPuXhYXVuMCKHkhLz44W6FijxW2e9n3T1hgyxcVq",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 8,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 9,
+        "username": "three.col",
+        "email": "three.col@example.com",
+        "displayName": null,
+        "additionalName": null,
+        "familyName": "Column",
+        "givenName": "Three",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$ImRXq4gFC9teBstOBdQrZeEwBkCAJ0S6.CwI9/9r7fxWKTZ30pgVC",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 9,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 10,
+        "username": "threewn.col",
+        "email": "threewn.col@example.com",
+        "displayName": null,
+        "additionalName": null,
+        "familyName": "ColumnWide",
+        "givenName": "Three",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$LLYTJoK6MCBpeDBbmdt7tu1LNt7Eenqe1IpMlfem8xVjzynn.HpxW",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 10,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 11,
+        "username": "four.col",
+        "email": "four.col@example.com",
+        "displayName": null,
+        "additionalName": null,
+        "familyName": "Column",
+        "givenName": "Four",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$tZgWcaG2EJPLtseZ339n7uTu3GZn31h3iTr20orwgbbRAI15uoIFK",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 11,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 12,
+        "username": "fourwn.col",
+        "email": "fourwn.col@example.com",
+        "displayName": null,
+        "additionalName": null,
+        "familyName": "ColumnWide",
+        "givenName": "Four",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$4kPYhgowurWqXGVDigxOxOVj/M.rqLRwqbn0kT/OD4pISL6pDG/c2",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 12,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 13,
+        "username": "rave2011.myopenid.com",
+        "email": "rave2011_openid@example.org",
+        "displayName": null,
+        "additionalName": null,
+        "familyName": "OpenId",
+        "givenName": "Rave",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$dML97.rnOn4.iSlEEdju8OCB2NckuKw0Ki5yMVzzMmWQsWMvym3qC",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": "http://rave2011.myopenid.com/",
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 13,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    }
+],
+    "groups": [
+    {
+        "id": 1,
+        "title": "Party",
+        "description": "Party Group",
+        "owner": null,
+        "members": [
+            {
+                "id": 1,
+                "username": "canonical",
+                "email": "canonical@example.com",
+                "displayName": "Canonical User",
+                "additionalName": null,
+                "familyName": "User",
+                "givenName": "Canonical",
+                "honorificPrefix": null,
+                "honorificSuffix": null,
+                "preferredName": null,
+                "aboutMe": null,
+                "status": "Single",
+                "addresses": [],
+                "organizations": [],
+                "properties": [],
+                "groups": [],
+                "password": "$2a$10$TkEgze5kLy9nRlfd8PT1zunh6P1ND8WPjLojFjAMNgZMu1D9D1n4.",
+                "expired": false,
+                "locked": false,
+                "enabled": true,
+                "openId": null,
+                "forgotPasswordHash": null,
+                "forgotPasswordTime": null,
+                "defaultPageLayout": {
+                    "id": 4,
+                    "code": "columns_3",
+                    "numberOfRegions": 3,
+                    "renderSequence": 3,
+                    "userSelectable": true
+                },
+                "confirmPassword": null,
+                "defaultPageLayoutCode": null,
+                "authorities": [
+                    {
+                        "id": 2,
+                        "authority": "ROLE_ADMIN",
+                        "users": [],
+                        "defaultForNewUser": false
+                    }
+                ],
+                "pageUsers": [],
+                "widgetTags": [],
+                "id": 1,
+                "accountNonLocked": true,
+                "credentialsNonExpired": true,
+                "accountNonExpired": true
+            },
+            {
+                "id": 5,
+                "username": "mario.rossi",
+                "email": "mario.rossi@example.com",
+                "displayName": "Mario Rossi",
+                "additionalName": null,
+                "familyName": "Rossi",
+                "givenName": "Mario",
+                "honorificPrefix": null,
+                "honorificSuffix": null,
+                "preferredName": null,
+                "aboutMe": null,
+                "status": "Single",
+                "addresses": [],
+                "organizations": [],
+                "properties": [],
+                "groups": [],
+                "password": "$2a$10$HZ6WHAKQCs8waLooL98l6.fLzwh3D8u/V0.UebIjojawfXJhX1DQ2",
+                "expired": false,
+                "locked": false,
+                "enabled": true,
+                "openId": null,
+                "forgotPasswordHash": null,
+                "forgotPasswordTime": null,
+                "defaultPageLayout": {
+                    "id": 4,
+                    "code": "columns_3",
+                    "numberOfRegions": 3,
+                    "renderSequence": 3,
+                    "userSelectable": true
+                },
+                "confirmPassword": null,
+                "defaultPageLayoutCode": null,
+                "authorities": [
+                    {
+                        "id": 1,
+                        "authority": "ROLE_USER",
+                        "users": [],
+                        "defaultForNewUser": true
+                    }
+                ],
+                "pageUsers": [],
+                "widgetTags": [],
+                "id": 5,
+                "accountNonLocked": true,
+                "credentialsNonExpired": true,
+                "accountNonExpired": true
+            }
+        ]
+    },
+    {
+        "id": 2,
+        "title": "Portal",
+        "description": "Portal Group",
+        "owner": null,
+        "members": [
+            {
+                "id": 1,
+                "username": "canonical",
+                "email": "canonical@example.com",
+                "displayName": "Canonical User",
+                "additionalName": null,
+                "familyName": "User",
+                "givenName": "Canonical",
+                "honorificPrefix": null,
+                "honorificSuffix": null,
+                "preferredName": null,
+                "aboutMe": null,
+                "status": "Single",
+                "addresses": [],
+                "organizations": [],
+                "properties": [],
+                "groups": [],
+                "password": "$2a$10$TkEgze5kLy9nRlfd8PT1zunh6P1ND8WPjLojFjAMNgZMu1D9D1n4.",
+                "expired": false,
+                "locked": false,
+                "enabled": true,
+                "openId": null,
+                "forgotPasswordHash": null,
+                "forgotPasswordTime": null,
+                "defaultPageLayout": {
+                    "id": 4,
+                    "code": "columns_3",
+                    "numberOfRegions": 3,
+                    "renderSequence": 3,
+                    "userSelectable": true
+                },
+                "confirmPassword": null,
+                "defaultPageLayoutCode": null,
+                "authorities": [
+                    {
+                        "id": 2,
+                        "authority": "ROLE_ADMIN",
+                        "users": [],
+                        "defaultForNewUser": false
+                    }
+                ],
+                "pageUsers": [],
+                "widgetTags": [],
+                "id": 1,
+                "accountNonLocked": true,
+                "credentialsNonExpired": true,
+                "accountNonExpired": true
+            },
+            {
+                "id": 2,
+                "username": "john.doe",
+                "email": "john.doe@example.com",
+                "displayName": "John Doe",
+                "additionalName": null,
+                "familyName": "Doe",
+                "givenName": "John",
+                "honorificPrefix": null,
+                "honorificSuffix": null,
+                "preferredName": null,
+                "aboutMe": null,
+                "status": "Single",
+                "addresses": [],
+                "organizations": [],
+                "properties": [],
+                "groups": [],
+                "password": "$2a$10$8Dir7boy3UyVqy6erfj6WuQXUTf.ejTldPSsVIty7.pPT3Krkly26",
+                "expired": false,
+                "locked": false,
+                "enabled": true,
+                "openId": null,
+                "forgotPasswordHash": null,
+                "forgotPasswordTime": null,
+                "defaultPageLayout": {
+                    "id": 4,
+                    "code": "columns_3",
+                    "numberOfRegions": 3,
+                    "renderSequence": 3,
+                    "userSelectable": true
+                },
+                "confirmPassword": null,
+                "defaultPageLayoutCode": null,
+                "authorities": [
+                    {
+                        "id": 1,
+                        "authority": "ROLE_USER",
+                        "users": [],
+                        "defaultForNewUser": true
+                    }
+                ],
+                "pageUsers": [],
+                "widgetTags": [],
+                "id": 2,
+                "accountNonLocked": true,
+                "credentialsNonExpired": true,
+                "accountNonExpired": true
+            }
+        ]
+    }
+],
+    "widgets": [
+    {
+        "id" : 1,
+        "title": "Wikipedia",
+        "titleUrl": "http://en.wikipedia.org/wiki/Main_Page",
+        "url": "http://www.widget-dico.com/wikipedia/google/wikipedia.xml",
+        "type": "OpenSocial",
+        "author": "WidgetMe",
+        "authorEmail": "google@widgetme.com",
+        "description": "A Wikipedia Search and Go widget. Language choice.",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 2,
+        "title": "Translate Gadget",
+        "titleUrl": "http://translate.google.com/",
+        "url": "http://www.gstatic.com/ig/modules/dictionary/dictionary.xml",
+        "type": "OpenSocial",
+        "author": "Google Taiwan",
+        "authorEmail": "googlemodules+dictionary+201109071@google.com",
+        "description": "Google Translation gadget.",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 3,
+        "title": "NYTimes.com - Top Stories",
+        "url": "http://widgets.nytimes.com/packages/html/igoogle/topstories.xml",
+        "type": "OpenSocial",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 4,
+        "title": "Google News Gadget",
+        "url": "http://www.gstatic.com/ig/modules/tabnews/tabnews.xml",
+        "type": "OpenSocial",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 5,
+        "title": "Pet Hamster",
+        "url": "http://hosting.gmodules.com/ig/gadgets/file/112581010116074801021/hamster.xml",
+        "type": "OpenSocial",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 6,
+        "title": "Herbie Hamster Virtual Pet",
+        "url": "http://hosting.gmodules.com/ig/gadgets/file/109548057311228444554/hamster.xml",
+        "type": "OpenSocial",
+        "author": "Naj",
+        "description": "A cute little hamster for you to feed and look after. Watch him follow your cursor around. Click on the more tab to treat him to a strawberry. Click him then put him on the wheel and watch him play! ***NEW: make Herbie hamster your very own!",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 7,
+        "title": "List of CTSS Resources - Map View",
+        "url": "http://localhost:8080/demogadgets/CTSSResourcesMapView.xml",
+        "type": "OpenSocial",
+        "author": "Suresh Deivasigamani",
+        "description": "This is a gadget developed for Teragrid - OGCE project. Used Google gadgets API to retrieve the information from the Information Services REST Web Service and display the information using Google Maps API. This is a list of available CTSS resources and its details",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 8,
+        "title": "Twitter",
+        "url": "http://localhost:8080/demogadgets/twitter.xml",
+        "type": "OpenSocial",
+        "author": "LOGIKA Corporation",
+        "description": "Fully functional, lightweight, AJAX-based twitter user interface with many configuration options including user specified auto-refresh rate, full timeline, pagination, and more.  Control display elements such as user thumbnails, date stamps, and post source.  Specify gadget size based on availble screen footprint, even incorporate into your Gmail account.  Insert symbols, dingbats and emoticons into your tweets using the TwitterGadget Symbols pulldown menu.",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 9,
+        "title": "Youtube",
+        "url": "http://localhost:8080/demogadgets/youtubesearch.xml",
+        "type": "OpenSocial",
+        "author": "David Olsen",
+        "description": "A search module, which searches YouTube by tags like Politics News Life Music Family Photography Art Random Travel Personal Religion Movies Business Thoughts Media Humor Culture Poetry Christmas Writing Books Food Friends.",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 10,
+        "title": "Open Views Demo",
+        "url": "http://localhost:8080/demogadgets/open_views_demo.xml",
+        "type": "OpenSocial",
+        "author": "Erin Noe-Payne",
+        "description": "A demo gadget to show open views popups in action.",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 11,
+        "title": "Gadget View Type",
+        "url": "http://localhost:8080/demogadgets/canvas-nav.xml",
+        "type": "OpenSocial",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 12,
+        "title": "User Prefs Demo",
+        "url": "http://localhost:8080/demogadgets/user_prefs_demo.xml",
+        "type": "OpenSocial",
+        "author": "Anthony Carlucci",
+        "description": "An example gadget which demos some of the different capabilities of user preferences.",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 13,
+        "title": "My Activity",
+        "url": "http://localhost:8080/demogadgets/my_activity.xml",
+        "type": "OpenSocial",
+        "author": "Anthony Carlucci",
+        "description": "Static widget of activities for demoing on the Person Profile page",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 14,
+        "title": "Current Schedule",
+        "url": "http://localhost:8080/demogadgets/schedule.xml",
+        "type": "OpenSocial",
+        "author": "Anthony Carlucci",
+        "description": "Static widget of a schedule for demoing on the Person Profile page",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 15,
+        "title": "Favorite Websites",
+        "url": "http://localhost:8080/demogadgets/favorite_websites.xml",
+        "type": "OpenSocial",
+        "author": "Anthony Carlucci",
+        "description": "Static widget of favorite websites for demoing on the Person Profile page",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 16,
+        "title": "My Groups",
+        "url": "http://localhost:8080/demogadgets/my_groups.xml",
+        "type": "OpenSocial",
+        "author": "Anthony Carlucci",
+        "description": "Static widget of groups for demoing on the Person Profile page",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 17,
+        "title": "My Experience",
+        "url": "http://localhost:8080/demogadgets/my_experience.xml",
+        "type": "OpenSocial",
+        "author": "Anthony Carlucci",
+        "description": "Static widget of experience for demoing on the Person Profile page",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 18,
+        "title": "Activity Streams",
+        "url": "http://localhost:8080/samplecontainer/examples/ActivityStreams/ActivityStreamGadget.xml",
+        "type": "OpenSocial",
+        "author": "Apache Shindig",
+        "description": "Sample Activity Streams gadget from Shindig",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 19,
+        "title": "Album Viewer",
+        "url": "http://localhost:8080/samplecontainer/examples/embeddedexperiences/AlbumViewer.xml",
+        "type": "OpenSocial",
+        "author": "Apache Shindig",
+        "description": "Sample Embedded Experience gadget from Shindig",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 20,
+        "title": "Photo List",
+        "url": "http://localhost:8080/samplecontainer/examples/embeddedexperiences/PhotoList.xml",
+        "type": "OpenSocial",
+        "author": "Apache Shindig",
+        "description": "Sample Embedded Experience gadget from Shindig",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 21,
+        "title": "OAuth2 Facebook",
+        "url": "http://localhost:8080/samplecontainer/examples/oauth2/oauth2_facebook.xml",
+        "type": "OpenSocial",
+        "author": "Apache Shindig",
+        "description": "Sample Facebook gadget from Shindig",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 22,
+        "title": "Ohloh Apache Rave Languages",
+        "url": "http://www.ohloh.net/p/521520/widgets/project_languages.xml",
+        "type": "OpenSocial",
+        "author": "Ohloh",
+        "description": "Ohloh is an open source network that connects people through the software they create and use. Ohloh gadgets provide detailed statistics about open source software projects and developers.",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 23,
+        "title": "Ohloh Apache Rave Factoids",
+        "url": "http://www.ohloh.net/p/521520/widgets/project_factoids.xml",
+        "type": "OpenSocial",
+        "author": "Ohloh",
+        "description": "Ohloh is an open source network that connects people through the software they create and use. Ohloh gadgets provide detailed statistics about open source software projects and developers.",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 24,
+        "title": "Ohloh Apache Rave COCOMO Estimates",
+        "url": "http://www.ohloh.net/p/521520/widgets/project_cocomo.xml",
+        "type": "OpenSocial",
+        "author": "Ohloh",
+        "description": "Ohloh is an open source network that connects people through the software they create and use. Ohloh gadgets provide detailed statistics about open source software projects and developers.",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 25,
+        "title": "Ohloh Apache Rave Stats",
+        "url": "http://www.ohloh.net/p/521520/widgets/project_basic_stats.xml",
+        "type": "OpenSocial",
+        "author": "Ohloh",
+        "description": "Ohloh is an open source network that connects people through the software they create and use. Ohloh gadgets provide detailed statistics about open source software projects and developers.",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 26,
+        "title": "OpenAJAX Hub Publisher",
+        "url": "http://localhost:8080/container/sample-pubsub-2-publisher.xml",
+        "type": "OpenSocial",
+        "author": "Apache Shindig",
+        "description": "OpenAJAX Hub publisher gadget from Shindig",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 27,
+        "title": "OpenAJAX Hub Subscriber",
+        "url": "http://localhost:8080/container/sample-pubsub-2-subscriber.xml",
+        "type": "OpenSocial",
+        "author": "Apache Shindig",
+        "description": "OpenAJAX Hub subscriber gadget from Shindig",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 28,
+        "title": "Friends",
+        "url": "http://localhost:8080/demogadgets/friends.xml",
+        "type": "OpenSocial",
+        "author": "Viknes Balasubramanee",
+        "description": "This gadget display the list of friends for a particular user",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    }
+],
+    "authorities": [
+    {
+        "id": 1,
+        "authority": "ROLE_USER",
+        "users": [],
+        "defaultForNewUser": true
+    },
+    {
+        "id": 2,
+        "authority": "ROLE_ADMIN",
+        "users": [],
+        "defaultForNewUser": false
+    }
+],
+    "portalPreferences": [
+    {
+        "id": 1,
+        "key": "titleSuffix",
+        "values": [
+            " - Rave"
+        ],
+        "value": " - Rave"
+    },
+    {
+        "id": 2,
+        "key": "pageSize",
+        "values": [
+            "10"
+        ],
+        "value": "10"
+    },
+    {
+        "id": 3,
+        "key": "javaScriptDebugMode",
+        "values": [
+            "1"
+        ],
+        "value": "1"
+    },
+    {
+        "id": 4,
+        "key": "defaultWidgetHeight",
+        "values": [
+            "250"
+        ],
+        "value": "250"
+    },
+    {
+        "id": 5,
+        "key": "showStackTrace",
+        "values": [
+            "0"
+        ],
+        "value": "0"
+    }
+],
+    "categories": [
+    {
+        "id": 1,
+        "text": "Technology",
+        "createdUserId": "1",
+        "createdDate": 1326949200000,
+        "lastModifiedUserId": "1",
+        "lastModifiedDate": 1326949200000
+    },
+    {
+        "id": 2,
+        "text": "News",
+        "createdUsedId": "1",
+        "createdDate": 1326949200000,
+        "lastModifiedUserId": "1",
+        "lastModifiedDate": 1326949200000
+    },
+    {
+        "id": 3,
+        "text": "Travel",
+        "createdUserId": "1",
+        "createdDate": 1326949200000,
+        "lastModifiedUserId": "1",
+        "lastModifiedDate": 1326949200000
+    },
+    {
+        "id": 4,
+        "text": "Projects",
+        "createdUserId": "1",
+        "createdDate": 1326949200000,
+        "lastModifiedUserId": "1",
+        "lastModifiedDate": 1326949200000
+    },
+    {
+        "id": 5,
+        "text": "Communications",
+        "createdUserId": "1",
+        "createdDate": 1326949200000,
+        "lastModifiedUserId":"1",
+        "lastModifiedDate": 1326949200000
+    }
+],
+    "pageTemplates": [
+    {
+        "id": 1,
+        "name": "Person Profile",
+        "description": "Template for person profile pages",
+        "pageType": "PERSON_PROFILE",
+        "parentPageTemplate": null,
+        "subPageTemplates": [
+            {
+                "id": 2,
+                "name": "About",
+                "description": "Template for the About sub page for the person profile",
+                "pageType": "SUB_PAGE",
+                "parentPageTemplate": null,
+                "subPageTemplates": [],
+                "pageLayout": {
+                    "id": 1,
+                    "code": "columns_1",
+                    "numberOfRegions": 1,
+                    "renderSequence": 0,
+                    "userSelectable": true
+                },
+                "pageTemplateRegions": [
+                    {
+                        "id": 2,
+                        "renderSequence": 0,
+                        "pageTemplate": null,
+                        "pageTemplateWidgets": [
+                            {
+                                "id": 3,
+                                "pageTemplateRegion": null,
+                                "widgetId": "15",
+                                "locked": true,
+                                "hideChrome": false,
+                                "renderSeq": 0
+                            },
+                            {
+                                "id": 4,
+                                "pageTemplateRegion": null,
+                                "widgetId": "14",
+                                "locked": true,
+                                "hideChrome": false,
+                                "renderSeq": 1
+                            }
+                        ],
+                        "locked": true
+                    }
+                ],
+                "renderSequence": 0,
+                "defaultTemplate": false
+            },
+            {
+                "id": 3,
+                "name": "My Activity",
+                "description": "Template for the My Activity sub page for the person profile",
+                "pageType": "SUB_PAGE",
+                "parentPageTemplate": null,
+                "subPageTemplates": [],
+                "pageLayout": {
+                    "id": 1,
+                    "code": "columns_1",
+                    "numberOfRegions": 1,
+                    "renderSequence": 0,
+                    "userSelectable": true
+                },
+                "pageTemplateRegions": [
+                    {
+                        "id": 3,
+                        "renderSequence": 0,
+                        "pageTemplate": null,
+                        "pageTemplateWidgets": [
+                            {
+                                "id": 5,
+                                "pageTemplateRegion": null,
+                                "widgetId": "3",
+                                "locked": true,
+                                "hideChrome": false,
+                                "renderSeq": 0
+                            }
+                        ],
+                        "locked": true
+                    }
+                ],
+                "renderSequence": 1,
+                "defaultTemplate": false
+            }
+        ],
+        "pageLayout": {
+            "id": 9,
+            "code": "person_profile",
+            "numberOfRegions": 1,
+            "renderSequence": 8,
+            "userSelectable": false
+        },
+        "pageTemplateRegions": [
+            {
+                "id": 1,
+                "renderSequence": 0,
+                "pageTemplate": null,
+                "pageTemplateWidgets": [
+                    {
+                        "id": 1,
+                        "pageTemplateRegion": null,
+                        "widgetId": "1",
+                        "locked": true,
+                        "hideChrome": true,
+                        "renderSeq": 0
+                    },
+                    {
+                        "id": 2,
+                        "pageTemplateRegion": null,
+                        "widgetId": "17",
+                        "locked": true,
+                        "hideChrome": true,
+                        "renderSeq": 1
+                    }
+                ],
+                "locked": true
+            }
+        ],
+        "renderSequence": 0,
+        "defaultTemplate": true
+    },
+    {
+        "id": 2,
+        "name": "Default Home",
+        "description": "Default User Template",
+        "pageType": "USER",
+        "parentPageTemplate": null,
+        "subPageTemplates": [],
+        "pageLayout": {
+            "id": 1,
+            "code": "columns_3_newuser",
+            "numberOfRegions": 1,
+            "renderSequence": 0,
+            "userSelectable": true
+        },
+        "pageTemplateRegions": [
+            {
+                "renderSequence": 0,
+                "pageTemplate": null,
+                "pageTemplateWidgets": [
+                    {
+                        "pageTemplateRegion": null,
+                        "widgetId": "2",
+                        "locked": false,
+                        "hideChrome": false,
+                        "id": 3,
+                        "renderSeq": 0
+                    },
+                    {
+                        "pageTemplateRegion": null,
+                        "widgetId": "7",
+                        "locked": false,
+                        "hideChrome": false,
+                        "id": 4,
+                        "renderSeq": 1
+                    }
+                ],
+                "locked": false,
+                "id": 2
+            },
+            {
+                "renderSequence": 1,
+                "pageTemplate": null,
+                "pageTemplateWidgets": [
+                    {
+                        "pageTemplateRegion": null,
+                        "widgetId": "10",
+                        "locked": false,
+                        "hideChrome": false,
+                        "id": 3,
+                        "renderSeq": 0
+                    },
+                    {
+                        "pageTemplateRegion": null,
+                        "widgetId": "23",
+                        "locked": false,
+                        "hideChrome": false,
+                        "id": 4,
+                        "renderSeq": 1
+                    }
+                ],
+                "locked": false,
+                "id": 2
+            },
+            {
+                "renderSequence": 2,
+                "pageTemplate": null,
+                "pageTemplateWidgets": [
+                    {
+                        "pageTemplateRegion": null,
+                        "widgetId": "11",
+                        "locked": false,
+                        "hideChrome": false,
+                        "id": 3,
+                        "renderSeq": 0
+                    }
+                ],
+                "locked": false,
+                "id": 2
+            }
+        ],
+        "renderSequence": 1,
+        "defaultTemplate": true
+    }
+]
+}
\ No newline at end of file
diff --git a/rave-portal-resources/src/main/webapp/WEB-INF/applicationContext.xml b/rave-portal-resources/src/main/webapp/WEB-INF/applicationContext.xml
index 5aeee5a..a905e93 100644
--- a/rave-portal-resources/src/main/webapp/WEB-INF/applicationContext.xml
+++ b/rave-portal-resources/src/main/webapp/WEB-INF/applicationContext.xml
@@ -21,13 +21,132 @@
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:p="http://www.springframework.org/schema/p"
        xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:aop="http://www.springframework.org/schema/aop"
+       xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
                            http://www.springframework.org/schema/util
-                           http://www.springframework.org/schema/util/spring-util.xsd">
+                           http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
+
+    <!-- make the the portal.properties props available to autowire injectors, location of the properties can
+be overridden by setting a system property "portal.override.properties" -->
+    <bean id="portalPropertyPlaceholder" class="org.apache.rave.util.OverridablePropertyPlaceholderConfigurer">
+        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
+        <property name="systemPropertyName" value="portal.override.properties"/>
+        <property name="location" value="classpath:portal.properties"/>
+    </bean>
+
+    <!-- bean post-processor for JPA annotations -->
+    <context:annotation-config/>
+
+    <!-- enable the use of the @AspectJ style of Spring AOP -->
+    <aop:aspectj-autoproxy/>
+
+    <!-- rave-common component base-package scan (maybe move to a separate common-applicationContext.xml?) -->
+    <context:component-scan base-package="org.apache.rave.service"/>
+    <context:component-scan base-package="org.apache.rave.synchronization"/>
+
+    <!-- rave-core component base-package scan -->
+    <context:component-scan base-package="org.apache.rave.portal.model"/>
+    <context:component-scan base-package="org.apache.rave.portal.repository"/>
+
+    <!-- Password encoding -->
+    <bean class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" id="passwordEncoder">
+        <!--<constructor-arg index="0" value="10"/>-->
+    </bean>
+
+    <!-- email settings -->
+    <bean id="emailServiceMailMessage" class="org.springframework.mail.SimpleMailMessage">
+        <property name="from" value="${portal.mail.sender}"/>
+        <property name="replyTo" value="${portal.mail.replyto}"/>
+    </bean>
+
+    <bean id="freemarkerMailConfiguration" class="org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean">
+        <property name="templateLoaderPath" value="/WEB-INF/mailtemplates"/>
+    </bean>
+    <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
+        <property name="host" value="${portal.mail.host}"/>
+        <property name="password" value="${portal.mail.password}"/>
+        <property name="username" value="${portal.mail.username}"/>
+        <property name="port" value="${portal.mail.port}"/>
+        <property name="protocol" value="${portal.mail.protocol}"/>
+        <!-- NOTE: if using Gmail, you'll need following properties-->
+        <!--<property name="javaMailProperties">
+            <props>
+                <prop key="mail.smtp.auth">true</prop>
+                <prop key="mail.smtp.starttls.enable">true</prop>
+                <prop key="mail.smtp.timeout">8500</prop>
+            </props>
+        </property>-->
+    </bean>
+    <!--
+    NOTE: to use mail session you'll need to configure following within catalina_home/conf/context.xml
+    <Resource name="mail/Session" auth="Container" type="javax.mail.Session" mail.smtp.host="my.mail.host"/>
+
+    Further, activation & mail jars needs to be placed within catalina_home/lib folder
+    -->
+    <!--
+    <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
+        <property name="session" ref="mailSession"/>
+    </bean>
+    <bean id="mailSession" class="org.springframework.jndi.JndiObjectFactoryBean">
+        <property name="jndiName" value="java:comp/env/mail/Session"/>
+    </bean>
+    -->
+
+    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate" />
+
+    <bean id="staticContentCache" class="org.apache.rave.service.impl.DefaultStaticContentFetcherService">
+        <constructor-arg ref="restTemplate"/>
+        <constructor-arg>
+            <list>
+                <!-- example of a Static Content source that doesn't have any string token placeholders in its content body
+                <bean class="org.apache.rave.model.StaticContent">
+                    <constructor-arg index="0" value="standardCompanyHeader"/>
+                    <constructor-arg index="1" value="${company.header.host}/content/standard_header.html"/>
+                    <constructor-arg index="2">
+                        <null/>
+                    </constructor-arg>
+                </bean>
+                -->
+                <!-- example of a Static Content source that has string token placeholders
+                <bean class="org.apache.rave.model.StaticContent">
+                    <constructor-arg index="0" value="environmentSpecificContent"/>
+                    <constructor-arg index="1" value="${company.header.host}/content/footer.html"/>
+                    <constructor-arg index="2">
+                        <map>
+                            <entry key="\{supportEmail\}" value="${raveproperty.supportemail}"/>
+                            <entry key="\{productVersion\}" value="${raveproperty.version}"/>
+                        </map>
+                    </constructor-arg>
+                </bean>
+                -->
+            </list>
+        </constructor-arg>
+    </bean>
+
+    <!-- example on how to setup a Spring Timer to refresh the Static Content cache at a fixed interval
+    <bean id="refreshStaticContentCacheScheduledTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
+        <property name="delay" value="5000"/>
+        <property name="period" value="300000"/>
+        <property name="timerTask">
+            <bean class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean"
+                  p:targetObject-ref="staticContentCache" p:targetMethod="refreshAll"/>
+        </property>
+    </bean>
+    <bean id="timerFactory" class="org.springframework.scheduling.timer.TimerFactoryBean">
+        <property name="daemon" value="true"/>
+        <property name="scheduledTimerTasks">
+            <list>
+                <ref local="refreshStaticContentCacheScheduledTask"/>
+            </list>
+        </property>
+    </bean>
+    -->
 
     <import resource="classpath*:org/apache/rave/core-applicationContext.xml"/>
-    <import resource="classpath*:org/apache/rave/jpa-applicationContext.xml"/>
+    <import resource="classpath*:org/apache/rave/persistence-applicationContext.xml"/>
     <import resource="classpath*:org/apache/rave/web-applicationContext.xml"/>
     <import resource="classpath*:org/apache/rave/opensocial-provider-applicationContext.xml"/>
     <import resource="classpath*:org/apache/rave/w3c-provider-applicationContext.xml"/>
diff --git a/rave-portal-resources/src/main/webapp/WEB-INF/dispatcher-servlet.xml b/rave-portal-resources/src/main/webapp/WEB-INF/dispatcher-servlet.xml
index a366948..c089355 100644
--- a/rave-portal-resources/src/main/webapp/WEB-INF/dispatcher-servlet.xml
+++ b/rave-portal-resources/src/main/webapp/WEB-INF/dispatcher-servlet.xml
@@ -27,6 +27,8 @@
         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd">
 
+    <import resource="classpath*:/org/apache/rave/marshaller-applicationContext.xml" />
+
     <!--
     Scans the classpath of this application for @Components to deploy as beans
     NOTE: only the controllers (api and controller packages) are scanned here in dispatcher-servlet.xml. All other
@@ -90,16 +92,6 @@
         <property name="suffix" value=".jsp"/>
     </bean>
 
-    <oxm:jaxb2-marshaller id="xmlMarshaller">
-        <oxm:class-to-be-bound name="org.apache.rave.portal.model.JpaUser"/>
-        <oxm:class-to-be-bound name="org.apache.rave.portal.model.JpaPage"/>
-        <oxm:class-to-be-bound name="org.apache.rave.portal.model.JpaRegion"/>
-        <oxm:class-to-be-bound name="org.apache.rave.portal.model.JpaRegionWidget"/>
-        <oxm:class-to-be-bound name="org.apache.rave.portal.model.JpaRegionWidgetPreference"/>
-        <oxm:class-to-be-bound name="org.apache.rave.portal.model.JpaWidget"/>
-        <oxm:class-to-be-bound name="org.apache.rave.portal.web.model.RegionWidgetPreferenceListWrapper"/>
-    </oxm:jaxb2-marshaller>
-
     <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
         <property name="messageConverters">
             <list>
diff --git a/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/preferences.jsp b/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/preferences.jsp
index e3d3f8f..d2c4e00 100644
--- a/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/preferences.jsp
+++ b/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/preferences.jsp
@@ -42,7 +42,7 @@
 	            <h2><fmt:message key="admin.preferences.shorttitle"/></h2>
 	
 	            <spring:url value="/app/admin/preferencedetail/edit" var="detaillink"/>
-	                <%--@elvariable id="preferenceMap" type="java.util.Map<java.lang.String, org.apache.rave.portal.model.JpaPortalPreference>"--%>
+	                <%--@elvariable id="preferenceMap" type="java.util.Map<java.lang.String, org.apache.rave.portal.model.PortalPreference>"--%>
 	            <c:choose>
 	                <c:when test="${fn:length(preferenceMap) eq 0}">
 	                    <a class="btn btn-primary" href="<c:out value="${detaillink}"/>"><fmt:message key="admin.preferences.edit"/></a>
diff --git a/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/userdetail.jsp b/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/userdetail.jsp
index afed810..442b7f3 100644
--- a/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/userdetail.jsp
+++ b/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/userdetail.jsp
@@ -115,7 +115,7 @@
 	                        </fieldset>
 	                        <fieldset>
 	                            <span class="control-label"><fmt:message key="admin.userdata.authorities"/></span>
-	                                <%--@elvariable id="authorities" type="org.apache.rave.portal.model.util.SearchResult<org.apache.rave.portal.model.JpaAuthority>"--%>
+	                                <%--@elvariable id="authorities" type="org.apache.rave.portal.model.util.SearchResult<org.apache.rave.portal.model.Authority>"--%>
 	                            <ul class="checkboxlist">
 	                                <form:checkboxes path="authorities" items="${authorities.resultSet}" itemLabel="authority" itemValue="authority" element="li"/>
 	                            </ul>
diff --git a/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/users.jsp b/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/users.jsp
index f629e19..757d183 100644
--- a/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/users.jsp
+++ b/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/users.jsp
@@ -19,7 +19,7 @@
 <%@ page language="java" trimDirectiveWhitespaces="true" %>
 <%@ include file="/WEB-INF/jsp/includes/taglibs.jsp" %>
 <fmt:setBundle basename="messages"/>
-<%--@elvariable id="searchResult" type="org.apache.rave.portal.model.util.SearchResult<org.apache.rave.portal.model.JpaUser>"--%>
+<%--@elvariable id="searchResult" type="org.apache.rave.portal.model.util.SearchResult<org.apache.rave.portal.model.User>"--%>
 
 <fmt:message key="${pageTitleKey}" var="pagetitle"/>
 <rave:navbar pageTitle="${pagetitle}"/>
diff --git a/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/widgets.jsp b/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/widgets.jsp
index 69d16d9..71469f0 100644
--- a/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/widgets.jsp
+++ b/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/widgets.jsp
@@ -19,7 +19,7 @@
 <%@ page language="java" trimDirectiveWhitespaces="true" %>
 <%@ include file="/WEB-INF/jsp/includes/taglibs.jsp" %>
 <fmt:setBundle basename="messages"/>
-<%--@elvariable id="searchResult" type="org.apache.rave.portal.model.util.SearchResult<org.apache.rave.portal.model.JpaWidget>"--%>
+<%--@elvariable id="searchResult" type="org.apache.rave.portal.model.util.SearchResult<org.apache.rave.portal.model.Widget>"--%>
 <fmt:message key="${pageTitleKey}" var="pagetitle"/>
 <rave:navbar pageTitle="${pagetitle}"/>
 <div class="container-fluid">
diff --git a/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/page.jsp b/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/page.jsp
index 5ddfc23..32e484d 100644
--- a/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/page.jsp
+++ b/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/page.jsp
@@ -22,7 +22,7 @@
 <fmt:setBundle basename="messages"/>
 <jsp:useBean id="pages" type="java.util.List<org.apache.rave.portal.model.Page>" scope="request"/>
 <jsp:useBean id="pageUser" type="org.apache.rave.portal.model.PageUser" scope="request"/>
-<jsp:useBean id="pageLayouts" type="java.util.List<org.apache.rave.portal.model.JpaPageLayout>" scope="request"/>
+<jsp:useBean id="pageLayouts" type="java.util.List" scope="request"/>
 
 <%--@elvariable id="page" type="org.apache.rave.portal.model.Page"--%>
 <sec:authentication property="principal.id" var="principalId" scope="request"/>
@@ -100,7 +100,7 @@
                         </li>
                     </c:when>
                     <c:otherwise>
-                        <li id="tab-${userPage.id}" onclick="rave.viewPage(${userPage.id});">
+                        <li id="tab-${userPage.id}" onclick="rave.viewPage('${userPage.id}');">
                             <c:choose>
                                 <c:when test="${isSharedToMe}">
                                     <a href="#" class="rave-ui-tab-shared-to-me">
diff --git a/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/personProfile.jsp b/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/personProfile.jsp
index b9979cf..bd14185 100644
--- a/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/personProfile.jsp
+++ b/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/personProfile.jsp
@@ -21,7 +21,7 @@
 <%@ page errorPage="/WEB-INF/jsp/views/error.jsp" %>
 <%@ include file="/WEB-INF/jsp/includes/taglibs.jsp" %>
 <fmt:setBundle basename="messages"/>
-<jsp:useBean id="userProfile" type="org.apache.rave.portal.model.JpaUser" scope="request"/>
+<jsp:useBean id="userProfile" type="org.apache.rave.portal.model.User" scope="request"/>
 <sec:authentication property="principal.username" var="principleUsername" scope="request"/>
 <sec:authentication property="principal.displayName" var="displayName" scope="request"/>
 
@@ -165,7 +165,7 @@
             </div>
         </div>
         <div class="span3">
-            <portal:person id="${page.ownerId}" var="${owner}" />
+            <portal:person id="${page.ownerId}" var="owner" />
         	<button type="button" id="addRemoveFriend" value="${owner.username}" class="btn btn-primary profile-info-visible"><fmt:message key="page.personProfile.addremove.friends"/></button>
         </div>
         <div class="span3">
diff --git a/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/store.jsp b/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/store.jsp
index b3f16bf..2086d9f 100644
--- a/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/store.jsp
+++ b/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/store.jsp
@@ -76,7 +76,7 @@
                     </div>
                 </c:if>
                 <ul class="storeItems">
-                        <%--@elvariable id="widget" type="org.apache.rave.portal.model.JpaWidget"--%>
+                        <%--@elvariable id="widget" type="org.apache.rave.portal.model.Widget"--%>
                     <c:forEach var="widget" items="${widgets.resultSet}">
                         <%--@elvariable id="widgetsStatistics" type="org.apache.rave.portal.model.util.WidgetStatistics"--%>
                         <c:set var="widgetStatistics" value="${widgetsStatistics[widget.id]}"/>
@@ -100,7 +100,7 @@
 
                             <div id="widgetAdded_${widget.id}" class="storeButton">
                                 <button class="btn btn-small btn-primary" id="addWidget_${widget.id}"
-                                        onclick="rave.api.rpc.addWidgetToPage({widgetId: ${widget.id}, pageId: ${referringPageId}, buttonId: this.id});" 
+                                        onclick="rave.api.rpc.addWidgetToPage({widgetId: '${widget.id}', pageId: '${referringPageId}', buttonId: this.id});"
                                         data-success="<fmt:message key="page.widget.addedToPage"/>">
                                     <fmt:message key="page.widget.addToPage"/>
                                 </button>
diff --git a/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/userProfile.jsp b/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/userProfile.jsp
index 792985c..6ce07b9 100644
--- a/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/userProfile.jsp
+++ b/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/userProfile.jsp
@@ -19,7 +19,7 @@
 <%@ page language="java" trimDirectiveWhitespaces="true" %>
 <%@ include file="/WEB-INF/jsp/includes/taglibs.jsp" %>
 <fmt:setBundle basename="messages"/>
-<jsp:useBean id="userProfile" type="org.apache.rave.portal.model.JpaUser" scope="request"/>
+<jsp:useBean id="userProfile" type="org.apache.rave.portal.model.User" scope="request"/>
 <div id="content">
     <h1>${pagetitle}</h1>
     <form:form id="userProfileForm" commandName="userProfile" action="updateUserProfile" method="POST">
diff --git a/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/widget.jsp b/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/widget.jsp
index 5aaeee5..4c00485 100644
--- a/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/widget.jsp
+++ b/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/widget.jsp
@@ -43,7 +43,7 @@
                         <div id="widgetAdded_${widget.id}" class="detailWidgetAdd">
                             <button class="btn btn-primary btn-large storeItemButton"
                                     id="addWidget_${widget.id}"
-                                    onclick="rave.api.rpc.addWidgetToPage({widgetId: ${widget.id}, pageId: ${referringPageId}, redirectAfterAdd:true});"
+                                    onclick="rave.api.rpc.addWidgetToPage({widgetId: '${widget.id}', pageId: '${referringPageId}', redirectAfterAdd:true});"
                                     data-success="<fmt:message key="page.widget.addedToPage"/>">
                                 <fmt:message key="page.widget.addToPage"/>
                             </button>
@@ -218,12 +218,12 @@
                                         </span>
                                         <c:if test="${userProfile.id eq comment.userId}">
                                             <button id="comment-delete-${comment.id}" class="btn btn-danger btn-mini commentDeleteButton"
-                                                    value="Delete" title="Delete comment" data-widgetid="<c:out value="${comment.widgetId}"/>">
+                                                    value="Delete" title="Delete comment" data-widgetid="<c:out value="${widget.id}"/>">
                                                 <i class="icon-remove icon-white"></i>
                                             </button>
                                             <button id="comment-edit-${comment.id}" class="btn btn-mini commentEditButton"
                                                     value="Edit" title="Edit comment"
-                                                    data-widgetid="<c:out value="${comment.widgetId}"/>"
+                                                    data-widgetid="<c:out value="${widget.id}"/>"
                                                     data-toggle="modal" data-target="#editComment-dialog">
                                                 <i class="icon-pencil"></i>
                                             </button>
diff --git a/rave-portal-resources/src/main/webapp/WEB-INF/tags/navbar.tag b/rave-portal-resources/src/main/webapp/WEB-INF/tags/navbar.tag
index ce6e61a..436f40f 100644
--- a/rave-portal-resources/src/main/webapp/WEB-INF/tags/navbar.tag
+++ b/rave-portal-resources/src/main/webapp/WEB-INF/tags/navbar.tag
@@ -44,7 +44,7 @@
                          			<c:when test="${navItem.hasChildren}">
 		                         		<ul class="dropdown-menu friendRequestDropdown">
 											<c:forEach items="${navItem.childNavigationItems}" var="childItem">
-												<li class="requestItem">${childItem.name}
+												<li class="requestItem"><c:out value="${childItem.name}" />
 												<a class="acceptFriendRequest" id="${childItem.nameParam}" href="#"><i class="icon-ok"></i></a>
 												<a class="declineFriendRequest" id="${childItem.nameParam}" href="#"><i class="icon-remove"></i></a>
 												</li>
diff --git a/rave-portal-resources/src/main/webapp/static/script/rave_person_profile.js b/rave-portal-resources/src/main/webapp/static/script/rave_person_profile.js
index 332082e..4a1bfe0 100644
--- a/rave-portal-resources/src/main/webapp/static/script/rave_person_profile.js
+++ b/rave-portal-resources/src/main/webapp/static/script/rave_person_profile.js
@@ -130,33 +130,33 @@
                      )
                      .append(
                          $("<td/>")
-                         .attr("id", "friendStatusButtonHolder" + this.entityId)
+                         .attr("id", "friendStatusButtonHolder" + this.id)
                      )
                  );
 
                  if(this.username != currentUser){
                      // check if already added
                      if(rave.personprofile.isUserAlreadyFriend(this.username)){
-                         $('#friendStatusButtonHolder'+this.entityId)
+                         $('#friendStatusButtonHolder'+this.id)
                          .append(
                              $("<a/>")
                              .attr("href", "#")
                              .attr("id", this.entityId)
-                             .attr("onclick", "rave.personprofile.removeFriend("+this.entityId+", '"+this.username+"');")
+                             .attr("onclick", "rave.personprofile.removeFriend("+this.id+", '"+this.username+"');")
                              .text(rave.getClientMessage("common.remove"))
                          );
                      // check if already sent friend request
                      }else if(rave.personprofile.isFriendRequestSent(this.username)){
-                         $('#friendStatusButtonHolder'+this.entityId)
+                         $('#friendStatusButtonHolder'+this.id)
                          .append(
                              $("<a/>")
                              .attr("href", "#")
                              .attr("id", this.entityId)
-                             .attr("onclick", "rave.personprofile.removeFriendRequestSent("+this.entityId+", '"+this.username+"');")
+                             .attr("onclick", "rave.personprofile.removeFriendRequestSent("+this.id+", '"+this.username+"');")
                              .text(rave.getClientMessage("common.cancel.request"))
                          );
                      }else if(rave.personprofile.isFriendRequestReceived(this.username)){
-                         $('#friendStatusButtonHolder'+this.entityId)
+                         $('#friendStatusButtonHolder'+this.id)
                          .append(
                              $("<a/>")
                              .attr("href", "#")
@@ -166,17 +166,17 @@
                              ' / ',
                              $("<a/>")
                              .attr("href", "#")
-                             .attr("id", this.entityId)
-                             .attr("onclick", "rave.personprofile.declineFriendRequest("+this.entityId+", '"+this.username+"');")
+                             .attr("id", this.id)
+                             .attr("onclick", "rave.personprofile.declineFriendRequest("+this.id+", '"+this.username+"');")
                              .text(rave.getClientMessage("common.decline"))
                          );
                      }else {
-                         $('#friendStatusButtonHolder'+this.entityId)
+                         $('#friendStatusButtonHolder'+this.id)
                          .append(
                              $("<a/>")
                              .attr("href", "#")
-                             .attr("id", this.entityId)
-                             .attr("onclick", "rave.personprofile.addFriend("+this.entityId+", '"+this.username+"');")
+                             .attr("id", this.id)
+                             .attr("onclick", "rave.personprofile.addFriend("+this.id+", '"+this.username+"');")
                              .text(rave.getClientMessage("common.add"))
                          );
                      }
diff --git a/rave-portal/pom.xml b/rave-portal/pom.xml
index 45a8ca8..7156f7f 100644
--- a/rave-portal/pom.xml
+++ b/rave-portal/pom.xml
@@ -201,7 +201,7 @@
                             <!--  un-comment following property for: Loading the SizeOfAgent will probably fail,
                             as you are running on Apple OS X and have a value set for java.io.tmpdir  -->
                             <!-- <net.sf.ehcache.pool.sizeof.AgentSizeOf.bypass>true</net.sf.ehcache.pool.sizeof.AgentSizeOf.bypass>  -->
-	                  
+
 	                   <!-- Documentation: http://rave.apache.org/documentation/host-configuration.html -->
                             <!--
                                 <portal.override.properties>/path/to/custom.portal.properties</portal.override.properties>
@@ -284,6 +284,74 @@
                 </plugins>
             </build>
         </profile>
+            <profile>
+                <id>jpa</id>
+                <activation>
+                    <activeByDefault>true</activeByDefault>
+                </activation>
+                <build>
+                    <testResources>
+                        <testResource>
+                            <directory>${project.basedir}/src/test/resources_jpa</directory>
+                        </testResource>
+                    </testResources>
+                </build>
+            </profile>
+            <profile>
+                <id>mongodb</id>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.rave</groupId>
+                        <artifactId>rave-portal-dependencies</artifactId>
+                        <type>pom</type>
+                        <exclusions>
+                            <exclusion>
+                                <groupId>org.apache.rave</groupId>
+                                <artifactId>rave-jpa</artifactId>
+                            </exclusion>
+                        </exclusions>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.apache.rave</groupId>
+                        <artifactId>rave-mongodb</artifactId>
+                    </dependency>
+                    <dependency>
+                        <groupId>de.flapdoodle.embed</groupId>
+                        <artifactId>de.flapdoodle.embed.mongo</artifactId>
+                        <scope>test</scope>
+                    </dependency>
+                </dependencies>
+                <build>
+                    <testResources>
+                        <testResource>
+                            <directory>${project.basedir}/src/test/resources_mongo</directory>
+                        </testResource>
+                    </testResources>
+                    <plugins>
+                        <plugin>
+                            <groupId>com.github.joelittlejohn.embedmongo</groupId>
+                            <artifactId>embedmongo-maven-plugin</artifactId>
+                            <version>0.1.5</version>
+                            <executions>
+                                <execution>
+                                    <id>start</id>
+                                    <phase>test-compile</phase>
+                                    <goals>
+                                        <goal>start</goal>
+                                    </goals>
+                                </execution>
+                                <execution>
+                                    <id>stop</id>
+                                    <phase>post-integration-test</phase>
+                                    <goals>
+                                        <goal>stop</goal>
+                                    </goals>
+                                </execution>
+                            </executions>
+                        </plugin>
+                    </plugins>
+                </build>
+            </profile>
     </profiles>
 
 </project>
diff --git a/rave-portal/src/test/resources/portal.properties b/rave-portal/src/test/resources/portal.properties
index 5ed4be2..5b0979c 100644
--- a/rave-portal/src/test/resources/portal.properties
+++ b/rave-portal/src/test/resources/portal.properties
@@ -34,21 +34,30 @@
 portal.page.default_name=Main
 
 #Default Rave Portal database settings with in memory H2 database
-portal.dataSource.url=jdbc:h2:mem:portal;DB_CLOSE_DELAY=-1
-portal.dataSource.driver=org.h2.Driver
-portal.dataSource.username=sa
-portal.dataSource.password=local
+jpa.dataSource.url=jdbc:h2:mem:portal;DB_CLOSE_DELAY=-1
+jpa.dataSource.driver=org.h2.Driver
+jpa.dataSource.username=sa
+jpa.dataSource.password=local
 
-portal.jpaDialect=org.apache.rave.persistence.jpa.impl.H2OpenJpaDialect
-portal.jpaVendorAdapter.databasePlatform=org.apache.openjpa.jdbc.sql.H2Dictionary
-portal.jpaVendorAdapter.database=H2
+jpa.jpaDialect=org.apache.rave.persistence.jpa.impl.H2OpenJpaDialect
+jpa.jpaVendorAdapter.databasePlatform=org.apache.openjpa.jdbc.sql.H2Dictionary
+jpa.jpaVendorAdapter.database=H2
 
-# General Rave portal database settings
-portal.jpaVendorAdapter.showSql=true
-portal.openjpa.Log=DefaultLevel=WARN, Runtime=INFO, Tool=INFO, SQL=WARN
-portal.openjpa.RuntimeUnenhancedClasses=unsupported
-portal.openjpa.jdbc.SynchronizeMappings=buildSchema(ForeignKeys=true)
-portal.openjpa.jdbc.MappingDefaults=ForeignKeyDeleteAction=restrict, JoinForeignKeyDeleteAction=restrict
+# General Rave jpa database settings
+jpa.jpaVendorAdapter.showSql=true
+jpa.openjpa.Log=DefaultLevel=WARN, Runtime=INFO, Tool=INFO, SQL=WARN
+jpa.openjpa.RuntimeUnenhancedClasses=unsupported
+jpa.openjpa.jdbc.SynchronizeMappings=buildSchema(ForeignKeys=true)
+jpa.openjpa.jdbc.MappingDefaults=ForeignKeyDeleteAction=restrict, JoinForeignKeyDeleteAction=restrict
+
+###################################################################
+# Properties related to the Rave MongoDB implementation               #
+###################################################################
+mongo.host=localhost
+mongo.port=27017
+mongo.database=rave
+mongo.username=
+mongo.password=
 
 provider.wookie.wookieServerUrl=http://localhost:8080/wookie
 provider.wookie.wookieApiKey=TEST
diff --git a/rave-portal/src/test/resources/test-applicationContext.xml b/rave-portal/src/test/resources/test-applicationContext.xml
index e2839a6..04e81c5 100644
--- a/rave-portal/src/test/resources/test-applicationContext.xml
+++ b/rave-portal/src/test/resources/test-applicationContext.xml
@@ -23,7 +23,7 @@
                            http://www.springframework.org/schema/beans/spring-beans.xsd">
 
     <import resource="classpath:org/apache/rave/core-applicationContext.xml"/>
-    <import resource="classpath:org/apache/rave/jpa-applicationContext.xml"/>
+    <import resource="classpath:org/apache/rave/persistence-applicationContext.xml"/>
     <import resource="classpath:org/apache/rave/web-applicationContext.xml"/>
     <import resource="classpath:org/apache/rave/opensocial-provider-applicationContext.xml"/>
 
diff --git a/rave-portal/src/test/resources/test-data.sql b/rave-portal/src/test/resources_jpa/test-data.sql
similarity index 100%
rename from rave-portal/src/test/resources/test-data.sql
rename to rave-portal/src/test/resources_jpa/test-data.sql
diff --git a/rave-portal/src/test/resources/test-dataContext.xml b/rave-portal/src/test/resources_jpa/test-dataContext.xml
similarity index 100%
rename from rave-portal/src/test/resources/test-dataContext.xml
rename to rave-portal/src/test/resources_jpa/test-dataContext.xml
diff --git a/rave-portal/src/test/resources_mongo/initial-data.json b/rave-portal/src/test/resources_mongo/initial-data.json
new file mode 100644
index 0000000..4ba0687
--- /dev/null
+++ b/rave-portal/src/test/resources_mongo/initial-data.json
@@ -0,0 +1,2051 @@
+{
+    "pageLayouts": [
+    {
+        "id": 1,
+        "code": "columns_1",
+        "numberOfRegions": 1,
+        "renderSequence": 0,
+        "userSelectable": true
+    },
+    {
+        "id": 2,
+        "code": "columns_2",
+        "numberOfRegions": 2,
+        "renderSequence": 1,
+        "userSelectable": true
+    },
+    {
+        "id": 3,
+        "code": "columns_2wn",
+        "numberOfRegions": 2,
+        "renderSequence": 2,
+        "userSelectable": true
+    },
+    {
+        "id": 4,
+        "code": "columns_3",
+        "numberOfRegions": 3,
+        "renderSequence": 3,
+        "userSelectable": true
+    },
+    {
+        "id": 5,
+        "code": "columns_3nwn",
+        "numberOfRegions": 3,
+        "renderSequence": 4,
+        "userSelectable": true
+    },
+    {
+        "id": 6,
+        "code": "columns_3_newuser",
+        "numberOfRegions": 3,
+        "renderSequence": 5,
+        "userSelectable": true
+    },
+    {
+        "id": 7,
+        "code": "columns_4",
+        "numberOfRegions": 4,
+        "renderSequence": 6,
+        "userSelectable": true
+    },
+    {
+        "id": 8,
+        "code": "columns_3nwn_1_bottom",
+        "numberOfRegions": 4,
+        "renderSequence": 7,
+        "userSelectable": true
+    },
+    {
+        "id": 9,
+        "code": "person_profile",
+        "numberOfRegions": 1,
+        "renderSequence": 8,
+        "userSelectable": false
+    }
+],
+    "users": [
+    {
+        "id": 1,
+        "username": "canonical",
+        "email": "canonical@example.com",
+        "displayName": "Canonical User",
+        "additionalName": null,
+        "familyName": "User",
+        "givenName": "Canonical",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$TkEgze5kLy9nRlfd8PT1zunh6P1ND8WPjLojFjAMNgZMu1D9D1n4.",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 2,
+                "authority": "ROLE_ADMIN",
+                "users": [],
+                "defaultForNewUser": false
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 1,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 2,
+        "username": "john.doe",
+        "email": "john.doe@example.com",
+        "displayName": "John Doe",
+        "additionalName": null,
+        "familyName": "Doe",
+        "givenName": "John",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$8Dir7boy3UyVqy6erfj6WuQXUTf.ejTldPSsVIty7.pPT3Krkly26",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 2,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 3,
+        "username": "jane.doe",
+        "email": "jane.doe@example.net",
+        "displayName": "Jane Doe",
+        "additionalName": null,
+        "familyName": "Doe",
+        "givenName": "Jane",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$YP9cjZEA.gG/ng2YwTBIyucMpuiQ7Fvz0K8rOt14rIBhVwlOrh1tu",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 3,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 4,
+        "username": "george.doe",
+        "email": "george.doe@example.org",
+        "displayName": "George Doe",
+        "additionalName": null,
+        "familyName": "Doe",
+        "givenName": "George",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$0bcOUkQgAwE/qmdc1NcUveNzx/IYIcOUu4ydyT8DEicTCxGJF/vcW",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 4,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 5,
+        "username": "mario.rossi",
+        "email": "mario.rossi@example.com",
+        "displayName": "Mario Rossi",
+        "additionalName": null,
+        "familyName": "Rossi",
+        "givenName": "Mario",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$HZ6WHAKQCs8waLooL98l6.fLzwh3D8u/V0.UebIjojawfXJhX1DQ2",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 5,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 6,
+        "username": "maija.m",
+        "email": "maijam@example.com",
+        "displayName": "Maija M",
+        "additionalName": null,
+        "familyName": "M",
+        "givenName": "Maija",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$3feYdjrW40hkqP4/xupKP.YMgdYmDsZZus./vK4FbBs9QZG2.FuNC",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 6,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 7,
+        "username": "one.col",
+        "email": "one.col@example.com",
+        "displayName": null,
+        "additionalName": null,
+        "familyName": "Column",
+        "givenName": "One",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$5VqE2YEqT75pCVjKqjP2b.gNGly9fsTVUOMQR/JEjkHSbqvA3A6IO",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 7,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 8,
+        "username": "twown.col",
+        "email": "twown.col@example.com",
+        "displayName": null,
+        "additionalName": null,
+        "familyName": "Column",
+        "givenName": "Two",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$Inpufv82TRUGYoPuXhYXVuMCKHkhLz44W6FijxW2e9n3T1hgyxcVq",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 8,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 9,
+        "username": "three.col",
+        "email": "three.col@example.com",
+        "displayName": null,
+        "additionalName": null,
+        "familyName": "Column",
+        "givenName": "Three",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$ImRXq4gFC9teBstOBdQrZeEwBkCAJ0S6.CwI9/9r7fxWKTZ30pgVC",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 9,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 10,
+        "username": "threewn.col",
+        "email": "threewn.col@example.com",
+        "displayName": null,
+        "additionalName": null,
+        "familyName": "ColumnWide",
+        "givenName": "Three",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$LLYTJoK6MCBpeDBbmdt7tu1LNt7Eenqe1IpMlfem8xVjzynn.HpxW",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 10,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 11,
+        "username": "four.col",
+        "email": "four.col@example.com",
+        "displayName": null,
+        "additionalName": null,
+        "familyName": "Column",
+        "givenName": "Four",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$tZgWcaG2EJPLtseZ339n7uTu3GZn31h3iTr20orwgbbRAI15uoIFK",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 11,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 12,
+        "username": "fourwn.col",
+        "email": "fourwn.col@example.com",
+        "displayName": null,
+        "additionalName": null,
+        "familyName": "ColumnWide",
+        "givenName": "Four",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$4kPYhgowurWqXGVDigxOxOVj/M.rqLRwqbn0kT/OD4pISL6pDG/c2",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": null,
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 12,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    },
+    {
+        "id": 13,
+        "username": "rave2011.myopenid.com",
+        "email": "rave2011_openid@example.org",
+        "displayName": null,
+        "additionalName": null,
+        "familyName": "OpenId",
+        "givenName": "Rave",
+        "honorificPrefix": null,
+        "honorificSuffix": null,
+        "preferredName": null,
+        "aboutMe": null,
+        "status": "Single",
+        "addresses": [],
+        "organizations": [],
+        "properties": [],
+        "groups": [],
+        "password": "$2a$10$dML97.rnOn4.iSlEEdju8OCB2NckuKw0Ki5yMVzzMmWQsWMvym3qC",
+        "expired": false,
+        "locked": false,
+        "enabled": true,
+        "openId": "http://rave2011.myopenid.com/",
+        "forgotPasswordHash": null,
+        "forgotPasswordTime": null,
+        "defaultPageLayout": {
+            "id": 4,
+            "code": "columns_3",
+            "numberOfRegions": 3,
+            "renderSequence": 3,
+            "userSelectable": true
+        },
+        "confirmPassword": null,
+        "defaultPageLayoutCode": null,
+        "authorities": [
+            {
+                "id": 1,
+                "authority": "ROLE_USER",
+                "users": [],
+                "defaultForNewUser": true
+            }
+        ],
+        "pageUsers": [],
+        "widgetTags": [],
+        "id": 13,
+        "accountNonLocked": true,
+        "credentialsNonExpired": true,
+        "accountNonExpired": true
+    }
+],
+    "groups": [
+    {
+        "id": 1,
+        "title": "Party",
+        "description": "Party Group",
+        "owner": null,
+        "members": [
+            {
+                "id": 1,
+                "username": "canonical",
+                "email": "canonical@example.com",
+                "displayName": "Canonical User",
+                "additionalName": null,
+                "familyName": "User",
+                "givenName": "Canonical",
+                "honorificPrefix": null,
+                "honorificSuffix": null,
+                "preferredName": null,
+                "aboutMe": null,
+                "status": "Single",
+                "addresses": [],
+                "organizations": [],
+                "properties": [],
+                "groups": [],
+                "password": "$2a$10$TkEgze5kLy9nRlfd8PT1zunh6P1ND8WPjLojFjAMNgZMu1D9D1n4.",
+                "expired": false,
+                "locked": false,
+                "enabled": true,
+                "openId": null,
+                "forgotPasswordHash": null,
+                "forgotPasswordTime": null,
+                "defaultPageLayout": {
+                    "id": 4,
+                    "code": "columns_3",
+                    "numberOfRegions": 3,
+                    "renderSequence": 3,
+                    "userSelectable": true
+                },
+                "confirmPassword": null,
+                "defaultPageLayoutCode": null,
+                "authorities": [
+                    {
+                        "id": 2,
+                        "authority": "ROLE_ADMIN",
+                        "users": [],
+                        "defaultForNewUser": false
+                    }
+                ],
+                "pageUsers": [],
+                "widgetTags": [],
+                "id": 1,
+                "accountNonLocked": true,
+                "credentialsNonExpired": true,
+                "accountNonExpired": true
+            },
+            {
+                "id": 5,
+                "username": "mario.rossi",
+                "email": "mario.rossi@example.com",
+                "displayName": "Mario Rossi",
+                "additionalName": null,
+                "familyName": "Rossi",
+                "givenName": "Mario",
+                "honorificPrefix": null,
+                "honorificSuffix": null,
+                "preferredName": null,
+                "aboutMe": null,
+                "status": "Single",
+                "addresses": [],
+                "organizations": [],
+                "properties": [],
+                "groups": [],
+                "password": "$2a$10$HZ6WHAKQCs8waLooL98l6.fLzwh3D8u/V0.UebIjojawfXJhX1DQ2",
+                "expired": false,
+                "locked": false,
+                "enabled": true,
+                "openId": null,
+                "forgotPasswordHash": null,
+                "forgotPasswordTime": null,
+                "defaultPageLayout": {
+                    "id": 4,
+                    "code": "columns_3",
+                    "numberOfRegions": 3,
+                    "renderSequence": 3,
+                    "userSelectable": true
+                },
+                "confirmPassword": null,
+                "defaultPageLayoutCode": null,
+                "authorities": [
+                    {
+                        "id": 1,
+                        "authority": "ROLE_USER",
+                        "users": [],
+                        "defaultForNewUser": true
+                    }
+                ],
+                "pageUsers": [],
+                "widgetTags": [],
+                "id": 5,
+                "accountNonLocked": true,
+                "credentialsNonExpired": true,
+                "accountNonExpired": true
+            }
+        ]
+    },
+    {
+        "id": 2,
+        "title": "Portal",
+        "description": "Portal Group",
+        "owner": null,
+        "members": [
+            {
+                "id": 1,
+                "username": "canonical",
+                "email": "canonical@example.com",
+                "displayName": "Canonical User",
+                "additionalName": null,
+                "familyName": "User",
+                "givenName": "Canonical",
+                "honorificPrefix": null,
+                "honorificSuffix": null,
+                "preferredName": null,
+                "aboutMe": null,
+                "status": "Single",
+                "addresses": [],
+                "organizations": [],
+                "properties": [],
+                "groups": [],
+                "password": "$2a$10$TkEgze5kLy9nRlfd8PT1zunh6P1ND8WPjLojFjAMNgZMu1D9D1n4.",
+                "expired": false,
+                "locked": false,
+                "enabled": true,
+                "openId": null,
+                "forgotPasswordHash": null,
+                "forgotPasswordTime": null,
+                "defaultPageLayout": {
+                    "id": 4,
+                    "code": "columns_3",
+                    "numberOfRegions": 3,
+                    "renderSequence": 3,
+                    "userSelectable": true
+                },
+                "confirmPassword": null,
+                "defaultPageLayoutCode": null,
+                "authorities": [
+                    {
+                        "id": 2,
+                        "authority": "ROLE_ADMIN",
+                        "users": [],
+                        "defaultForNewUser": false
+                    }
+                ],
+                "pageUsers": [],
+                "widgetTags": [],
+                "id": 1,
+                "accountNonLocked": true,
+                "credentialsNonExpired": true,
+                "accountNonExpired": true
+            },
+            {
+                "id": 2,
+                "username": "john.doe",
+                "email": "john.doe@example.com",
+                "displayName": "John Doe",
+                "additionalName": null,
+                "familyName": "Doe",
+                "givenName": "John",
+                "honorificPrefix": null,
+                "honorificSuffix": null,
+                "preferredName": null,
+                "aboutMe": null,
+                "status": "Single",
+                "addresses": [],
+                "organizations": [],
+                "properties": [],
+                "groups": [],
+                "password": "$2a$10$8Dir7boy3UyVqy6erfj6WuQXUTf.ejTldPSsVIty7.pPT3Krkly26",
+                "expired": false,
+                "locked": false,
+                "enabled": true,
+                "openId": null,
+                "forgotPasswordHash": null,
+                "forgotPasswordTime": null,
+                "defaultPageLayout": {
+                    "id": 4,
+                    "code": "columns_3",
+                    "numberOfRegions": 3,
+                    "renderSequence": 3,
+                    "userSelectable": true
+                },
+                "confirmPassword": null,
+                "defaultPageLayoutCode": null,
+                "authorities": [
+                    {
+                        "id": 1,
+                        "authority": "ROLE_USER",
+                        "users": [],
+                        "defaultForNewUser": true
+                    }
+                ],
+                "pageUsers": [],
+                "widgetTags": [],
+                "id": 2,
+                "accountNonLocked": true,
+                "credentialsNonExpired": true,
+                "accountNonExpired": true
+            }
+        ]
+    }
+],
+    "widgets": [
+    {
+        "id" : 1,
+        "title": "Wikipedia",
+        "titleUrl": "http://en.wikipedia.org/wiki/Main_Page",
+        "url": "http://www.widget-dico.com/wikipedia/google/wikipedia.xml",
+        "type": "OpenSocial",
+        "author": "WidgetMe",
+        "authorEmail": "google@widgetme.com",
+        "description": "A Wikipedia Search and Go widget. Language choice.",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 2,
+        "title": "Translate Gadget",
+        "titleUrl": "http://translate.google.com/",
+        "url": "http://www.gstatic.com/ig/modules/dictionary/dictionary.xml",
+        "type": "OpenSocial",
+        "author": "Google Taiwan",
+        "authorEmail": "googlemodules+dictionary+201109071@google.com",
+        "description": "Google Translation gadget.",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 3,
+        "title": "NYTimes.com - Top Stories",
+        "url": "http://widgets.nytimes.com/packages/html/igoogle/topstories.xml",
+        "type": "OpenSocial",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 4,
+        "title": "Google News Gadget",
+        "url": "http://www.gstatic.com/ig/modules/tabnews/tabnews.xml",
+        "type": "OpenSocial",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 5,
+        "title": "Pet Hamster",
+        "url": "http://hosting.gmodules.com/ig/gadgets/file/112581010116074801021/hamster.xml",
+        "type": "OpenSocial",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 6,
+        "title": "Herbie Hamster Virtual Pet",
+        "url": "http://hosting.gmodules.com/ig/gadgets/file/109548057311228444554/hamster.xml",
+        "type": "OpenSocial",
+        "author": "Naj",
+        "description": "A cute little hamster for you to feed and look after. Watch him follow your cursor around. Click on the more tab to treat him to a strawberry. Click him then put him on the wheel and watch him play! ***NEW: make Herbie hamster your very own!",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 7,
+        "title": "List of CTSS Resources - Map View",
+        "url": "http://localhost:8080/demogadgets/CTSSResourcesMapView.xml",
+        "type": "OpenSocial",
+        "author": "Suresh Deivasigamani",
+        "description": "This is a gadget developed for Teragrid - OGCE project. Used Google gadgets API to retrieve the information from the Information Services REST Web Service and display the information using Google Maps API. This is a list of available CTSS resources and its details",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 8,
+        "title": "Twitter",
+        "url": "http://localhost:8080/demogadgets/twitter.xml",
+        "type": "OpenSocial",
+        "author": "LOGIKA Corporation",
+        "description": "Fully functional, lightweight, AJAX-based twitter user interface with many configuration options including user specified auto-refresh rate, full timeline, pagination, and more.  Control display elements such as user thumbnails, date stamps, and post source.  Specify gadget size based on availble screen footprint, even incorporate into your Gmail account.  Insert symbols, dingbats and emoticons into your tweets using the TwitterGadget Symbols pulldown menu.",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 9,
+        "title": "Youtube",
+        "url": "http://localhost:8080/demogadgets/youtubesearch.xml",
+        "type": "OpenSocial",
+        "author": "David Olsen",
+        "description": "A search module, which searches YouTube by tags like Politics News Life Music Family Photography Art Random Travel Personal Religion Movies Business Thoughts Media Humor Culture Poetry Christmas Writing Books Food Friends.",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 10,
+        "title": "Open Views Demo",
+        "url": "http://localhost:8080/demogadgets/open_views_demo.xml",
+        "type": "OpenSocial",
+        "author": "Erin Noe-Payne",
+        "description": "A demo gadget to show open views popups in action.",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 11,
+        "title": "Gadget View Type",
+        "url": "http://localhost:8080/demogadgets/canvas-nav.xml",
+        "type": "OpenSocial",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 12,
+        "title": "User Prefs Demo",
+        "url": "http://localhost:8080/demogadgets/user_prefs_demo.xml",
+        "type": "OpenSocial",
+        "author": "Anthony Carlucci",
+        "description": "An example gadget which demos some of the different capabilities of user preferences.",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 13,
+        "title": "My Activity",
+        "url": "http://localhost:8080/demogadgets/my_activity.xml",
+        "type": "OpenSocial",
+        "author": "Anthony Carlucci",
+        "description": "Static widget of activities for demoing on the Person Profile page",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 14,
+        "title": "Current Schedule",
+        "url": "http://localhost:8080/demogadgets/schedule.xml",
+        "type": "OpenSocial",
+        "author": "Anthony Carlucci",
+        "description": "Static widget of a schedule for demoing on the Person Profile page",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 15,
+        "title": "Favorite Websites",
+        "url": "http://localhost:8080/demogadgets/favorite_websites.xml",
+        "type": "OpenSocial",
+        "author": "Anthony Carlucci",
+        "description": "Static widget of favorite websites for demoing on the Person Profile page",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 16,
+        "title": "My Groups",
+        "url": "http://localhost:8080/demogadgets/my_groups.xml",
+        "type": "OpenSocial",
+        "author": "Anthony Carlucci",
+        "description": "Static widget of groups for demoing on the Person Profile page",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 17,
+        "title": "My Experience",
+        "url": "http://localhost:8080/demogadgets/my_experience.xml",
+        "type": "OpenSocial",
+        "author": "Anthony Carlucci",
+        "description": "Static widget of experience for demoing on the Person Profile page",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 18,
+        "title": "Activity Streams",
+        "url": "http://localhost:8080/samplecontainer/examples/ActivityStreams/ActivityStreamGadget.xml",
+        "type": "OpenSocial",
+        "author": "Apache Shindig",
+        "description": "Sample Activity Streams gadget from Shindig",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 19,
+        "title": "Album Viewer",
+        "url": "http://localhost:8080/samplecontainer/examples/embeddedexperiences/AlbumViewer.xml",
+        "type": "OpenSocial",
+        "author": "Apache Shindig",
+        "description": "Sample Embedded Experience gadget from Shindig",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 20,
+        "title": "Photo List",
+        "url": "http://localhost:8080/samplecontainer/examples/embeddedexperiences/PhotoList.xml",
+        "type": "OpenSocial",
+        "author": "Apache Shindig",
+        "description": "Sample Embedded Experience gadget from Shindig",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 21,
+        "title": "OAuth2 Facebook",
+        "url": "http://localhost:8080/samplecontainer/examples/oauth2/oauth2_facebook.xml",
+        "type": "OpenSocial",
+        "author": "Apache Shindig",
+        "description": "Sample Facebook gadget from Shindig",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 22,
+        "title": "Ohloh Apache Rave Languages",
+        "url": "http://www.ohloh.net/p/521520/widgets/project_languages.xml",
+        "type": "OpenSocial",
+        "author": "Ohloh",
+        "description": "Ohloh is an open source network that connects people through the software they create and use. Ohloh gadgets provide detailed statistics about open source software projects and developers.",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 23,
+        "title": "Ohloh Apache Rave Factoids",
+        "url": "http://www.ohloh.net/p/521520/widgets/project_factoids.xml",
+        "type": "OpenSocial",
+        "author": "Ohloh",
+        "description": "Ohloh is an open source network that connects people through the software they create and use. Ohloh gadgets provide detailed statistics about open source software projects and developers.",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 24,
+        "title": "Ohloh Apache Rave COCOMO Estimates",
+        "url": "http://www.ohloh.net/p/521520/widgets/project_cocomo.xml",
+        "type": "OpenSocial",
+        "author": "Ohloh",
+        "description": "Ohloh is an open source network that connects people through the software they create and use. Ohloh gadgets provide detailed statistics about open source software projects and developers.",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 25,
+        "title": "Ohloh Apache Rave Stats",
+        "url": "http://www.ohloh.net/p/521520/widgets/project_basic_stats.xml",
+        "type": "OpenSocial",
+        "author": "Ohloh",
+        "description": "Ohloh is an open source network that connects people through the software they create and use. Ohloh gadgets provide detailed statistics about open source software projects and developers.",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 26,
+        "title": "OpenAJAX Hub Publisher",
+        "url": "http://localhost:8080/container/sample-pubsub-2-publisher.xml",
+        "type": "OpenSocial",
+        "author": "Apache Shindig",
+        "description": "OpenAJAX Hub publisher gadget from Shindig",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 27,
+        "title": "OpenAJAX Hub Subscriber",
+        "url": "http://localhost:8080/container/sample-pubsub-2-subscriber.xml",
+        "type": "OpenSocial",
+        "author": "Apache Shindig",
+        "description": "OpenAJAX Hub subscriber gadget from Shindig",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    },
+    {
+        "id" : 28,
+        "title": "Friends",
+        "url": "http://localhost:8080/demogadgets/friends.xml",
+        "type": "OpenSocial",
+        "author": "Viknes Balasubramanee",
+        "description": "This gadget display the list of friends for a particular user",
+        "disableRendering": false,
+        "featured": false,
+        "widgetStatus": "PUBLISHED"
+    }
+],
+    "authorities": [
+    {
+        "id": 1,
+        "authority": "ROLE_USER",
+        "users": [],
+        "defaultForNewUser": true
+    },
+    {
+        "id": 2,
+        "authority": "ROLE_ADMIN",
+        "users": [],
+        "defaultForNewUser": false
+    }
+],
+    "portalPreferences": [
+    {
+        "id": 1,
+        "key": "titleSuffix",
+        "values": [
+            " - Rave"
+        ],
+        "value": " - Rave"
+    },
+    {
+        "id": 2,
+        "key": "pageSize",
+        "values": [
+            "10"
+        ],
+        "value": "10"
+    },
+    {
+        "id": 3,
+        "key": "javaScriptDebugMode",
+        "values": [
+            "1"
+        ],
+        "value": "1"
+    },
+    {
+        "id": 4,
+        "key": "defaultWidgetHeight",
+        "values": [
+            "250"
+        ],
+        "value": "250"
+    },
+    {
+        "id": 5,
+        "key": "showStackTrace",
+        "values": [
+            "0"
+        ],
+        "value": "0"
+    }
+],
+    "categories": [
+    {
+        "id": 1,
+        "text": "Technology",
+        "createdUser": {
+            "id": 1,
+            "username": "canonical",
+            "email": "canonical@example.com",
+            "displayName": "Canonical User",
+            "additionalName": null,
+            "familyName": "User",
+            "givenName": "Canonical",
+            "honorificPrefix": null,
+            "honorificSuffix": null,
+            "preferredName": null,
+            "aboutMe": null,
+            "status": "Single",
+            "addresses": [],
+            "organizations": [],
+            "properties": [],
+            "groups": [],
+            "password": "$2a$10$TkEgze5kLy9nRlfd8PT1zunh6P1ND8WPjLojFjAMNgZMu1D9D1n4.",
+            "expired": false,
+            "locked": false,
+            "enabled": true,
+            "openId": null,
+            "forgotPasswordHash": null,
+            "forgotPasswordTime": null,
+            "defaultPageLayout": {
+                "id": 4,
+                "code": "columns_3",
+                "numberOfRegions": 3,
+                "renderSequence": 3,
+                "userSelectable": true
+            },
+            "confirmPassword": null,
+            "defaultPageLayoutCode": null,
+            "authorities": [
+                {
+                    "id": 2,
+                    "authority": "ROLE_ADMIN",
+                    "users": [],
+                    "defaultForNewUser": false
+                }
+            ],
+            "pageUsers": [],
+            "widgetTags": [],
+            "id": 1,
+            "accountNonLocked": true,
+            "credentialsNonExpired": true,
+            "accountNonExpired": true
+        },
+        "createdDate": 1326949200000,
+        "lastModifiedUser": {
+            "id": 1,
+            "username": "canonical",
+            "email": "canonical@example.com",
+            "displayName": "Canonical User",
+            "additionalName": null,
+            "familyName": "User",
+            "givenName": "Canonical",
+            "honorificPrefix": null,
+            "honorificSuffix": null,
+            "preferredName": null,
+            "aboutMe": null,
+            "status": "Single",
+            "addresses": [],
+            "organizations": [],
+            "properties": [],
+            "groups": [],
+            "password": "$2a$10$TkEgze5kLy9nRlfd8PT1zunh6P1ND8WPjLojFjAMNgZMu1D9D1n4.",
+            "expired": false,
+            "locked": false,
+            "enabled": true,
+            "openId": null,
+            "forgotPasswordHash": null,
+            "forgotPasswordTime": null,
+            "defaultPageLayout": {
+                "id": 4,
+                "code": "columns_3",
+                "numberOfRegions": 3,
+                "renderSequence": 3,
+                "userSelectable": true
+            },
+            "confirmPassword": null,
+            "defaultPageLayoutCode": null,
+            "authorities": [
+                {
+                    "id": 2,
+                    "authority": "ROLE_ADMIN",
+                    "users": [],
+                    "defaultForNewUser": false
+                }
+            ],
+            "pageUsers": [],
+            "widgetTags": [],
+            "id": 1,
+            "accountNonLocked": true,
+            "credentialsNonExpired": true,
+            "accountNonExpired": true
+        },
+        "lastModifiedDate": 1326949200000,
+        "id": 1
+    },
+    {
+        "id": 2,
+        "text": "News",
+        "createdUser": {
+            "id": 1,
+            "username": "canonical",
+            "email": "canonical@example.com",
+            "displayName": "Canonical User",
+            "additionalName": null,
+            "familyName": "User",
+            "givenName": "Canonical",
+            "honorificPrefix": null,
+            "honorificSuffix": null,
+            "preferredName": null,
+            "aboutMe": null,
+            "status": "Single",
+            "addresses": [],
+            "organizations": [],
+            "properties": [],
+            "groups": [],
+            "password": "$2a$10$TkEgze5kLy9nRlfd8PT1zunh6P1ND8WPjLojFjAMNgZMu1D9D1n4.",
+            "expired": false,
+            "locked": false,
+            "enabled": true,
+            "openId": null,
+            "forgotPasswordHash": null,
+            "forgotPasswordTime": null,
+            "defaultPageLayout": {
+                "id": 4,
+                "code": "columns_3",
+                "numberOfRegions": 3,
+                "renderSequence": 3,
+                "userSelectable": true
+            },
+            "confirmPassword": null,
+            "defaultPageLayoutCode": null,
+            "authorities": [
+                {
+                    "id": 2,
+                    "authority": "ROLE_ADMIN",
+                    "users": [],
+                    "defaultForNewUser": false
+                }
+            ],
+            "pageUsers": [],
+            "widgetTags": [],
+            "id": 1,
+            "accountNonLocked": true,
+            "credentialsNonExpired": true,
+            "accountNonExpired": true
+        },
+        "createdDate": 1326949200000,
+        "lastModifiedUser": {
+            "id": 1,
+            "username": "canonical",
+            "email": "canonical@example.com",
+            "displayName": "Canonical User",
+            "additionalName": null,
+            "familyName": "User",
+            "givenName": "Canonical",
+            "honorificPrefix": null,
+            "honorificSuffix": null,
+            "preferredName": null,
+            "aboutMe": null,
+            "status": "Single",
+            "addresses": [],
+            "organizations": [],
+            "properties": [],
+            "groups": [],
+            "password": "$2a$10$TkEgze5kLy9nRlfd8PT1zunh6P1ND8WPjLojFjAMNgZMu1D9D1n4.",
+            "expired": false,
+            "locked": false,
+            "enabled": true,
+            "openId": null,
+            "forgotPasswordHash": null,
+            "forgotPasswordTime": null,
+            "defaultPageLayout": {
+                "id": 4,
+                "code": "columns_3",
+                "numberOfRegions": 3,
+                "renderSequence": 3,
+                "userSelectable": true
+            },
+            "confirmPassword": null,
+            "defaultPageLayoutCode": null,
+            "authorities": [
+                {
+                    "id": 2,
+                    "authority": "ROLE_ADMIN",
+                    "users": [],
+                    "defaultForNewUser": false
+                }
+            ],
+            "pageUsers": [],
+            "widgetTags": [],
+            "id": 1,
+            "accountNonLocked": true,
+            "credentialsNonExpired": true,
+            "accountNonExpired": true
+        },
+        "lastModifiedDate": 1326949200000,
+        "id": 2
+    },
+    {
+        "id": 3,
+        "text": "Travel",
+        "createdUser": {
+            "id": 1,
+            "username": "canonical",
+            "email": "canonical@example.com",
+            "displayName": "Canonical User",
+            "additionalName": null,
+            "familyName": "User",
+            "givenName": "Canonical",
+            "honorificPrefix": null,
+            "honorificSuffix": null,
+            "preferredName": null,
+            "aboutMe": null,
+            "status": "Single",
+            "addresses": [],
+            "organizations": [],
+            "properties": [],
+            "groups": [],
+            "password": "$2a$10$TkEgze5kLy9nRlfd8PT1zunh6P1ND8WPjLojFjAMNgZMu1D9D1n4.",
+            "expired": false,
+            "locked": false,
+            "enabled": true,
+            "openId": null,
+            "forgotPasswordHash": null,
+            "forgotPasswordTime": null,
+            "defaultPageLayout": {
+                "id": 4,
+                "code": "columns_3",
+                "numberOfRegions": 3,
+                "renderSequence": 3,
+                "userSelectable": true
+            },
+            "confirmPassword": null,
+            "defaultPageLayoutCode": null,
+            "authorities": [
+                {
+                    "id": 2,
+                    "authority": "ROLE_ADMIN",
+                    "users": [],
+                    "defaultForNewUser": false
+                }
+            ],
+            "pageUsers": [],
+            "widgetTags": [],
+            "id": 1,
+            "accountNonLocked": true,
+            "credentialsNonExpired": true,
+            "accountNonExpired": true
+        },
+        "createdDate": 1326949200000,
+        "lastModifiedUser": {
+            "id": 1,
+            "username": "canonical",
+            "email": "canonical@example.com",
+            "displayName": "Canonical User",
+            "additionalName": null,
+            "familyName": "User",
+            "givenName": "Canonical",
+            "honorificPrefix": null,
+            "honorificSuffix": null,
+            "preferredName": null,
+            "aboutMe": null,
+            "status": "Single",
+            "addresses": [],
+            "organizations": [],
+            "properties": [],
+            "groups": [],
+            "password": "$2a$10$TkEgze5kLy9nRlfd8PT1zunh6P1ND8WPjLojFjAMNgZMu1D9D1n4.",
+            "expired": false,
+            "locked": false,
+            "enabled": true,
+            "openId": null,
+            "forgotPasswordHash": null,
+            "forgotPasswordTime": null,
+            "defaultPageLayout": {
+                "id": 4,
+                "code": "columns_3",
+                "numberOfRegions": 3,
+                "renderSequence": 3,
+                "userSelectable": true
+            },
+            "confirmPassword": null,
+            "defaultPageLayoutCode": null,
+            "authorities": [
+                {
+                    "id": 2,
+                    "authority": "ROLE_ADMIN",
+                    "users": [],
+                    "defaultForNewUser": false
+                }
+            ],
+            "pageUsers": [],
+            "widgetTags": [],
+            "id": 1,
+            "accountNonLocked": true,
+            "credentialsNonExpired": true,
+            "accountNonExpired": true
+        },
+        "lastModifiedDate": 1326949200000,
+        "id": 3
+    },
+    {
+        "id": 4,
+        "text": "Projects",
+        "createdUser": {
+            "id": 1,
+            "username": "canonical",
+            "email": "canonical@example.com",
+            "displayName": "Canonical User",
+            "additionalName": null,
+            "familyName": "User",
+            "givenName": "Canonical",
+            "honorificPrefix": null,
+            "honorificSuffix": null,
+            "preferredName": null,
+            "aboutMe": null,
+            "status": "Single",
+            "addresses": [],
+            "organizations": [],
+            "properties": [],
+            "groups": [],
+            "password": "$2a$10$TkEgze5kLy9nRlfd8PT1zunh6P1ND8WPjLojFjAMNgZMu1D9D1n4.",
+            "expired": false,
+            "locked": false,
+            "enabled": true,
+            "openId": null,
+            "forgotPasswordHash": null,
+            "forgotPasswordTime": null,
+            "defaultPageLayout": {
+                "id": 4,
+                "code": "columns_3",
+                "numberOfRegions": 3,
+                "renderSequence": 3,
+                "userSelectable": true
+            },
+            "confirmPassword": null,
+            "defaultPageLayoutCode": null,
+            "authorities": [
+                {
+                    "id": 2,
+                    "authority": "ROLE_ADMIN",
+                    "users": [],
+                    "defaultForNewUser": false
+                }
+            ],
+            "pageUsers": [],
+            "widgetTags": [],
+            "id": 1,
+            "accountNonLocked": true,
+            "credentialsNonExpired": true,
+            "accountNonExpired": true
+        },
+        "createdDate": 1326949200000,
+        "lastModifiedUser": {
+            "id": 1,
+            "username": "canonical",
+            "email": "canonical@example.com",
+            "displayName": "Canonical User",
+            "additionalName": null,
+            "familyName": "User",
+            "givenName": "Canonical",
+            "honorificPrefix": null,
+            "honorificSuffix": null,
+            "preferredName": null,
+            "aboutMe": null,
+            "status": "Single",
+            "addresses": [],
+            "organizations": [],
+            "properties": [],
+            "groups": [],
+            "password": "$2a$10$TkEgze5kLy9nRlfd8PT1zunh6P1ND8WPjLojFjAMNgZMu1D9D1n4.",
+            "expired": false,
+            "locked": false,
+            "enabled": true,
+            "openId": null,
+            "forgotPasswordHash": null,
+            "forgotPasswordTime": null,
+            "defaultPageLayout": {
+                "id": 4,
+                "code": "columns_3",
+                "numberOfRegions": 3,
+                "renderSequence": 3,
+                "userSelectable": true
+            },
+            "confirmPassword": null,
+            "defaultPageLayoutCode": null,
+            "authorities": [
+                {
+                    "id": 2,
+                    "authority": "ROLE_ADMIN",
+                    "users": [],
+                    "defaultForNewUser": false
+                }
+            ],
+            "pageUsers": [],
+            "widgetTags": [],
+            "id": 1,
+            "accountNonLocked": true,
+            "credentialsNonExpired": true,
+            "accountNonExpired": true
+        },
+        "lastModifiedDate": 1326949200000,
+        "id": 4
+    },
+    {
+        "id": 5,
+        "text": "Communications",
+        "createdUser": {
+            "id": 1,
+            "username": "canonical",
+            "email": "canonical@example.com",
+            "displayName": "Canonical User",
+            "additionalName": null,
+            "familyName": "User",
+            "givenName": "Canonical",
+            "honorificPrefix": null,
+            "honorificSuffix": null,
+            "preferredName": null,
+            "aboutMe": null,
+            "status": "Single",
+            "addresses": [],
+            "organizations": [],
+            "properties": [],
+            "groups": [],
+            "password": "$2a$10$TkEgze5kLy9nRlfd8PT1zunh6P1ND8WPjLojFjAMNgZMu1D9D1n4.",
+            "expired": false,
+            "locked": false,
+            "enabled": true,
+            "openId": null,
+            "forgotPasswordHash": null,
+            "forgotPasswordTime": null,
+            "defaultPageLayout": {
+                "id": 4,
+                "code": "columns_3",
+                "numberOfRegions": 3,
+                "renderSequence": 3,
+                "userSelectable": true
+            },
+            "confirmPassword": null,
+            "defaultPageLayoutCode": null,
+            "authorities": [
+                {
+                    "id": 2,
+                    "authority": "ROLE_ADMIN",
+                    "users": [],
+                    "defaultForNewUser": false
+                }
+            ],
+            "pageUsers": [],
+            "widgetTags": [],
+            "id": 1,
+            "accountNonLocked": true,
+            "credentialsNonExpired": true,
+            "accountNonExpired": true
+        },
+        "createdDate": 1326949200000,
+        "lastModifiedUser": {
+            "id": 1,
+            "username": "canonical",
+            "email": "canonical@example.com",
+            "displayName": "Canonical User",
+            "additionalName": null,
+            "familyName": "User",
+            "givenName": "Canonical",
+            "honorificPrefix": null,
+            "honorificSuffix": null,
+            "preferredName": null,
+            "aboutMe": null,
+            "status": "Single",
+            "addresses": [],
+            "organizations": [],
+            "properties": [],
+            "groups": [],
+            "password": "$2a$10$TkEgze5kLy9nRlfd8PT1zunh6P1ND8WPjLojFjAMNgZMu1D9D1n4.",
+            "expired": false,
+            "locked": false,
+            "enabled": true,
+            "openId": null,
+            "forgotPasswordHash": null,
+            "forgotPasswordTime": null,
+            "defaultPageLayout": {
+                "id": 4,
+                "code": "columns_3",
+                "numberOfRegions": 3,
+                "renderSequence": 3,
+                "userSelectable": true
+            },
+            "confirmPassword": null,
+            "defaultPageLayoutCode": null,
+            "authorities": [
+                {
+                    "id": 2,
+                    "authority": "ROLE_ADMIN",
+                    "users": [],
+                    "defaultForNewUser": false
+                }
+            ],
+            "pageUsers": [],
+            "widgetTags": [],
+            "id": 1,
+            "accountNonLocked": true,
+            "credentialsNonExpired": true,
+            "accountNonExpired": true
+        },
+        "lastModifiedDate": 1326949200000,
+        "id": 5
+    }
+],
+    "pageTemplates": [
+    {
+        "id": 1,
+        "name": "Person Profile",
+        "description": "Template for person profile pages",
+        "pageType": "PERSON_PROFILE",
+        "parentPageTemplate": null,
+        "subPageTemplates": [
+            {
+                "id": 2,
+                "name": "About",
+                "description": "Template for the About sub page for the person profile",
+                "pageType": "SUB_PAGE",
+                "parentPageTemplate": null,
+                "subPageTemplates": [],
+                "pageLayout": {
+                    "id": 1,
+                    "code": "columns_1",
+                    "numberOfRegions": 1,
+                    "renderSequence": 0,
+                    "userSelectable": true
+                },
+                "pageTemplateRegions": [
+                    {
+                        "id": 2,
+                        "renderSequence": 0,
+                        "pageTemplate": null,
+                        "pageTemplateWidgets": [
+                            {
+                                "id": 3,
+                                "pageTemplateRegion": null,
+                                "widget": {
+                                    "id" : 15,
+                                    "title": "Favorite Websites",
+                                    "url": "http://localhost:8080/demogadgets/favorite_websites.xml",
+                                    "type": "OpenSocial",
+                                    "author": "Anthony Carlucci",
+                                    "description": "Static widget of favorite websites for demoing on the Person Profile page",
+                                    "disableRendering": false,
+                                    "featured": false,
+                                    "status": "PUBLISHED"
+                                },
+                                "locked": true,
+                                "hideChrome": false,
+                                "id": 3,
+                                "renderSeq": 0
+                            },
+                            {
+                                "id": 4,
+                                "pageTemplateRegion": null,
+                                "widget": {
+                                    "id" :14,
+                                    "title": "Current Schedule",
+                                    "url": "http://localhost:8080/demogadgets/schedule.xml",
+                                    "type": "OpenSocial",
+                                    "author": "Anthony Carlucci",
+                                    "description": "Static widget of a schedule for demoing on the Person Profile page",
+                                    "disableRendering": false,
+                                    "featured": false,
+                                    "status": "PUBLISHED"
+                                },
+                                "locked": true,
+                                "hideChrome": false,
+                                "id": 4,
+                                "renderSeq": 1
+                            }
+                        ],
+                        "locked": true,
+                        "id": 2
+                    }
+                ],
+                "renderSequence": 0,
+                "defaultTemplate": false,
+                "id": 2
+            },
+            {
+                "id": 3,
+                "name": "My Activity",
+                "description": "Template for the My Activity sub page for the person profile",
+                "pageType": "SUB_PAGE",
+                "parentPageTemplate": null,
+                "subPageTemplates": [],
+                "pageLayout": {
+                    "id": 1,
+                    "code": "columns_1",
+                    "numberOfRegions": 1,
+                    "renderSequence": 0,
+                    "userSelectable": true
+                },
+                "pageTemplateRegions": [
+                    {
+                        "id": 3,
+                        "renderSequence": 0,
+                        "pageTemplate": null,
+                        "pageTemplateWidgets": [
+                            {
+                                "id": 5,
+                                "pageTemplateRegion": null,
+                                "widget": {
+                                    "id": 3,
+                                    "title": "My Activity",
+                                    "url": "http://localhost:8080/demogadgets/my_activity.xml",
+                                    "type": "OpenSocial",
+                                    "author": "Anthony Carlucci",
+                                    "description": "Static widget of activities for demoing on the Person Profile page",
+                                    "disableRendering": false,
+                                    "featured": false,
+                                    "status": "PUBLISHED"
+                                },
+                                "locked": true,
+                                "hideChrome": false,
+                                "id": 5,
+                                "renderSeq": 0
+                            }
+                        ],
+                        "locked": true,
+                        "id": 3
+                    }
+                ],
+                "renderSequence": 1,
+                "defaultTemplate": false,
+                "id": 3
+            }
+        ],
+        "pageLayout": {
+            "id": 9,
+            "code": "person_profile",
+            "numberOfRegions": 1,
+            "renderSequence": 8,
+            "userSelectable": false
+        },
+        "pageTemplateRegions": [
+            {
+                "id": 1,
+                "renderSequence": 0,
+                "pageTemplate": null,
+                "pageTemplateWidgets": [
+                    {
+                        "id": 1,
+                        "pageTemplateRegion": null,
+                        "widget": {
+                            "id": 16,
+                            "title": "My Groups",
+                            "url": "http://localhost:8080/demogadgets/my_groups.xml",
+                            "type": "OpenSocial",
+                            "author": "Anthony Carlucci",
+                            "description": "Static widget of groups for demoing on the Person Profile page",
+                            "disableRendering": false,
+                            "featured": false,
+                            "status": "PUBLISHED"
+                        },
+                        "locked": true,
+                        "hideChrome": true,
+                        "id": 1,
+                        "renderSeq": 0
+                    },
+                    {
+                        "id": 2,
+                        "pageTemplateRegion": null,
+                        "widget": {
+                            "id": 17,
+                            "title": "My Experience",
+                            "url": "http://localhost:8080/demogadgets/my_experience.xml",
+                            "type": "OpenSocial",
+                            "author": "Anthony Carlucci",
+                            "description": "Static widget of experience for demoing on the Person Profile page",
+                            "disableRendering": false,
+                            "featured": false,
+                            "status": "PUBLISHED"
+                        },
+                        "locked": true,
+                        "hideChrome": true,
+                        "id": 2,
+                        "renderSeq": 1
+                    }
+                ],
+                "locked": true,
+                "id": 1
+            }
+        ],
+        "renderSequence": 0,
+        "defaultTemplate": true,
+        "id": 1
+    },
+    {
+        "id": 2,
+        "name": "Default Home",
+        "description": "Default User Template",
+        "pageType": "USER",
+        "parentPageTemplate": null,
+        "subPageTemplates": [],
+        "pageLayout": {
+            "id": 1,
+            "code": "columns_3_newuser",
+            "numberOfRegions": 1,
+            "renderSequence": 0,
+            "userSelectable": true
+        },
+        "pageTemplateRegions": [
+            {
+                "renderSequence": 0,
+                "pageTemplate": null,
+                "pageTemplateWidgets": [
+                    {
+                        "pageTemplateRegion": null,
+                        "widget": {"id": 2},
+                        "locked": false,
+                        "hideChrome": false,
+                        "id": 3,
+                        "renderSeq": 0
+                    },
+                    {
+                        "pageTemplateRegion": null,
+                        "widget": {"id": 7},
+                        "locked": false,
+                        "hideChrome": false,
+                        "id": 4,
+                        "renderSeq": 1
+                    }
+                ],
+                "locked": false,
+                "id": 2
+            },
+            {
+                "renderSequence": 1,
+                "pageTemplate": null,
+                "pageTemplateWidgets": [
+                    {
+                        "pageTemplateRegion": null,
+                        "widget": {"id": 10},
+                        "locked": false,
+                        "hideChrome": false,
+                        "id": 3,
+                        "renderSeq": 0
+                    },
+                    {
+                        "pageTemplateRegion": null,
+                        "widget": {"id": 23},
+                        "locked": false,
+                        "hideChrome": false,
+                        "id": 4,
+                        "renderSeq": 1
+                    }
+                ],
+                "locked": false,
+                "id": 2
+            },
+            {
+                "renderSequence": 2,
+                "pageTemplate": null,
+                "pageTemplateWidgets": [
+                    {
+                        "pageTemplateRegion": null,
+                        "widget": {"id": 11},
+                        "locked": false,
+                        "hideChrome": false,
+                        "id": 3,
+                        "renderSeq": 0
+                    }
+                ],
+                "locked": false,
+                "id": 2
+            }
+        ],
+        "renderSequence": 0,
+        "defaultTemplate": true,
+        "id": 2
+    }
+]
+}
\ No newline at end of file
diff --git a/rave-portal/src/test/resources_mongo/test-dataContext.xml b/rave-portal/src/test/resources_mongo/test-dataContext.xml
new file mode 100644
index 0000000..bb96231
--- /dev/null
+++ b/rave-portal/src/test/resources_mongo/test-dataContext.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+  -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                           http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+    <bean id="dataImporter" class="org.apache.rave.portal.util.data.DataImporter">
+        <property name="dataExecutor">
+            <bean class="org.apache.rave.portal.util.data.DataImporter$ExecutorImpl" />
+        </property>
+        <property name="scriptLocations">
+            <list>
+                <value>classpath:initial-data.json</value>
+            </list>
+        </property>
+    </bean>
+</beans>
\ No newline at end of file
diff --git a/rave-providers/rave-opensocial-provider/rave-opensocial-client/src/main/java/org/apache/rave/provider/opensocial/web/renderer/OpenSocialWidgetRenderer.java b/rave-providers/rave-opensocial-provider/rave-opensocial-client/src/main/java/org/apache/rave/provider/opensocial/web/renderer/OpenSocialWidgetRenderer.java
index 56dfb8c..08fc287 100644
--- a/rave-providers/rave-opensocial-provider/rave-opensocial-client/src/main/java/org/apache/rave/provider/opensocial/web/renderer/OpenSocialWidgetRenderer.java
+++ b/rave-providers/rave-opensocial-provider/rave-opensocial-client/src/main/java/org/apache/rave/provider/opensocial/web/renderer/OpenSocialWidgetRenderer.java
@@ -64,19 +64,19 @@
     //Note the widgets.push() call.  This defines the widget objects, which are
     //added to the widgets[] array in home.jsp.
     private static final String SCRIPT_BLOCK =
-            "<script>rave.registerWidget(%1$s, {type: '%2$s'," +
-            " regionWidgetId: %3$s," +
+            "<script>rave.registerWidget('%1$s', {type: '%2$s'," +
+            " regionWidgetId: '%3$s'," +
             " widgetUrl: '%4$s', " +
             " securityToken: '%5$s', " +
             " metadata: %6$s," +
             " userPrefs: %7$s," +
             " collapsed: %8$s, " +
-            " widgetId: %9$s," +
+            " widgetId: '%9$s'," +
             " locked: %10$s," +
             " hideChrome: %11$s," +
             " subPage: {id: %12$s, name: '%13$s', isDefault: %14$s}" +
             "});</script>";
-    private static final String MARKUP = "<!-- RegionWidget %1$s placeholder -->";
+    private static final String MARKUP = "<!-- RegionWidget '%1$s' placeholder -->";
 
     @Override
     public String getSupportedContext() {
@@ -128,7 +128,7 @@
         boolean isDefault = false;
         Page page =  item.getRegion().getPage();
         if (PageType.SUB_PAGE.equals(page.getPageType())) {
-            pageId = page.getId();
+            pageId = "'" + page.getId() + "'";
             pageName = page.getName();
             // check to see if this regionWidget is on the first sub page, which will be the default
             // subpage rendered if the user doesn't specify which subpage via the URL hash
diff --git a/rave-providers/rave-opensocial-provider/rave-opensocial-client/src/test/java/org/apache/rave/provider/opensocial/web/renderer/OpenSocialWidgetRendererTest.java b/rave-providers/rave-opensocial-provider/rave-opensocial-client/src/test/java/org/apache/rave/provider/opensocial/web/renderer/OpenSocialWidgetRendererTest.java
index c5f5327..cde824c 100644
--- a/rave-providers/rave-opensocial-provider/rave-opensocial-client/src/test/java/org/apache/rave/provider/opensocial/web/renderer/OpenSocialWidgetRendererTest.java
+++ b/rave-providers/rave-opensocial-provider/rave-opensocial-client/src/test/java/org/apache/rave/provider/opensocial/web/renderer/OpenSocialWidgetRendererTest.java
@@ -22,7 +22,6 @@
 import org.apache.rave.exception.NotSupportedException;
 import org.apache.rave.portal.model.*;
 import org.apache.rave.portal.model.impl.*;
-import org.apache.rave.portal.service.WidgetService;
 import org.apache.rave.portal.web.renderer.RenderScope;
 import org.apache.rave.portal.web.renderer.Renderer;
 import org.apache.rave.portal.web.renderer.ScriptLocation;
@@ -49,7 +48,6 @@
     private SecurityTokenService securityTokenService;
     private ScriptManager scriptManager;
     private Renderer<RegionWidgetWrapper> renderer;
-    private WidgetService widgetService;
 
     private static final String VALID_GADGET_URL = "http://www.example.com/gadget.xml";
     private static final String VALID_METADATA = "metadata";
@@ -62,7 +60,6 @@
     @Before
     public void setup() {
         renderContext = new RenderContext();
-        widgetService = createMock(WidgetService.class);
         scriptManager = createStrictMock(ScriptManager.class);
         openSocialService = createNiceMock(OpenSocialService.class);
         securityTokenService = createNiceMock(SecurityTokenService.class);
@@ -100,10 +97,6 @@
         w.setType(Constants.WIDGET_TYPE);
         w.setUrl(VALID_GADGET_URL);
 
-        expect(widgetService.getWidget(w.getId())).andReturn(w);
-        expect(widgetService.getWidget(w.getId())).andReturn(w);
-        replay(widgetService);
-
         Region region = new RegionImpl(REGION_ID);
         region.setPage(subPage);
         RegionWidget rw = new RegionWidgetImpl(REGION_WIDGET_ID);
@@ -117,17 +110,17 @@
                                         new RegionWidgetPreferenceImpl( "1", null, null)));
 
         final String markup =
-            "<script>rave.registerWidget(" + REGION_ID + " , {type: 'OpenSocial'," +
-            " regionWidgetId: " + REGION_WIDGET_ID + "," +
+            "<script>rave.registerWidget('" + REGION_ID + "', {type: 'OpenSocial'," +
+            " regionWidgetId: '" + REGION_WIDGET_ID + "'," +
             " widgetUrl: '" + VALID_GADGET_URL +"', " +
             " securityToken: '" + VALID_SECURITY_TOKEN + "', " +
             " metadata: " + VALID_METADATA + "," +
             " userPrefs: {\"speed\":\"fast\",\"color\":\"blue\"}," +
             " collapsed: " + VALID_COLLAPSED + ", " +
-            " widgetId: " + WIDGET_ID + "," +
+            " widgetId: '" + WIDGET_ID + "'," +
             " locked: " + VALID_LOCKED + "," +
             " hideChrome: " + VALID_HIDE_CHROME + "," +
-            " subPage: {id: " + VALID_SUBPAGE_ID + ", name: '" + VALID_SUBPAGE_NAME + "', isDefault: " + VALID_IS_DEFAULT_SUBPAGE + "}" +
+            " subPage: {id: '" + VALID_SUBPAGE_ID + "', name: '" + VALID_SUBPAGE_NAME + "', isDefault: " + VALID_IS_DEFAULT_SUBPAGE + "}" +
             "});</script>";
 
         expect(securityTokenService.getEncryptedSecurityToken(rw, w)).andReturn(VALID_SECURITY_TOKEN);
@@ -135,16 +128,15 @@
 
         String key = OpenSocialWidgetRenderer.REGISTER_WIDGET_KEY+"-"+rw.getId();
         scriptManager.registerScriptBlock(key, markup, ScriptLocation.AFTER_RAVE, RenderScope.CURRENT_REQUEST, renderContext);
-        // TODO Renable this test once it's fixed.
-        //expectLastCall();
-        //replay(scriptManager);
+        expectLastCall();
+        replay(scriptManager);
 
         RegionWidgetWrapper wrapper = new RegionWidgetWrapper(w, rw);
 
         String result = renderer.render(wrapper, renderContext);
 
-        assertThat(result, is(equalTo("<!-- RegionWidget " + REGION_WIDGET_ID + " placeholder -->")));
-        //verify(scriptManager);
+        assertThat(result, is(equalTo("<!-- RegionWidget '" + rw.getId() + "' placeholder -->")));
+        verify(scriptManager);
     }
 
     @Test
@@ -156,13 +148,9 @@
         Page page = new PageImpl();
         page.setPageType(PageType.USER);
         
-        WidgetImpl w = new WidgetImpl(WIDGET_ID);
+        WidgetImpl w = new WidgetImpl();
         w.setType(Constants.WIDGET_TYPE);
 
-        expect(widgetService.getWidget(w.getId())).andReturn(w);
-        expect(widgetService.getWidget(w.getId())).andReturn(w);
-        replay(widgetService);
-
         Region region = new RegionImpl(REGION_ID);
         region.setPage(page);
         RegionWidget rw = new RegionWidgetImpl();
@@ -170,14 +158,14 @@
         rw.setRegion(region);
 
         final String markup =
-            "<script>rave.registerWidget(" + REGION_ID + ", {type: 'OpenSocial'," +
-            " regionWidgetId: null," +
+            "<script>rave.registerWidget('8675309', {type: 'OpenSocial'," +
+            " regionWidgetId: 'null'," +
             " widgetUrl: 'null', " +
             " securityToken: 'null', " +
             " metadata: null," +
             " userPrefs: {}," +
             " collapsed: false, " +
-            " widgetId: " + WIDGET_ID + "," +
+            " widgetId: 'null'," +
             " locked: false," +
             " hideChrome: false," +
             " subPage: {id: null, name: '', isDefault: false}" +
@@ -199,9 +187,6 @@
         w.setType("NONE");
         w.setUrl("http://www.example.com/gadget.xml");
 
-        expect(widgetService.getWidget(w.getId())).andReturn(w);
-        replay(widgetService);
-
         RegionWidget rw = new RegionWidgetImpl("1");
         rw.setWidgetId(w.getId());
 
diff --git a/rave-providers/rave-opensocial-provider/rave-opensocial-core/src/test/resources/rave.shindig.properties b/rave-providers/rave-opensocial-provider/rave-opensocial-core/src/test/resources/rave.shindig.properties
index b318e1d..f2e9f5c 100644
--- a/rave-providers/rave-opensocial-provider/rave-opensocial-core/src/test/resources/rave.shindig.properties
+++ b/rave-providers/rave-opensocial-provider/rave-opensocial-core/src/test/resources/rave.shindig.properties
@@ -27,21 +27,21 @@
 shindig.spring.base-package=org.apache.rave
 
 # Default Rave Shindig database settings with in memory H2 database
-rave-shindig.dataSource.url=jdbc:h2:mem:portal;DB_CLOSE_DELAY=-1
-rave-shindig.dataSource.driver=org.h2.Driver
-rave-shindig.dataSource.username=sa
-rave-shindig.dataSource.password=local
+jpa.dataSource.url=jdbc:h2:mem:portal;DB_CLOSE_DELAY=-1
+jpa.dataSource.driver=org.h2.Driver
+jpa.dataSource.username=sa
+jpa.dataSource.password=local
 
-rave-shindig.jpaDialect=org.apache.rave.persistence.jpa.impl.H2OpenJpaDialect
-rave-shindig.jpaVendorAdapter.databasePlatform=org.apache.openjpa.jdbc.sql.H2Dictionary
-rave-shindig.jpaVendorAdapter.database=H2
+jpa.jpaDialect=org.apache.rave.persistence.jpa.impl.H2OpenJpaDialect
+jpa.jpaVendorAdapter.databasePlatform=org.apache.openjpa.jdbc.sql.H2Dictionary
+jpa.jpaVendorAdapter.database=H2
 
 # General Rave Shindig database settings
-rave-shindig.jpaVendorAdapter.showSql=true
-rave-shindig.openjpa.Log=DefaultLevel=WARN, Runtime=INFO, Tool=INFO, SQL=WARN
-rave-shindig.openjpa.RuntimeUnenhancedClasses=supported
-rave-shindig.openjpa.jdbc.SynchronizeMappings=buildSchema(ForeignKeys=true)
-rave-shindig.openjpa.jdbc.MappingDefaults=ForeignKeyDeleteAction=restrict, JoinForeignKeyDeleteAction=restrict
+jpa.jpaVendorAdapter.showSql=true
+jpa.openjpa.Log=DefaultLevel=WARN, Runtime=INFO, Tool=INFO, SQL=WARN
+jpa.openjpa.RuntimeUnenhancedClasses=supported
+jpa.openjpa.jdbc.SynchronizeMappings=buildSchema(ForeignKeys=true)
+jpa.openjpa.jdbc.MappingDefaults=ForeignKeyDeleteAction=restrict, JoinForeignKeyDeleteAction=restrict
 
 #########################################################
 ## These are the properties that came from Shindig     ##
diff --git a/rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig/pom.xml b/rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig/pom.xml
index db62c10..3dfdd73 100644
--- a/rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig/pom.xml
+++ b/rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig/pom.xml
@@ -59,10 +59,6 @@
             </exclusions>
         </dependency>
         <dependency>
-            <groupId>org.apache.rave</groupId>
-            <artifactId>rave-jpa</artifactId>
-        </dependency>
-        <dependency>
             <groupId>org.apache.shindig</groupId>
             <artifactId>shindig-server</artifactId>
             <type>war</type>
@@ -134,4 +130,29 @@
 
     </build>
 
+    <profiles>
+        <profile>
+            <id>jpa</id>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>org.apache.rave</groupId>
+                    <artifactId>rave-jpa</artifactId>
+                </dependency>
+            </dependencies>
+        </profile>
+        <profile>
+            <id>mongodb</id>
+            <dependencies>
+                <dependency>
+                    <groupId>org.apache.rave</groupId>
+                    <artifactId>rave-mongodb</artifactId>
+                </dependency>
+            </dependencies>
+        </profile>
+    </profiles>
+
+
 </project>
diff --git a/rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig/src/main/resources/rave-shindig-applicationContext.xml b/rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig/src/main/resources/rave-shindig-applicationContext.xml
index 107ac36..09af195 100644
--- a/rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig/src/main/resources/rave-shindig-applicationContext.xml
+++ b/rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig/src/main/resources/rave-shindig-applicationContext.xml
@@ -50,39 +50,8 @@
     <context:component-scan base-package="org.apache.rave.opensocial" annotation-config="true"/>
     <context:component-scan base-package="org.apache.rave.service" annotation-config="true"/>
 
-    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
-        <property name="entityManagerFactory" ref="entityManagerFactory"/>
-    </bean>
+    <import resource="classpath*:org/apache/rave/persistence-applicationContext.xml" />
 
-    <tx:annotation-driven transaction-manager="transactionManager"/>
-
-    <bean id="entityManagerFactory"
-          class="org.apache.rave.persistence.jpa.PopulatedLocalContainerEntityManagerFactory">
-        <property name="persistenceUnitName" value="ravePersistenceUnit"/>
-        <property name="dataSource" ref="dataSource"/>
-        <property name="populator" ref="dataSourcePopulator"/>
-        <property name="jpaVendorAdapter">
-            <bean class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter"
-                  p:databasePlatform="${rave-shindig.jpaVendorAdapter.databasePlatform}"
-                  p:database="${rave-shindig.jpaVendorAdapter.database}"
-                  p:showSql="${rave-shindig.jpaVendorAdapter.showSql}"/>
-        </property>
-        <property name="jpaPropertyMap">
-            <map>
-                <entry key="openjpa.Log" value="${rave-shindig.openjpa.Log}"/>
-                <entry key="openjpa.RuntimeUnenhancedClasses" value="${rave-shindig.openjpa.RuntimeUnenhancedClasses}"/>
-                <entry key="openjpa.jdbc.SynchronizeMappings" value="${rave-shindig.openjpa.jdbc.SynchronizeMappings}"/>
-                <entry key="openjpa.jdbc.MappingDefaults" value="${rave-shindig.openjpa.jdbc.MappingDefaults}"/>
-            </map>
-        </property>
-    </bean>
-
-    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
-        <property name="url" value="${rave-shindig.dataSource.url}"/>
-        <property name="driverClassName" value="${rave-shindig.dataSource.driver}"/>
-        <property name="username" value="${rave-shindig.dataSource.username}"/>
-        <property name="password" value="${rave-shindig.dataSource.password}"/>
-    </bean>
 
     <bean id="oAuthStore" class="org.apache.rave.gadgets.oauth.inject.DefaultOAuthStore">
         <constructor-arg name="defaultCallbackUrl" value="${shindig.signing.global-callback-url}"/>
diff --git a/rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig/src/main/resources/rave.shindig.properties b/rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig/src/main/resources/rave.shindig.properties
index 70d4179..0cf9bdb 100644
--- a/rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig/src/main/resources/rave.shindig.properties
+++ b/rave-providers/rave-opensocial-provider/rave-opensocial-server/rave-shindig/src/main/resources/rave.shindig.properties
@@ -35,21 +35,31 @@
 
 # Default Rave Shindig database settings with in memory H2 database
 # rave.database.location is replaced during the build
-rave-shindig.dataSource.url=jdbc:h2:${rave.database.location};AUTO_SERVER=TRUE
-rave-shindig.dataSource.driver=org.h2.Driver
-rave-shindig.dataSource.username=sa
-rave-shindig.dataSource.password=local
+jpa.dataSource.url=jdbc:h2:${rave.database.location};AUTO_SERVER=TRUE
+jpa.dataSource.driver=org.h2.Driver
+jpa.dataSource.username=sa
+jpa.dataSource.password=local
 
-rave-shindig.jpaDialect=org.apache.rave.persistence.jpa.impl.H2OpenJpaDialect
-rave-shindig.jpaVendorAdapter.databasePlatform=org.apache.openjpa.jdbc.sql.H2Dictionary
-rave-shindig.jpaVendorAdapter.database=H2
+jpa.jpaDialect=org.apache.rave.persistence.jpa.impl.H2OpenJpaDialect
+jpa.jpaVendorAdapter.databasePlatform=org.apache.openjpa.jdbc.sql.H2Dictionary
+jpa.jpaVendorAdapter.database=H2
 
 # General Rave Shindig database settings
-rave-shindig.jpaVendorAdapter.showSql=true
-rave-shindig.openjpa.Log=DefaultLevel=WARN, Runtime=WARN, Tool=WARN, SQL=WARN
-rave-shindig.openjpa.RuntimeUnenhancedClasses=warn
-rave-shindig.openjpa.jdbc.SynchronizeMappings=buildSchema(ForeignKeys=true)
-rave-shindig.openjpa.jdbc.MappingDefaults=ForeignKeyDeleteAction=restrict, JoinForeignKeyDeleteAction=restrict
+jpa.jpaVendorAdapter.showSql=true
+jpa.openjpa.Log=DefaultLevel=WARN, Runtime=WARN, Tool=WARN, SQL=WARN
+jpa.openjpa.RuntimeUnenhancedClasses=warn
+jpa.openjpa.jdbc.SynchronizeMappings=buildSchema(ForeignKeys=true)
+jpa.openjpa.jdbc.MappingDefaults=ForeignKeyDeleteAction=restrict, JoinForeignKeyDeleteAction=restrict
+
+###################################################################
+# Properties related to the Rave MongoDB implementation               #
+###################################################################
+mongo.host=localhost
+mongo.port=27017
+mongo.database=rave
+mongo.username=
+mongo.password=
+
 
 #################################################################################
 ## These properties are a copy/paste from the default shindig.properties file. ##