Parancoe
The easy-to-use web framework

Chapter 1. Starting a new project with Parancoe

1.1. Software requisites

For developing with Parancore you'll need:

1.2. Starting up your own project

You can start the development of a new Web application using the Parancoe Web Application archetype:

mvn archetype:create -DarchetypeGroupId=org.parancoe \
    -DarchetypeArtifactId=parancoe-webarchetype \
    -DarchetypeVersion=2.0.3 \
    -DgroupId=com.mycompany \
    -DartifactId=testApp \
    -DpackageName=com.mycompany.testapp
            

Of course you can personalize the groupId, artifactId and package. After the execution you’ll have a complete web project with a common good layout, configured authentication and authorization, some Parancoe examples. Starting from this skeleton you can personalize it for developing your own application.

1.3. Using the project with an IDE

The Parancoe web application archetype produces a Maven 2 project. Of course you can use it with your preferred IDE.

  • NetBeans: install the Mevenide2 plug-in and use the project as a native NetBeans project. You'll find this plugin already available in the NetBeans plugin link starting from NetBeans 6.0.

  • Eclipse: run mvn eclipse:eclipse and open the project with Eclipse.

  • IntelliJ IDEA: run mvn idea:idea and open the project with IDEA.

1.4. Setting up your Maven environment

The easyest way to develop a project with Parancoe is to use Maven 2 as build tool.

Parancoe artifacts are distributed through the Maven Central Repository and its mirrors. You don’t have to configure anything for using this repository.

If you are behind a proxy, check the Maven guide to using proxies to configure maven 2 with your proxy.

1.5. Adding a CRUD to your application

In the following $PRJ indicates the directory in wich you created the project.

1.5.1. Add the entity

Add to the $PRJ/src/main/java/com/mycompany/testapp/po directory the Person.java file with the following content:

package com.mycompany.testapp.po;

import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.parancoe.persistence.po.hibernate.EntityBase;

@Entity
public class Person extends EntityBase {

    private String firstName;
    private String lastName;
    private Date birthDate;
    private String email;

    @Temporal(TemporalType.DATE)
    public Date getBirthDate() {
        return birthDate;
    }

    public void setBirthDate(Date birthDate) {
        this.birthDate = birthDate;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}
            

1.5.2. Add the DAO

Add to the $PRJ/src/main/java/com/mycompany/testapp/dao directory the PersonDao.java file with the following content:

package com.mycompany.testapp.dao;

import com.mycompany.testapp.po.Person;
import org.parancoe.persistence.dao.generic.Dao;
import org.parancoe.persistence.dao.generic.GenericDao;

@Dao(entity=Person.class)
public interface PersonDao extends GenericDao<Person, Long> {
}
            

1.5.3. Add the controller

Add to the $PRJ/src/main/java/com/mycompany/testapp/controllers directory the PersonController.java file with the following content:

package com.mycompany.testapp.controllers;

import com.mycompany.testapp.dao.PersonDao;
import com.mycompany.testapp.po.Person;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;

@Controller
@RequestMapping({"/person/*.form", "/person/*.html"})
@SessionAttributes(PersonController.PERSON_ATTR_NAME)
public class PersonController {

    public static final String PERSON_ATTR_NAME = "person";
    public static final String EDIT_VIEW = "person/edit";
    public static final String LIST_VIEW = "person/list";
    @Autowired
    private PersonDao personDao;

    @RequestMapping
    public String edit(@RequestParam("id") Long id, Model model) {
        Person person = personDao.get(id);
        if (person == null) {
            throw new RuntimeException("Person not found");
        }
        model.addAttribute(PERSON_ATTR_NAME, person);
        return EDIT_VIEW;
    }

    @RequestMapping
    public String save(@ModelAttribute(PERSON_ATTR_NAME) Person person,
            BindingResult result, SessionStatus status) {
        personDao.store(person);
        status.setComplete();
        return "redirect:list.html";
    }

    @RequestMapping
    public String list(Model model) {
        List<Person> people = personDao.findAll();
        model.addAttribute("people", people);
        return LIST_VIEW;
    }

