Commits

Anonymous committed ba52676

Added Document entity

Comments (0)

Files changed (16)

src/main/java/es/jogaco/model/Document.java

+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package es.jogaco.model;
+
+import java.io.Serializable;
+import java.util.Date;
+import javax.persistence.*;
+import org.hibernate.search.annotations.DocumentId;
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.Indexed;
+
+/**
+ *
+ * @author jgarcia
+ */
+@Entity
+@Table(name="document")
+@Indexed
+public class Document implements Serializable {
+
+    private static final long serialVersionUID = -9102286295950214586L;
+
+    private Long id;
+    private String name;
+    private Integer copies;
+    private Double price;
+    private Date releaseDate;
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.AUTO)
+    @DocumentId
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    @Column(name="name", nullable=false, unique=true)
+    @Field
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Column
+    public Integer getCopies() {
+        return copies;
+    }
+
+    public void setCopies(Integer copies) {
+        this.copies = copies;
+    }
+
+    @Column
+    public Double getPrice() {
+        return price;
+    }
+
+    public void setPrice(Double price) {
+        this.price = price;
+    }
+
+    @Column(name="date_release")
+    @Temporal(javax.persistence.TemporalType.DATE)
+    public Date getReleaseDate() {
+        return releaseDate;
+    }
+
+    public void setReleaseDate(Date releaseDate) {
+        this.releaseDate = releaseDate;
+    }
+
+    @Override
+    public String toString() {
+        return "Document{" + "id=" + id + ", name=" + name + ", releaseDate=" + releaseDate + '}';
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final Document other = (Document) obj;
+        if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
+            return false;
+        }
+        if (this.releaseDate != other.releaseDate && (this.releaseDate == null || !this.releaseDate.equals(other.releaseDate))) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 3;
+        hash = 71 * hash + (this.name != null ? this.name.hashCode() : 0);
+        hash = 71 * hash + (this.releaseDate != null ? this.releaseDate.hashCode() : 0);
+        return hash;
+    }
+
+}

src/main/java/es/jogaco/webapp/action/DocumentAction.java

