For developing with Parancore you'll need:
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.
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.
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.
In the following
$PRJ indicates the directory in wich you created the project.
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;
}
}
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> {
}
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";
}
}
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> </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>
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";
}
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).
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-adminAs you can see, it's very easy to define data sets, even with references to other data. The main rules are:
<entity_name>.yml&<entity_name>-<some-useful-identifier>*<entity_name>-<some-useful-identifier> for referencing that item;