    @RequestMapping
    public String create(Model model) {
        Person person = new Person();
        model.addAttribute(PERSON_ATTR_NAME, person);
        return EDIT_VIEW;
    }

    @RequestMapping
    public String delete(@RequestParam("id") Long id, Model model) {
        Person person = personDao.get(id);
        if (person == null) {
            throw new RuntimeException("Person not found");
        }
        personDao.delete(person);
        return "redirect:list.html";
    }
}
            

1.5.4. Add the views (JSP)

Create the $PRJ/src/main/webapp/WEB-INF/jsp/person directory.

Add to the $PRJ/src/main/webapp/WEB-INF/jsp/person directory the list.jsp file with the following content:

<%@ include file="../common.jspf" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <%@ include file="../head.jspf" %>
    </head>
    <body>
        <div id="nonFooter">
            <jsp:include page="../header.jsp"/>
            <div id="content">
                <div id="content_main">
                    <h1>People</h1>
                    <table>
                        <c:forEach var="person" items="${people}">
                            <tr>
                                <td>${person.firstName}</td>
                                <td>${person.lastName}</td>
                                <td>${person.birthDate}</td>
                                <td>${person.email}</td>
                                <td>
                                    <a href="edit.form?id=${person.id}">Edit</a>
                                    <a href="delete.html?id=${person.id}">Delete</a>
                                </td>
                            </tr>
                        </c:forEach>
                    </table>
                    <c:if test="${empty people}">
                        No people in the DB
                    </c:if>
                    <a href="create.html">New</a>
                </div>
                <jsp:include page="../menu.jsp"/>
            </div>
        </div>
        <jsp:include page="../footer.jsp"/>
    </body>
</html>
            

Add to the $PRJ/src/main/webapp/WEB-INF/jsp/person directory the edit.jsp file with the following content:

<%@ include file="../common.jspf" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <%@ include file="../head.jspf" %>
    </head>
    <body>
        <div id="nonFooter">
            <jsp:include page="../header.jsp"/>
            <div id="content">
                <div id="content_main">
                    <h1>Edit person</h1>
                    <form:form commandName="person" method="POST"
                            action="${cp}/person/save.form">
                        <table>
                        <tr>
                            <td>First name:</td>
                            <td><form:input path="firstName"/></td>
                        </tr>
                        <tr>
                            <td>Last name:</td>
                            <td><form:input path="lastName"/></td>
                        </tr>
                        <tr>
                            <td>Birth date:</td>
                            <td><form:input path="birthDate"/> (dd/MM/yyyy)</td>
                        </tr>
                        <tr>
                            <td>E-mail:</td>
                            <td><form:input path="email"/></td>
                        </tr>
                        <tr>
                            <td>&nbsp;</td>
                            <td><input type="submit" value="Submit"/><br/><br/></td>
                        </tr>
                        </table>
                        <form:errors path="*" cssClass="errorBox"/>
                    </form:form>
                </div>
                <jsp:include page="../menu.jsp"/>
            </div>
        </div>
        <jsp:include page="../footer.jsp"/>
    </body>
</html>
            

Add an item to the page menu in the $PRJ/src/main/webapp/WEB-INF/jsp/menu.jsp file:

<%@ include file="common.jspf" %>
<div id="content_menu">
    <p class="menuTitle"><spring:message code="label_menu"/></p>
    <p class="menuLevel0"><a href="${cp}/"><spring:message code="menu_home"/></a></p>
    <p class="menuLevel0"><a href="${cp}/person/list.html">People</a></p>
    <p class="menuLevel0">
        <a href="${cp}/admin/index.html"><spring:message code="menu_administration"/></a>
    </p>
    <authz:authorize ifAnyGranted="ROLE_ADMIN,ROLE_PARANCOE">
        <p class="menuLevel0"><a href="${cp}/logout.secure">Logout</a></p>
    </authz:authorize>
</div>
            

1.5.5. Add the validation

Add the validation rules to your form bean (in this example it's also the persistence entity) in the $PRJ/src/main/java/com/mycompany/testapp/po/Person.java. The rules are expressed through annotations.

package com.mycompany.testapp.po;

import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.parancoe.persistence.po.hibernate.EntityBase;
import org.springmodules.validation.bean.conf.loader.annotation.handler.Email;
import org.springmodules.validation.bean.conf.loader.annotation.handler.NotBlank;

@Entity
public class Person extends EntityBase {

    @NotBlank
    private String firstName;
    @NotBlank
    private String lastName;
    private Date birthDate;
    @Email
    private String email;

    @Temporal(TemporalType.DATE)
    public Date getBirthDate() {
        return birthDate;
    }

    public void setBirthDate(Date birthDate) {
        this.birthDate = birthDate;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}
            

Add the @Validation annotation to the save method of the PersonController class:

@RequestMapping
@Validation(view=EDIT_VIEW)
public String save(@ModelAttribute(PERSON_ATTR_NAME) Person person,
        BindingResult result, SessionStatus status) {
    personDao.store(person);
    status.setComplete();
    return "redirect:list.html";
}
            

1.6. Configure your database

The application generated by the Parancoe Web Application has its database configuration in the $PRJ/src/main/webapp/WEB-INF/database.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<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-2.5.xsd">

  <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="java:comp/env/jdbc/testAppDS"/>
  </bean>

  <bean id="sessionFactory" parent="abstractSessionFactory">
    <property name="hibernateProperties">
      <props merge="true">
        <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
        <prop key="hibernate.hbm2ddl.auto">update</prop>
        <prop key="hibernate.show_sql">true</prop>
      </props>
    </property>
    <property name="eventListeners">
      <map>
        <entry key="merge">
          <bean class=
   "org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener"/>
        </entry>
      </map>
    </property>
  </bean>
</beans>
        

As you see in the previous file, the database connection is configured through a datasource, so you just need to define a datasource with that name in your application server. If you are using Tomcat, you can define the datasource in the $PRJ/src/main/webapp/META-INF/context.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/testApp" reloadable="true">
  <Resource name="jdbc/testAppDS"
            type="javax.sql.DataSource"
            auth="Container"
            driverClassName="org.hsqldb.jdbcDriver"
            url="jdbc:hsqldb:mem:testApp"
            username="sa"
            password=""
            maxActive="5"
            />
</Context>
        

For ease of configuration, the default database is an HSQL in-memory database. Of course you need to change it to a database with real persistence.

When you change your database, you need to change your datasource and the Hibernate dialect (if you aren't using an HSQL database server).

1.7. Database data initialization

A common case of every application is the initialization of the database with the data needed for putting the application itself in a proper initial state after its first deploy.

For example the application generated by the Parancoe Web Archetype populate the database with the ROLE_PARANCOE and ROLE_ADMIN roles, and the parancoe and admin users. This is achieved adding the entities that must be initialized to the clazzToPopulate list of the PopulateInitialDataContextListener class:

package com.mycompany.testapp;

import com.mycompany.testapp.po.Person;
import org.parancoe.plugins.security.Authority;
import org.parancoe.plugins.security.User;

public class PopulateInitialDataContextListener
        extends org.parancoe.web.PopulateInitialDataContextListener {

    public PopulateInitialDataContextListener() {
        // Add here to the clazzToPopulate collection
        // the entity classes you need to populate
        clazzToPopulate.add(Authority.class);
        clazzToPopulate.add(User.class);
    }

}

The data to load are defined in the $PRJ/src/main/resources/initialData directory by a set of "fixtures" in YAML format:

Example 1.1. Authority.yml

- &Authority-parancoe
  role: ROLE_PARANCOE
- &Authority-admin
  role: ROLE_ADMIN

Example 1.2. User.yml

- &User-parancoe
  username: parancoe
  # password : parancoe
  password: d928b1a8468c96804da6fcc70bff826f
  enabled: true
  authorities:
    - *Authority-parancoe
- &User-admin
  username: admin
  # password : admin
  password: ceb4f32325eda6142bd65215f4c0f371
  enabled: true
  authorities:
    - *Authority-admin

As you can see, it's very easy to define data sets, even with references to other data. The main rules are:

  1. Put your data in a file named <entity_name>.yml
  2. Identify your data items with &<entity_name>-<some-useful-identifier>
  3. Use *<entity_name>-<some-useful-identifier> for referencing that item;