+package es.jogaco.webapp.action;
+
+import com.opensymphony.xwork2.Preparable;
+import org.appfuse.service.GenericManager;
+import es.jogaco.model.Document;
+import es.jogaco.webapp.action.BaseAction;
+
+import java.util.List;
+
+public class DocumentAction extends BaseAction implements Preparable {
+    private GenericManager<Document, Long> documentManager;
+    private List documents;
+    private Document document;
+    private Long id;
+    private String query;
+
+    public void setDocumentManager(GenericManager<Document, Long> documentManager) {
+        this.documentManager = documentManager;
+    }
+
+    public List getDocuments() {
+        return documents;
+    }
+
+    /**
+     * Grab the entity from the database before populating with request parameters
+     */
+    public void prepare() {
+        if (getRequest().getMethod().equalsIgnoreCase("post")) {
+            // prevent failures on new
+            String documentId = getRequest().getParameter("document.id");
+            if (documentId != null && !documentId.equals("")) {
+                document = documentManager.get(new Long(documentId));
+            }
+        }
+    }
+
+    public void setQ(String q) {
+        this.query = q;
+    }
+
+    public String list() {
+        documents = documentManager.search(query, Document.class);
+        return SUCCESS;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Document getDocument() {
+        return document;
+    }
+
+    public void setDocument(Document document) {
+        this.document = document;
+    }
+
+    public String delete() {
+        documentManager.remove(document.getId());
+        saveMessage(getText("document.deleted"));
+
+        return SUCCESS;
+    }
+
+    public String edit() {
+        if (id != null) {
+            document = documentManager.get(id);
+        } else {
+            document = new Document();
+        }
+
+        return SUCCESS;
+    }
+
+    public String save() throws Exception {
+        if (cancel != null) {
+            return "cancel";
+        }
+
+        if (delete != null) {
+            return delete();
+        }
+
+        boolean isNew = (document.getId() == null);
+
+        documentManager.save(document);
+
+        String key = (isNew) ? "document.added" : "document.updated";
+        saveMessage(getText(key));
+
+        if (!isNew) {
+            return INPUT;
+        } else {
+            return SUCCESS;
+        }
+    }
+}

src/main/resources/ApplicationResources.properties

 company.url=http://raibledesigns.com
 copyright.year=${copyright.year}
 
-user.status=Logged in as: 
+user.status=Logged in as:
 user.logout=Logout
 
 # -- validator errors --
 # -- success messages --
 user.added=User information for {0} has been added successfully.
 user.deleted=User Profile for {0} has been deleted successfully.
-user.registered=You have successfully registered for access to this application. 
+user.registered=You have successfully registered for access to this application.
 user.saved=Your profile has been updated successfully.
 user.updated.byAdmin=User information for {0} has been successfully updated.
 newuser.email.message={0} has created an AppFuse account for you.  Your username and password information is below.
 uploadForm.name=Friendly Name
 uploadForm.file=File to Upload
 
-# -- display page messages -- 
+# -- display page messages --
 display.title=File Uploaded Successfully!
 display.heading=File Information
 
 
 # JSF-only messages, remove if not using JSF
 javax.faces.component.UIInput.REQUIRED=This is a required field.
-activeUsers.summary={0} User(s) found, displaying {1} user(s), from {2} to {3}. Page {4} / {5}
+activeUsers.summary={0} User(s) found, displaying {1} user(s), from {2} to {3}. Page {4} / {5}
+# -- Document-START
+document.id=Id
+document.copies=Copies
+document.name=Name
+document.price=Price
+document.releaseDate=Release Date
+
+document.added=Document has been added successfully.
+document.updated=Document has been updated successfully.
+document.deleted=Document has been deleted successfully.
+
+# -- document list page --
+documentList.title=Document List
+documentList.heading=Documents
+documentList.document=document
+documentList.documents=documents
+documentList.message=This is the list of your Documents. You can add Documents. To view a document's details, edit or delete it, click on one of the documents from the list.
+
+
+# -- document detail page --
+documentDetail.title=Document Detail
+documentDetail.heading=Document Information
+documentDetail.message=Please enter your Document information
+# -- Document-END

src/main/resources/es/jogaco/model/Document-validation.xml

+<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
+    "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
+<validators>
+    <field name="document.name">
+        <field-validator type="requiredstring">
+            <message key="errors.required"/>
+        </field-validator>
+    </field>
+</validators> 

src/main/resources/es/jogaco/webapp/action/DocumentAction-validation.xml

+<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
+    "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
+<validators>
+    <field name="document">
+        <field-validator type="visitor">
+            <param name="appendPrefix">false</param>
+            <message/>
+        </field-validator>
+    </field>
+</validators> 

src/main/resources/hibernate.cfg.xml

     <session-factory>
         <mapping class="org.appfuse.model.User"/>
         <mapping class="org.appfuse.model.Role"/>
+        <mapping class="es.jogaco.model.Document"/>
     </session-factory>
 </hibernate-configuration>

src/main/resources/struts.xml

             <result name="success">/</result>
         </action>
 
+        <!--DocumentAction-START-->
+        <action name="documents" class="es.jogaco.webapp.action.DocumentAction" method="list">
+            <result>/WEB-INF/pages/documentList.jsp</result>
+        </action>
+
+        <action name="editDocument" class="es.jogaco.webapp.action.DocumentAction" method="edit">
+            <result>/WEB-INF/pages/documentForm.jsp</result>
+            <result name="error">/WEB-INF/pages/documentList.jsp</result>
+        </action>
+
+        <action name="saveDocument" class="es.jogaco.webapp.action.DocumentAction" method="save">
+            <result name="input">/WEB-INF/pages/documentForm.jsp</result>
+            <result name="cancel" type="redirectAction">documents</result>
+            <result name="delete" type="redirectAction">documents</result>
+            <result name="success" type="redirectAction">documents</result>
+        </action>
+        <!--DocumentAction-END-->
+
         <!-- Add additional actions here -->
     </package>
 

src/main/webapp/WEB-INF/applicationContext.xml

 
     <!-- Add new DAOs here -->
 
+    <!--DocumentManager-START-->
+    <bean id="documentManager" class="org.appfuse.service.impl.GenericManagerImpl">
+        <constructor-arg>
+            <bean class="org.appfuse.dao.hibernate.GenericDaoHibernate">
+                <constructor-arg value="es.jogaco.model.Document"/>
+            </bean>
+        </constructor-arg>
+    </bean>
+    <!--DocumentManager-END-->
+
     <!-- Add new Managers here -->
 </beans>

src/main/webapp/WEB-INF/menu-config.xml

             <Item name="FileUpload" title="menu.selectFile" page="/uploadFile"/>
         </Menu>
         <Menu name="Logout" title="user.logout" page="/logout" roles="ROLE_ADMIN,ROLE_USER"/>
+        <!--Document-START-->
+        <Menu name="DocumentMenu" title="documentList.title" page="/documents"  roles="ROLE_ADMIN,ROLE_USER"/>
+        <!--Document-END-->
     </Menus>
 </MenuConfig>

src/main/webapp/WEB-INF/pages/documentForm.jsp

+<%@ include file="/common/taglibs.jsp"%>
+
+<head>
+    <title><fmt:message key="documentDetail.title"/></title>
+    <meta name="heading" content="<fmt:message key='documentDetail.heading'/>"/>
+</head>
+
+<c:set var="delObject" scope="request"><fmt:message key="documentList.document"/></c:set>
+<script type="text/javascript">var msgDelConfirm =
+   "<fmt:message key="delete.confirm"><fmt:param value="${delObject}"/></fmt:message>";
+</script>
+
+<div class="span3">
+    <h2><fmt:message key="documentDetail.heading"/></h2>
+    <fmt:message key="documentDetail.message"/>
+</div>
+
+<div class="span7">
+    <s:form id="documentForm" action="saveDocument" method="post" validate="true" cssClass="well form-horizontal">
+        <li style="display: none">
+            <s:hidden key="document.id"/>
+        </li>
+        <s:textfield key="document.copies" required="false" maxlength="255" cssClass="text medium"/>
+        <s:textfield key="document.name" required="true" maxlength="255" cssClass="text medium"/>
+        <s:textfield key="document.price" required="false" maxlength="255" cssClass="text medium"/>
+        <s:textfield key="document.releaseDate" required="false" maxlength="255" cssClass="text" size="11" title="date" datepicker="true"/>
+
+        <div id="actions" class="form-actions">
+            <s:submit type="button" cssClass="btn btn-primary" method="save" key="button.save" theme="simple">
+                <i class="icon-ok"></i>
+                <fmt:message key="button.save"/>
+            </s:submit>
+            <c:if test="${not empty document.id}">
+                <s:submit type="button" cssClass="btn btn-danger" method="delete" key="button.delete"
+                    onclick="return confirmMessage(msgDelConfirm)" theme="simple">
+                <i class="icon-trash"></i>
+                <fmt:message key="button.delete"/>
+                </s:submit>
+            </c:if>
+            <s:submit type="button" cssClass="btn" method="cancel" key="button.cancel" theme="simple">
+                <i class="icon-remove"></i>
+                <fmt:message key="button.cancel"/>
+            </s:submit>
+        </div>
+    </s:form>
+</div>
+
+<link rel="stylesheet" type="text/css" media="all" href="<c:url value='/scripts/datepicker/css/datepicker.css'/>" />
+<script type="text/javascript" src="<c:url value='/scripts/datepicker/js/bootstrap-datepicker.js'/>"></script>
+<c:if test="${pageContext.request.locale.language != 'en'}">
+<script type="text/javascript" src="<c:url value='/scripts/datepicker/js/locales/bootstrap-datepicker.${pageContext.request.locale.language}.js'/>"></script>
+</c:if>
+<script type="text/javascript">
+    $(document).ready(function() {
+        $("input[type='text']:visible:enabled:first", document.forms['documentForm']).focus();
+        $('.input-append.date').datepicker({format: "<fmt:message key='calendar.format'/>", weekStart: "<fmt:message key='calendar.weekstart'/>", language: '${pageContext.request.locale.language}'});
+    });
+</script>

src/main/webapp/WEB-INF/pages/documentList.jsp

+<%@ include file="/common/taglibs.jsp"%>
+
+<head>
+    <title><fmt:message key="documentList.title"/></title>
+    <meta name="heading" content="<fmt:message key='documentList.heading'/>"/>
+    <meta name="menu" content="DocumentMenu"/>
+</head>
+
+<div class="span10">
+    <h2><fmt:message key="documentList.heading"/></h2>
+    <div id="search">
+        <form method="get" action="${ctx}/documents" id="searchForm" class="form-search">
+            <input type="text" size="20" name="q" id="query" value="${param.q}"
+                   placeholder="<fmt:message key="search.enterTerms"/>" class="input-medium search-query"/>
+            <button id="button.search" class="btn" type="submit">
+                <i class="icon-search"></i>
+                <fmt:message key="button.search"/>
+            </button>
+        </form>
+    </div>
+    <fmt:message key="documentList.message"/>
+
+    <div id="actions" class="form-actions">
+        <a class="btn btn-primary" href="<c:url value='/editDocument'/>" >
+            <i class="icon-plus"></i>
+            <fmt:message key="button.add"/>
+        </a>
+        <a class="btn" href="<c:url value="/mainMenu"/>" >
+            <fmt:message key="button.done"/>
+        </a>
+    </div>
+
+    <display:table name="documents" class="table" requestURI="" id="documentList" export="true" pagesize="25">
+        <display:column property="id" sortable="true" href="editDocument" media="html"
+            paramId="id" paramProperty="id" titleKey="document.id"/>
+        <display:column property="id" media="csv excel xml pdf" titleKey="document.id"/>
+        <display:column property="copies" sortable="true" titleKey="document.copies"/>
+        <display:column property="name" sortable="true" titleKey="document.name"/>
+        <display:column property="price" sortable="true" titleKey="document.price"/>
+        <display:column sortProperty="releaseDate" sortable="true" titleKey="document.releaseDate">
+             <fmt:formatDate value="${documentList.releaseDate}" pattern="${datePattern}"/>
+        </display:column>
+
+        <display:setProperty name="paging.banner.item_name"><fmt:message key="documentList.document"/></display:setProperty>
+        <display:setProperty name="paging.banner.items_name"><fmt:message key="documentList.documents"/></display:setProperty>
+
+        <display:setProperty name="export.excel.filename"><fmt:message key="documentList.title"/>.xls</display:setProperty>
+        <display:setProperty name="export.csv.filename"><fmt:message key="documentList.title"/>.csv</display:setProperty>
+        <display:setProperty name="export.pdf.filename"><fmt:message key="documentList.title"/>.pdf</display:setProperty>
+    </display:table>
+
+    <div id="actions" class="form-actions">
+        <a class="btn btn-primary" href="<c:url value='/editDocument'/>" >
+            <i class="icon-plus"></i>
+            <fmt:message key="button.add"/>
+        </a>
+        <a class="btn" href="<c:url value="/mainMenu"/>" >
+            <fmt:message key="button.done"/>
+        </a>
+    </div>
+</div>

src/main/webapp/common/menu.jsp

 <%@ include file="/common/taglibs.jsp"%>
 
-<menu:useMenuDisplayer name="Velocity" config="topbarMenu.vm" permissions="rolesAdapter">
+<menu:useMenuDisplayer name="Velocity" config="navbarMenu.vm" permissions="rolesAdapter">
 <ul class="nav">
-    <c:if test="${empty pageContext.request.remoteUser}"><li class="active"><a href="<c:url value="/login"/>" class="current"><fmt:message key="login.title"/></a></li></c:if>
+    <c:if test="${empty pageContext.request.remoteUser}">
+        <li class="active"><a href="<c:url value="/login"/>" class="current"><fmt:message key="login.title"/></a>
+        </li>
+    </c:if>
     <menu:displayMenu name="MainMenu"/>
     <menu:displayMenu name="UserMenu"/>
     <menu:displayMenu name="AdminMenu"/>
+    <!--Document-START-->
+    <menu:displayMenu name="DocumentMenu"/>
+    <!--Document-END-->
     <menu:displayMenu name="Logout"/>
 </ul>
 </menu:useMenuDisplayer>

src/main/webapp/decorators/default.jsp

         <div class="navbar-inner">
             <div class="container-fluid">
                 <a class="brand" href="<c:url value='/'/>"><fmt:message key="webapp.name"/></a>
-                <menu:useMenuDisplayer name="Velocity" config="navbarMenu.vm" permissions="rolesAdapter">
-                <ul class="nav">
-                    <c:if test="${empty pageContext.request.remoteUser}">
-                        <li class="active">
-                            <a href="<c:url value="/login"/>"><fmt:message key="login.title"/></a>
-                        </li>
-                    </c:if>
-                    <menu:displayMenu name="MainMenu"/>
-                    <menu:displayMenu name="UserMenu"/>
-                    <menu:displayMenu name="AdminMenu"/>
-                    <menu:displayMenu name="Logout"/>
-                </ul>
-                </menu:useMenuDisplayer>
+                <%@ include file="/common/menu.jsp"%>
 
                 <c:if test="${pageContext.request.locale.language ne 'en'}">
                     <div id="switchLocale"><a href="<c:url value='/?locale=en'/>">

src/test/java/es/jogaco/webapp/action/DocumentActionTest.java

+package es.jogaco.webapp.action;
+
+import com.opensymphony.xwork2.ActionSupport;
+import org.apache.struts2.ServletActionContext;
+import org.appfuse.service.GenericManager;
+import es.jogaco.model.Document;
+import es.jogaco.webapp.action.BaseActionTestCase;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.mock.web.MockHttpServletRequest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class DocumentActionTest extends BaseActionTestCase {
+    private DocumentAction action;
+
+    @Before
+    public void onSetUp() {
+        super.onSetUp();
+
+        action = new DocumentAction();
+        GenericManager documentManager = (GenericManager) applicationContext.getBean("documentManager");
+        action.setDocumentManager(documentManager);
+
+        // add a test document to the database
+        Document document = new Document();
+
+        // enter all required fields
+        document.setName("" + Math.random());
+
+        documentManager.save(document);
+    }
+
+    @Test
+    public void testGetAllDocuments() throws Exception {
+        assertEquals(action.list(), ActionSupport.SUCCESS);
+        assertTrue(action.getDocuments().size() >= 1);
+    }
+
+    @Test
+    public void testSearch() throws Exception {
+        // regenerate indexes
+        GenericManager<Document, Long> documentManager = (GenericManager<Document, Long>) applicationContext.getBean("documentManager");
+        documentManager.reindex();
+
+        action.setQ("*");
+        assertEquals(action.list(), ActionSupport.SUCCESS);
+        assertEquals(4, action.getDocuments().size());
+    }
+
+    @Test
+    public void testEdit() throws Exception {
+        log.debug("testing edit...");
+        action.setId(-1L);
+        assertNull(action.getDocument());
+        assertEquals("success", action.edit());
+        assertNotNull(action.getDocument());
+        assertFalse(action.hasActionErrors());
+    }
+
+    @Test
+    public void testSave() throws Exception {
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        ServletActionContext.setRequest(request);
+        action.setId(-1L);
+        assertEquals("success", action.edit());
+        assertNotNull(action.getDocument());
+
+        Document document = action.getDocument();
+        // update required fields
+        document.setName("IcUaPsKcPcHyUqBvKgDaZeQuNtXmCoQvTkPbQsVjWuFnOrCvPyZxMfEpXsClFmTwIvBoTmHsEeXcPuBiAvTiAoSgHqMgVwPuHpUzSaZmAoSpJkJqChTfKkUsFsQsPqXdAlBfDkZoIzEdOhFrNcJeKlIoMmVeJnUjNvHnXlIeYdSrQxVdCxGnKxTyUeHpQlVjJuSxAwDyOrHsYcSgQgMtOrHsRvMbUfTeRaLmSiHcXxNjStCnDkMcWrUwWiXiHoV");
+
+        action.setDocument(document);
+
+        assertEquals("input", action.save());
+        assertFalse(action.hasActionErrors());
+        assertFalse(action.hasFieldErrors());
+        assertNotNull(request.getSession().getAttribute("messages"));
+    }
+
+    @Test
+    public void testRemove() throws Exception {
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        ServletActionContext.setRequest(request);
+        action.setDelete("");
+        Document document = new Document();
+        document.setId(-2L);
+        action.setDocument(document);
+        assertEquals("success", action.delete());
+        assertNotNull(request.getSession().getAttribute("messages"));
+    }
+}

src/test/resources/sample-data.xml

             <value description="role_id">-1</value>
         </row>
     </table>
-</dataset>
+    <!--Document-START-->
+    <table name="document">
+        <column>id</column>
+        <column>copies</column>
+        <column>name</column>
+        <column>price</column>
+        <column>date_release</column>
+    <row>
+        <value description="id">-1</value>
+        <value description="copies">48</value>
+        <value description="name">LnPxWqGlLsShUwGlJnLgAbGtUyOiPoHbMkLeUaBhUwSsP</value>
+        <value description="price">7.11</value>
+        <value description="date_release">2012-10-18</value>
+    </row>
+    <row>
+        <value description="id">-2</value>
+        <value description="copies">15</value>
+        <value description="name">XrXvCjZtYdRcKcXmLoHxTxCiGnGfGfRxPxOfLsMv</value>
+        <value description="price">6.0</value>
+        <value description="date_release">2012-10-18</value>
+    </row>
+    <row>
+        <value description="id">-3</value>
+        <value description="copies">37</value>
+        <value description="name">GbZuLuTjCpLaGtJhLrGrCpAzFzEuHfMoLoGqDnGsWd</value>
+        <value description="price">1.32</value>
+        <value description="date_release">2012-10-18</value>
+    </row>
+    </table>
+    <!--Document-END-->
+</dataset>

src/test/resources/web-tests.xml

 
     <!-- runs all targets -->
     <target name="run-all-tests" 
-        depends="Login,Logout,PasswordHint,Signup,UserTests,StaticPages,WebServices,DWR,FileUpload"
+        depends="Login,Logout,PasswordHint,Signup,UserTests,StaticPages,WebServices,DWR,FileUpload,DocumentTests"
         description="Call and executes all test cases (targets)"/>
     
     <!-- runs user-related tests -->
             </steps>
         </webtest>
     </target>
+    <!--Document-START-->
+    <!-- runs document-related tests -->
+    <target name="DocumentTests" depends="SearchDocuments,EditDocument,SaveDocument,AddDocument,DeleteDocument"
+            description="Call and executes all document test cases (targets)">
+        <echo>Successfully ran all Document UI tests!</echo>
+    </target>
+
+    <!-- Verify the documents list screen displays without errors -->
+    <target name="SearchDocuments" description="Tests search for and displaying all documents">
+        <webtest name="searchDocuments">
+            &config;
+            <steps>
+                &login;
+                <invoke description="click View Document link" url="/documents"/>
+                <verifytitle description="we should see the documentList title"
+                             text=".*${documentList.title}.*" regex="true"/>
+                <setinputfield description="set search term" name="q" value="*"/>
+                <clickbutton label="${button.search}" description="Click Search"/>
+                <verifytitle description="we should see the documentList title"
+                             text=".*${documentList.title}.*" regex="true"/>
+            </steps>
+        </webtest>
+    </target>
+
+    <!-- Verify the edit document screen displays without errors -->
+    <target name="EditDocument" description="Tests editing an existing Document's information">
+        <webtest name="editDocument">
+            &config;
+            <steps>
+                &login;
+                <invoke description="click Edit Document link" url="/editDocument?id=-1"/>
+                <verifytitle description="we should see the documentDetail title"
+                             text=".*${documentDetail.title}.*" regex="true"/>
+            </steps>
+        </webtest>
+    </target>
+
+    <!-- Edit a document and then save -->
+    <target name="SaveDocument" description="Tests editing and saving a document">
+        <webtest name="saveDocument">
+            &config;
+            <steps>
+                &login;
+                <invoke description="click Edit Document link" url="/editDocument?id=-1"/>
+                <verifytitle description="we should see the documentDetail title"
+                             text=".*${documentDetail.title}.*" regex="true"/>
+
+                <!-- update some of the required fields -->
+                <setInputField description="set name" name="document.name" value="VkYpJxExBdJtUpWvVfCkLsNhFtYtAhFzSaIuMqApFiAxQfClYxVtLpLlEfXmNkOaZhWuAcXoXpMxVcCnXlUdXbIqDnKrRsCuGhKqWoMcUyRaVyNaWoDmLaEtQpReFbNdPvXqHvOjGwMwRyZjKaEeFdVzFqPoBrZuWyCzXxXkKyXdUnLhQcZvFoQaDvBvZuLjZrGlEqChVrHfQbTgZrJcQzWhSfHbQwJaRhZgRaAuCpWiWiPzXkXqJtXrQfOyUvT"/>
+
+                <clickbutton label="${button.save}" description="Click Save"/>
+                <verifytitle description="Page re-appears if save successful"
+                             text=".*${documentDetail.title}.*" regex="true"/>
+                <verifytext description="verify success message" text="${document.updated}"/>
+            </steps>
+        </webtest>
+    </target>
+
+    <!-- Add a new Document -->
+    <target name="AddDocument" description="Adds a new Document">
+        <webtest name="addDocument">
+            &config;
+            <steps>
+                &login;
+                <invoke description="click Add Button" url="/editDocument"/>
+                <verifytitle description="we should see the documentDetail title"
+                             text=".*${documentDetail.title}.*" regex="true"/>
+
+                <!-- enter required fields -->
+                <setInputField description="set name" name="document.name" value="ZqMqKuMhVfTtUoTiEzFjQzMxIqWdTnMjNnYtBbLyWiFpMwBqUkVeDvSwXkUiJeLbFpIsGaGnUyBiPuHuBjYmFjUmSsBeYeFoGjCvZaEjPzMjUfWsGdGcSxGuPwPuDgHlClBpDsWcBnFpKgCxKwXyWjGsOhNmNuXgQaSbJiXjTlZiVvSvKgKqTmHxBpAyErOcCcIoIsQxIlQqPmXpHyFjAcDyHoHoRbKdRkUwCwIuXnDxDjMoTiGzHwCuUpXdDtH"/>
+
+                <clickbutton label="${button.save}" description="Click button 'Save'"/>
+                <verifytitle description="Document List appears if save successful"
+                             text=".*${documentList.title}.*" regex="true"/>
+                <verifytext description="verify success message" text="${document.added}"/>
+            </steps>
+        </webtest>
+    </target>
+
+    <!-- Delete existing document -->
+    <target name="DeleteDocument" description="Deletes existing Document">
+        <webtest name="deleteDocument">
+            &config;
+            <steps>
+                &login;
+                <invoke description="click Edit Document link" url="/editDocument?id=-1"/>
+                <prepareDialogResponse description="Confirm delete" dialogType="confirm" response="true"/>
+                <clickbutton label="${button.delete}" description="Click button 'Delete'"/>
+                <verifyNoDialogResponses/>
+                <verifytitle description="display Document List" text=".*${documentList.title}.*" regex="true"/>
+                <verifytext description="verify success message" text="${document.deleted}"/>
+            </steps>
+        </webtest>
+    </target>
+    <!--Document-END-->
 </project>