ItEr07S05CUCreacionRecursoTraballadorItEr06S07: Creates, edits and lists workers. Test for WorkerCRUDController. EasyMock is added as dependency.

This commit is contained in:
Óscar González Fernández 2009-05-06 19:36:37 +02:00 committed by Javier Moran Rua
parent 3763f322d0
commit d5bb95e490
19 changed files with 718 additions and 270 deletions

View file

@ -1,7 +1,6 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<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>
<parent>
<groupId>org.navalplanner</groupId>
@ -11,7 +10,7 @@
<artifactId>navalplanner-business</artifactId>
<packaging>jar</packaging>
<name>Naval Planner Business Module</name>
<dependencies>
<!-- JDBC driver -->
<dependency>
@ -37,6 +36,11 @@
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View file

@ -1,6 +1,7 @@
package org.navalplanner.business.common.daos;
package org.navalplanner.business.common.daos;
import java.io.Serializable;
import java.util.List;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
@ -20,11 +21,13 @@ public interface IGenericDao <E, PK extends Serializable>{
* It updates and inserts the object passed as a parameter.
*/
public void save(E entity);
public E find(PK id) throws InstanceNotFoundException;
public boolean exists(PK id);
public void remove(PK id) throws InstanceNotFoundException;
public <T extends E> List<T> list(Class<T> klass);
}

View file

@ -2,13 +2,13 @@ package org.navalplanner.business.common.daos.impl;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.navalplanner.business.common.daos.IGenericDao;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
@ -33,54 +33,54 @@ import org.springframework.orm.hibernate3.SessionFactoryUtils;
* @param <E> Entity class
* @param <PK> Primary key class
*/
public class GenericDaoHibernate<E, PK extends Serializable>
implements IGenericDao<E, PK> {
public class GenericDaoHibernate<E, PK extends Serializable> implements
IGenericDao<E, PK> {
private Class<E> entityClass;
@Autowired
private SessionFactory sessionFactory;
@SuppressWarnings("unchecked")
public GenericDaoHibernate() {
this.entityClass = (Class<E>) ((ParameterizedType) getClass().
getGenericSuperclass()).getActualTypeArguments()[0];
this.entityClass = (Class<E>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
protected DataAccessException convertHibernateAccessException(
HibernateException e) {
return SessionFactoryUtils.convertHibernateAccessException(e);
HibernateException e) {
return SessionFactoryUtils.convertHibernateAccessException(e);
}
public void save(E entity) {
try {
getSession().saveOrUpdate(entity);
} catch (HibernateException e) {
throw convertHibernateAccessException(e);
}
}
@SuppressWarnings("unchecked")
public E find(PK id) throws InstanceNotFoundException {
try {
E entity = (E) getSession().get(entityClass, id);
if (entity == null) {
throw new InstanceNotFoundException(id, entityClass.getName());
}
return entity;
} catch (HibernateException e) {
throw convertHibernateAccessException(e);
}
@ -88,14 +88,13 @@ public class GenericDaoHibernate<E, PK extends Serializable>
}
public boolean exists(final PK id) {
try {
return getSession().createCriteria(entityClass).
add(Restrictions.idEq(id)).
setProjection(Projections.id()).
uniqueResult() != null;
return getSession().createCriteria(entityClass).add(
Restrictions.idEq(id)).setProjection(Projections.id())
.uniqueResult() != null;
} catch (HibernateException e) {
throw convertHibernateAccessException(e);
}
@ -103,13 +102,19 @@ public class GenericDaoHibernate<E, PK extends Serializable>
}
public void remove(PK id) throws InstanceNotFoundException {
try {
getSession().delete(find(id));
} catch (HibernateException e) {
throw convertHibernateAccessException(e);
}
}
}
@SuppressWarnings("unchecked")
@Override
public <T extends E> List<T> list(Class<T> klass) {
return getSession().createCriteria(klass).list();
}
}

View file

@ -2,12 +2,12 @@ package org.navalplanner.business.common.daos.impl;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.navalplanner.business.common.daos.IGenericDao;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
@ -33,23 +33,23 @@ import org.springframework.orm.hibernate3.HibernateTemplate;
* @param <E> Entity class
* @param <PK> Primary key class
*/
public class GenericDaoHibernateTemplate<E, PK extends Serializable>
implements IGenericDao<E, PK> {
public class GenericDaoHibernateTemplate<E, PK extends Serializable> implements
IGenericDao<E, PK> {
private Class<E> entityClass;
private HibernateTemplate hibernateTemplate;
@SuppressWarnings("unchecked")
public GenericDaoHibernateTemplate() {
this.entityClass = (Class<E>) ((ParameterizedType) getClass().
getGenericSuperclass()).getActualTypeArguments()[0];
this.entityClass = (Class<E>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
protected HibernateTemplate getHibernateTemplate() {
return hibernateTemplate;
}
@Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
hibernateTemplate = new HibernateTemplate(sessionFactory);
@ -58,7 +58,7 @@ public class GenericDaoHibernateTemplate<E, PK extends Serializable>
public void save(E entity) {
hibernateTemplate.saveOrUpdate(entity);
}
@SuppressWarnings("unchecked")
public E find(PK id) throws InstanceNotFoundException {
@ -73,13 +73,12 @@ public class GenericDaoHibernateTemplate<E, PK extends Serializable>
}
public boolean exists(final PK id) {
return (Boolean) hibernateTemplate.execute(new HibernateCallback() {
public Object doInHibernate(Session session) {
return session.createCriteria(entityClass).
add(Restrictions.idEq(id)).
setProjection(Projections.id()).
uniqueResult() != null;
return session.createCriteria(entityClass).add(
Restrictions.idEq(id)).setProjection(Projections.id())
.uniqueResult() != null;
}
});
@ -89,4 +88,10 @@ public class GenericDaoHibernateTemplate<E, PK extends Serializable>
hibernateTemplate.delete(find(id));
}
}
@SuppressWarnings("unchecked")
@Override
public <T extends E> List<T> list(Class<T> klass) {
return hibernateTemplate.loadAll(klass);
}
}

View file

@ -1,7 +1,10 @@
package org.navalplanner.business.resources.services;
import java.util.List;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.business.resources.entities.Worker;
/**
* Interface for the resource management service.
@ -10,19 +13,19 @@ import org.navalplanner.business.resources.entities.Resource;
*
*/
public interface ResourceService {
/**
* It updates or inserts the resource passed as a parameter. If the
* resource is a composite resource, updating or inserting is cascaded to
* the resources contained in it.
* It updates or inserts the resource passed as a parameter. If the resource
* is a composite resource, updating or inserting is cascaded to the
* resources contained in it.
*/
public void saveResource(Resource resource);
public Resource findResource(Long resourceId)
throws InstanceNotFoundException;
public Resource findResource(Long resourceId)
throws InstanceNotFoundException;
/**
* It adds a resource to a resource group. It the resource already belongs
* It adds a resource to a resource group. It the resource already belongs
* to a resource group, the resource is moved to the new group.
*/
public void addResourceToResourceGroup(Long resourceId,
@ -32,10 +35,12 @@ public interface ResourceService {
throws InstanceNotFoundException;
/**
* It removes a resource. If the resource is a composite resource, the
* It removes a resource. If the resource is a composite resource, the
* resources contained in it are not removed.
*/
public void removeResource(Long resourceId)
throws InstanceNotFoundException;
public void removeResource(Long resourceId)
throws InstanceNotFoundException;
public List<Worker> getWorkers();
}

View file

@ -1,10 +1,13 @@
package org.navalplanner.business.resources.services.impl;
import java.util.List;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.resources.daos.IResourceDao;
import org.navalplanner.business.resources.daos.IResourceGroupDao;
import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.business.resources.entities.ResourceGroup;
import org.navalplanner.business.resources.entities.Worker;
import org.navalplanner.business.resources.services.ResourceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
@ -18,46 +21,50 @@ import org.springframework.transaction.annotation.Transactional;
*/
@Transactional
public class ResourceServiceImpl implements ResourceService {
@Autowired
private IResourceDao resourceDao;
@Autowired
private IResourceGroupDao resourceGroupDao;
private IResourceGroupDao resourceGroupDao;
public void saveResource(Resource resource) {
resourceDao.save(resource);
}
@Transactional(readOnly = true)
public Resource findResource(Long resourceId)
throws InstanceNotFoundException {
throws InstanceNotFoundException {
return resourceDao.find(resourceId);
}
public void addResourceToResourceGroup(Long resourceId,
Long resourceGroupId) throws InstanceNotFoundException {
public void addResourceToResourceGroup(Long resourceId, Long resourceGroupId)
throws InstanceNotFoundException {
ResourceGroup resourceGroup = resourceGroupDao.find(resourceGroupId);
resourceGroup.addResource(resourceId);
}
@Transactional(readOnly = true)
public int getResourceDailyCapacity(Long resourceId)
throws InstanceNotFoundException {
return resourceDao.find(resourceId).getDailyCapacity();
}
public void removeResource(Long resourceId)
throws InstanceNotFoundException {
@Transactional(readOnly = true)
public int getResourceDailyCapacity(Long resourceId)
throws InstanceNotFoundException {
return resourceDao.find(resourceId).getDailyCapacity();
}
public void removeResource(Long resourceId)
throws InstanceNotFoundException {
resourceDao.find(resourceId).remove();
}
@Override
public List<Worker> getWorkers() {
return resourceDao.list(Worker.class);
}
}

View file

@ -27,77 +27,76 @@ import org.springframework.transaction.annotation.Transactional;
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={BUSINESS_SPRING_CONFIG_FILE,
BUSINESS_SPRING_CONFIG_TEST_FILE})
@ContextConfiguration(locations = { BUSINESS_SPRING_CONFIG_FILE,
BUSINESS_SPRING_CONFIG_TEST_FILE })
@Transactional
public class ResourceServiceTest {
@Autowired
private ResourceService resourceService;
@Autowired
private IResourceDao resourceDao;
@Test
public void testAddResourceToResourceGroup()
throws InstanceNotFoundException {
public void testAddResourceToResourceGroup()
throws InstanceNotFoundException {
/* Two workers. One of them belongs to a resource group. */
Worker worker1 = new Worker("worker-1", "worker-1-surname",
"11111111A", 8);
Worker worker2 = new Worker("worker-2", "worker-2-surname",
"22222222B", 7);
Worker worker1 = new Worker("worker-1", "worker-1-surname",
"11111111A", 8);
Worker worker2 = new Worker("worker-2", "worker-2-surname",
"22222222B", 7);
ResourceGroup resourceGroup1 = new ResourceGroup();
resourceGroup1.addResource(worker1);
resourceService.saveResource(resourceGroup1); // worker1 is also saved.
resourceService.saveResource(worker2);
/* A resource group. */
ResourceGroup resourceGroup2 = new ResourceGroup();
resourceService.saveResource(resourceGroup2);
/* Add workers to resource group. */
resourceService.addResourceToResourceGroup(worker1.getId(),
resourceGroup2.getId());
resourceGroup2.getId());
resourceService.addResourceToResourceGroup(worker2.getId(),
resourceGroup2.getId());
resourceGroup2.getId());
/* Check resource group. */
ResourceGroup resourceGroup = (ResourceGroup)
resourceService.findResource(resourceGroup2.getId());
ResourceGroup resourceGroup = (ResourceGroup) resourceService
.findResource(resourceGroup2.getId());
assertEquals(2, resourceGroup.getResources().size());
assertTrue(resourceGroup.getResources().contains(worker1));
assertTrue(resourceGroup.getResources().contains(worker2));
/* Check worker1 is no longer in group 1. */
assertFalse(resourceGroup1.getResources().contains(worker1));
}
@Test
public void testGetResourceDailyCapacity()
throws InstanceNotFoundException {
public void testGetResourceDailyCapacity() throws InstanceNotFoundException {
/* Three workers. */
Worker worker1 = new Worker("worker-1", "worker-1-surname",
"11111111A", 8);
Worker worker2 = new Worker("worker-2", "worker-2-surname",
"22222222B", 7);
Worker worker3 = new Worker("worker-3", "worker-3-surname",
"33333333C", 6);
Worker worker1 = new Worker("worker-1", "worker-1-surname",
"11111111A", 8);
Worker worker2 = new Worker("worker-2", "worker-2-surname",
"22222222B", 7);
Worker worker3 = new Worker("worker-3", "worker-3-surname",
"33333333C", 6);
/* A group of two workers. */
ResourceGroup resourceGroup1 = new ResourceGroup();
Worker worker4 = new Worker("worker-4", "worker-4-surname",
"44444444D", 5);
Worker worker5 = new Worker("worker-5", "worker-5-surname",
"55555555E", 4);
Worker worker4 = new Worker("worker-4", "worker-4-surname",
"44444444D", 5);
Worker worker5 = new Worker("worker-5", "worker-5-surname",
"55555555E", 4);
resourceGroup1.addResource(worker4);
resourceGroup1.addResource(worker5);
/*
* A complex group containing the first three workers and a group with
/*
* A complex group containing the first three workers and a group with
* the last two workers.
*/
ResourceGroup resourceGroup2 = new ResourceGroup();
@ -105,76 +104,95 @@ public class ResourceServiceTest {
resourceGroup2.addResource(worker2);
resourceGroup2.addResource(worker3);
resourceGroup2.addResource(resourceGroup1);
/* Calculate total daily capacity. */
int totalDailyCapacity =
worker1.getDailyCapacity() + worker2.getDailyCapacity() +
worker3.getDailyCapacity() + worker4.getDailyCapacity() +
worker5.getDailyCapacity();
int totalDailyCapacity = worker1.getDailyCapacity()
+ worker2.getDailyCapacity() + worker3.getDailyCapacity()
+ worker4.getDailyCapacity() + worker5.getDailyCapacity();
/* Save the second group (and in consequence all resources). */
resourceService.saveResource(resourceGroup2);
/* Test ResourceService's getResourceDailyCapacity. */
int resourceGroupDailyCapacity =
resourceService.getResourceDailyCapacity(resourceGroup2.getId());
assertEquals(totalDailyCapacity, resourceGroupDailyCapacity);
int resourceGroupDailyCapacity = resourceService
.getResourceDailyCapacity(resourceGroup2.getId());
assertEquals(totalDailyCapacity, resourceGroupDailyCapacity);
}
@Test
public void testRemoveResource() throws InstanceNotFoundException {
/* A group of three workers. */
ResourceGroup resourceGroup = new ResourceGroup();
Worker worker1 = new Worker("worker-1", "worker-2-surname",
"11111111A", 8);
Worker worker2 = new Worker("worker-2", "worker-3-surname",
"22222222B", 6);
Worker worker3 = new Worker("worker-3", "worker-3-surname",
"33333333C", 4);
Worker worker1 = new Worker("worker-1", "worker-2-surname",
"11111111A", 8);
Worker worker2 = new Worker("worker-2", "worker-3-surname",
"22222222B", 6);
Worker worker3 = new Worker("worker-3", "worker-3-surname",
"33333333C", 4);
resourceGroup.addResource(worker1);
resourceGroup.addResource(worker2);
resourceGroup.addResource(worker3);
resourceService.saveResource(resourceGroup);
/* Remove worker 3. */
resourceService.removeResource(worker3.getId());
/* Check worker 3 does not exist. */
assertFalse(resourceDao.exists(worker3.getId()));
/*
* Check worker 3 is not in resource group and the other workers
* are still in the group.
/*
* Check worker 3 is not in resource group and the other workers are
* still in the group.
*/
assertFalse(resourceGroup.getResources().contains(worker3));
assertTrue(resourceGroup.getResources().contains(worker1));
assertTrue(resourceGroup.getResources().contains(worker2));
/* Remove the group. */
resourceService.removeResource(resourceGroup.getId());
/* Check the resource group does not exist. */
assertFalse(resourceDao.exists(resourceGroup.getId()));
/* Check workers still exist. */
assertTrue(resourceDao.exists(worker1.getId()));
assertTrue(resourceDao.exists(worker2.getId()));
/* Check workers do not belong to any resource group. */
assertNull(worker1.getResourceGroup());
assertNull(worker2.getResourceGroup());
/* Remove workers. */
resourceService.removeResource(worker1.getId());
resourceService.removeResource(worker2.getId());
/* Check workers do not exist. */
assertFalse(resourceDao.exists(worker1.getId()));
assertFalse(resourceDao.exists(worker2.getId()));
}
@Test
public void testListWorkers() throws Exception {
ResourceGroup resourceGroup = new ResourceGroup();
Worker worker1 = new Worker("worker-1", "worker-2-surname",
"11111111A", 8);
Worker worker2 = new Worker("worker-2", "worker-3-surname",
"22222222B", 6);
Worker worker3 = new Worker("worker-3", "worker-3-surname",
"33333333C", 4);
resourceGroup.addResource(worker1);
resourceGroup.addResource(worker2);
resourceService.saveResource(resourceGroup);
assertEquals(
"Two workers has been created when saving the resource group",
2, resourceService.getWorkers().size());
resourceService.saveResource(worker3);
assertEquals("Three workers has been created", 3, resourceService
.getWorkers().size());
}
}

View file

@ -1,7 +1,6 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<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>
<parent>
<groupId>org.navalplanner</groupId>
@ -15,7 +14,7 @@
<build>
<finalName>navalplanner-webapp</finalName>
</build>
<dependencies>
<!-- Spring -->
<dependency>
@ -44,17 +43,25 @@
<dependency>
<groupId>org.zkoss.zk</groupId>
<artifactId>zk</artifactId>
</dependency>
</dependency>
<!-- Naval Planner ZK Components -->
<dependency>
<groupId>org.navalplanner</groupId>
<artifactId>navalplanner-gantt-zk</artifactId>
</dependency>
</dependency>
<!-- Naval Planner Business -->
<dependency>
<groupId>org.navalplanner</groupId>
<artifactId>navalplanner-business</artifactId>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,27 @@
package org.navalplanner.web.common;
import java.util.Arrays;
import java.util.List;
import org.zkoss.zk.ui.Component;
/**
* Utility for enforcing that only one of the supplied component is visible. <br />
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
public class OnlyOneVisible {
private List<Component> components;
public OnlyOneVisible(Component... components) {
this.components = Arrays.asList(components);
showOnly(null);
}
public void showOnly(Component component) {
for (Component c : components) {
c.setVisible(component != null && c.equals(component));
}
}
}

View file

@ -0,0 +1,23 @@
package org.navalplanner.web.common;
import org.zkoss.zk.ui.Component;
import org.zkoss.zkplus.databind.DataBinder;
/**
* Utilities class. <br />
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
public class Util {
public static void reloadBindings(Component reload) {
DataBinder binder = Util.getBinder(reload);
if (binder != null) {
binder.loadComponent(reload);
}
}
public static DataBinder getBinder(Component component) {
return (DataBinder) component.getVariable("binder", false);
}
}

View file

@ -0,0 +1,19 @@
package org.navalplanner.web.resources;
import java.util.List;
import org.navalplanner.business.resources.entities.Worker;
/**
* Interface for workerModel. <br />
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
public interface IWorkerModel {
Worker createNewInstance();
void save(Worker worker);
List<Worker> getWorkers();
}

View file

@ -0,0 +1,99 @@
package org.navalplanner.web.resources;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.navalplanner.business.resources.entities.Worker;
import org.navalplanner.web.common.OnlyOneVisible;
import org.navalplanner.web.common.Util;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.api.Window;
/**
* Controller for {@link Worker} resource <br />
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
public class WorkerCRUDController extends GenericForwardComposer {
private static final Log LOG = LogFactory
.getLog(WorkerCRUDController.class);
private Window createWindow;
private Window listWindow;
private Window editWindow;
private IWorkerModel workerModel;
private Worker worker;
private OnlyOneVisible visibility;
public WorkerCRUDController() {
}
public WorkerCRUDController(Window createWindow, Window listWindow,
Window editWindow, IWorkerModel workerModel) {
this.createWindow = createWindow;
this.listWindow = listWindow;
this.editWindow = editWindow;
this.workerModel = workerModel;
}
public Worker getWorker() {
if (worker == null) {
worker = workerModel.createNewInstance();
}
return worker;
}
public List<Worker> getWorkers() {
return workerModel.getWorkers();
}
public void save() {
workerModel.save(worker);
getVisibility().showOnly(listWindow);
Util.reloadBindings(listWindow);
worker = null;
}
public void cancel() {
getVisibility().showOnly(listWindow);
worker = null;
}
public void goToEditForm(Worker worker) {
if (worker == null)
throw new IllegalArgumentException("worker cannot be null");
this.worker = worker;
getVisibility().showOnly(editWindow);
Util.reloadBindings(editWindow);
}
public void goToCreateForm() {
worker = workerModel.createNewInstance();
getVisibility().showOnly(createWindow);
Util.reloadBindings(createWindow);
}
@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
comp.setVariable("controller", this, true);
getVisibility().showOnly(listWindow);
}
private OnlyOneVisible getVisibility() {
if (visibility == null) {
visibility = new OnlyOneVisible(listWindow, editWindow,
createWindow);
}
return visibility;
}
}

View file

@ -0,0 +1,39 @@
package org.navalplanner.web.resources;
import java.util.List;
import org.navalplanner.business.resources.entities.Worker;
import org.navalplanner.business.resources.services.ResourceService;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Model for worker <br />
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
public class WorkerModel implements IWorkerModel {
private final ResourceService resourceService;
@Autowired
public WorkerModel(ResourceService resourceService) {
if (resourceService == null)
throw new IllegalArgumentException("resourceService cannot be null");
this.resourceService = resourceService;
}
@Override
public Worker createNewInstance() {
return new Worker();
}
@Override
public void save(Worker worker) {
resourceService.saveResource(worker);
}
@Override
public List<Worker> getWorkers() {
return resourceService.getWorkers();
}
}

View file

@ -1,16 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!-- For enabling annotation-based configuration (in particular, required
for "@Autowired") -->
<context:annotation-config/>
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!--
For enabling annotation-based configuration (in particular,
required for "@Autowired")
-->
<context:annotation-config />
<bean id="workerModel" class="org.navalplanner.web.resources.WorkerModel"
scope="prototype" />
</beans>

View file

@ -0,0 +1,31 @@
<window id="${arg.top_id}" title="${arg.title}">
<grid fixedLayout="true">
<columns>
<column label="Type" width="150px" />
<column label="Content" />
</columns>
<rows>
<row>
<label value="first_name" width="150px" />
<textbox value="@{controller.worker.firstName}"
width="150px" />
</row>
<row>
<label value="last_name" width="150px" />
<textbox value="@{controller.worker.surname}"
width="150px" />
</row>
<row>
<label value="nif" width="150px" />
<textbox value="@{controller.worker.nif}" width="150px" />
</row>
<row>
<label value="daily_hours" width="150px" />
<textbox value="@{controller.worker.dailyHours}"
width="150px" />
</row>
</rows>
</grid>
<button onClick="controller.save();" label="${arg.save_button_label}" />
<button onClick="controller.cancel();" label="${arg.cancel_button_label}" />
</window>

View file

@ -0,0 +1,28 @@
<window id="${arg.top_id}" title="List">
<grid id="listing" model="@{controller.workers}" mold="paging"
pageSize="5">
<columns>
<column label="First Name" />
<column label="Surname" />
<column label="nif" />
<column label="daily_hours" />
<column label="operations" />
</columns>
<rows>
<row self="@{each='worker'}" value="@{worker}">
<label value="@{worker.firstName}" />
<label value="@{worker.surname}" />
<label value="@{worker.nif}" />
<label value="@{worker.dailyHours}" />
<hbox>
<button label="Edit"
onClick="controller.goToEditForm(self.getParent().getParent().value);">
</button>
</hbox>
</row>
</rows>
</grid>
<button id="show_create_form" onClick="controller.goToCreateForm();"
label="Create">
</button>
</window>

View file

@ -0,0 +1,17 @@
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>
<?taglib uri="http://www.zkoss.org/dsp/web/core" prefix="c"?>
<?page id="Create"?>
<?init class="org.zkoss.zk.ui.util.Composition" arg0="/common/layout/template.zul"?>
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<?component name="list" inline="true" macroURI="_list.zul"?>
<?component name="edition" inline="true" macroURI="_edition.zul"?>
<zk>
<window title="Worker" self="@{define(content)}"
apply="org.navalplanner.web.resources.WorkerCRUDController">
<list top_id="listWindow" />
<edition top_id="createWindow" title="Create"
save_button_label="Save" cancel_button_label="Cancel" />
<edition top_id="editWindow" title="Edit"
save_button_label="Save" cancel_button_label="Cancel" />
</window>
</zk>

View file

@ -0,0 +1,95 @@
package org.navalplanner.web.resources;
import static junit.framework.Assert.assertEquals;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import org.navalplanner.business.resources.entities.Worker;
import org.zkoss.zul.api.Window;
/**
* Tests for {@link WorkerCRUDController} <br />
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
public class WorkerCRUDControllerTest {
private Window createWindow;
private Window listWindow;
private Window editWindow;
private WorkerCRUDController createControllerForModel(
IWorkerModel workerModel) {
createWindow = createNiceMock(Window.class);
listWindow = createNiceMock(Window.class);
editWindow = createNiceMock(Window.class);
WorkerCRUDController workerCRUDController = new WorkerCRUDController(
createWindow, listWindow, editWindow, workerModel);
return workerCRUDController;
}
@Test
public void testSave() throws Exception {
IWorkerModel workerModel = createMock(IWorkerModel.class);
Worker workerToReturn = new Worker();
WorkerCRUDController workerCRUDController = createControllerForModel(workerModel);
replay(createWindow, listWindow, editWindow);
// expectations
expect(workerModel.createNewInstance()).andReturn(workerToReturn);
workerModel.save(workerToReturn);
replay(workerModel);
// action
workerCRUDController.goToCreateForm();
workerCRUDController.save();
// verify
verify(workerModel);
}
@Test
public void testGoToSaveAndThenCancel() {
IWorkerModel workerModel = createMock(IWorkerModel.class);
Worker workerToReturn = new Worker();
// expectations
WorkerCRUDController workerCRUDController = createControllerForModel(workerModel);
expect(workerModel.createNewInstance()).andReturn(workerToReturn);
expect(createWindow.setVisible(true)).andReturn(false);
expect(createWindow.setVisible(false)).andReturn(true);
expect(listWindow.setVisible(true)).andReturn(false);
replay(createWindow, listWindow, editWindow, workerModel);
// actions
workerCRUDController.goToCreateForm();
workerCRUDController.cancel();
// verify
verify(workerModel);
}
@Test
public void testEditWorker() throws Exception {
IWorkerModel workerModel = createMock(IWorkerModel.class);
WorkerCRUDController workerCRUDController = createControllerForModel(workerModel);
List<Worker> workersToReturn = new ArrayList<Worker>(Arrays.asList(
new Worker("firstName", "surname", "nif", 4), new Worker(
"firstName", "surname", "nif", 4)));
// expectations
expect(workerModel.getWorkers()).andReturn(workersToReturn);
expect(editWindow.setVisible(true)).andReturn(false);
workerModel.save(workersToReturn.get(0));
replay(createWindow, listWindow, editWindow, workerModel);
// perform actions
List<Worker> workers = workerCRUDController.getWorkers();
assertEquals(workersToReturn, workers);
workerCRUDController.goToEditForm(workers.get(0));
workerCRUDController.save();
// verify
verify(workerModel, editWindow);
}
}

201
pom.xml
View file

@ -1,28 +1,32 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<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>
<groupId>org.navalplanner</groupId>
<artifactId>navalplanner</artifactId>
<packaging>pom</packaging>
<version>1.0.0</version>
<name>Naval Planner</name>
<!-- =================================================================== -->
<!--
===================================================================
-->
<!-- Modules -->
<modules>
<module>navalplanner-business</module>
<module>navalplanner-gantt-zk</module>
<module>navalplanner-webapp</module>
</modules>
<!-- =================================================================== -->
<!-- Default values for properties. These default values are expected to be
valid for most profiles. Specific profiles can overwrite values when
necessary.
<!--
===================================================================
-->
<properties>
<!--
Default values for properties. These default values are expected
to be valid for most profiles. Specific profiles can overwrite
values when necessary.
-->
<properties>
<!-- Data source properties -->
<dataSource.user>naval</dataSource.user>
<dataSource.password>naval</dataSource.password>
@ -30,50 +34,38 @@
<testDataSource.user>${dataSource.user}</testDataSource.user>
<testDataSource.password>${dataSource.password}</testDataSource.password>
</properties>
<!-- =================================================================== -->
<!-- Profiles.
* The build is always executed by selecting at least two non-exclusive
profiles. By default, such profiles are "dev" and "postgresql"
(meaning "use PostgreSQL assuming a development environment").
* General profiles. There are two general (database-independent)
profiles: "dev" and "prod". The former is used for development
(including testing) and the latter is used for production (including
testing). As shown below, two dataSources (databases schemas) are
used in both profiles: one for running (dataSource) and another one
for the Maven test fase (testDataSource). Note the Maven test fase
is executed both with development and production profiles.
* Database-specific profiles. There is a profile for each supported
database.
* Specific profiles can be defined to better adapt to a particular
environment by overwriting/adding properties and/or including other
chunks of valid XML.
* Usage:
+ mvn <<goal>> => Execute <<goal>> with default profiles.
+ mvn -Pdev,<<database>> <<goal> => Execute <<goal>> with "dev"
and <<database>> profiles.
+ mvn -Pprod,<<database>> <<goal>> => Execute <<goal>> with
"prod" and <<database>> profiles.
+ Note that when using -P option all desired profiles must be
specified (e.g. "-Pprod" with the intention to select "prod" and
the default database profile is not correct;
"-Pprod,<<database>>" must be used instead).
* Examples:
+ mvn <<goal>>
+ mvn -Ppostgresql,prod <<goal>>
+ mvn -Ppostgresql,dev <<goal>>
<!--
===================================================================
-->
<profiles>
<!--
Profiles. * The build is always executed by selecting at least
two non-exclusive profiles. By default, such profiles are "dev"
and "postgresql" (meaning "use PostgreSQL assuming a development
environment"). * General profiles. There are two general
(database-independent) profiles: "dev" and "prod". The former is
used for development (including testing) and the latter is used
for production (including testing). As shown below, two
dataSources (databases schemas) are used in both profiles: one
for running (dataSource) and another one for the Maven test fase
(testDataSource). Note the Maven test fase is executed both with
development and production profiles. * Database-specific
profiles. There is a profile for each supported database. *
Specific profiles can be defined to better adapt to a particular
environment by overwriting/adding properties and/or including
other chunks of valid XML. * Usage: + mvn <<goal>> => Execute
<<goal>> with default profiles. + mvn -Pdev,<<database>> <<goal>
=> Execute <<goal>> with "dev" and <<database>> profiles. + mvn
-Pprod,<<database>> <<goal>> => Execute <<goal>> with "prod" and
<<database>> profiles. + Note that when using -P option all
desired profiles must be specified (e.g. "-Pprod" with the
intention to select "prod" and the default database profile is
not correct; "-Pprod,<<database>>" must be used instead). *
Examples: + mvn <<goal>> + mvn -Ppostgresql,prod <<goal>> + mvn
-Ppostgresql,dev <<goal>>
-->
<profiles>
<!-- Development profile -->
<profile>
<id>dev</id>
@ -90,7 +82,7 @@
<hibernate.hbm2ddl.auto>update</hibernate.hbm2ddl.auto>
</properties>
</profile>
<!-- Production profile -->
<profile>
<id>prod</id>
@ -103,7 +95,7 @@
<hibernate.use_sql_comments>false</hibernate.use_sql_comments>
<hibernate.hbm2ddl.auto>update</hibernate.hbm2ddl.auto>
</properties>
</profile>
</profile>
<!-- PostgreSQL profile -->
<profile>
@ -123,8 +115,8 @@
<!-- Hibernate properties -->
<hibernate.dialect>org.hibernate.dialect.PostgreSQLDialect</hibernate.dialect>
</properties>
</profile>
</profile>
<!-- MySQL profile -->
<profile>
<id>mysql</id>
@ -141,7 +133,7 @@
<hibernate.dialect>org.hibernate.dialect.MySQLDialect</hibernate.dialect>
</properties>
</profile>
<!-- HSQLDB profile -->
<profile>
<id>hsqldb</id>
@ -153,17 +145,19 @@
<jdbcDriver.className>org.hsqldb.jdbcDriver</jdbcDriver.className>
<!-- Data source properties -->
<dataSource.user>sa</dataSource.user>
<dataSource.password/>
<dataSource.password />
<dataSource.url>jdbc:hsqldb:${java.io.tmpdir}/naval${navalplanner.mode};shutdown=true</dataSource.url>
<testDataSource.url>jdbc:hsqldb:${java.io.tmpdir}/naval${navalplanner.mode}test;shutdown=true</testDataSource.url>
<!-- Hibernate properties -->
<hibernate.dialect>org.hibernate.dialect.HSQLDialect</hibernate.dialect>
</properties>
</profile>
</profile>
</profiles>
<!-- =================================================================== -->
<!--
===================================================================
-->
<!-- Dependency management -->
<dependencyManagement>
<dependencies>
@ -181,14 +175,25 @@
<version>3.2.6.ga</version>
</dependency>
<!-- JUnit -->
<!-- IMPORTANT: Spring TestContext 2.5.x is not compatible with
JUnit 4.5. -->
<!--
IMPORTANT: Spring TestContext 2.5.x is not compatible
with JUnit 4.5.
-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.4</version>
<scope>test</scope>
</dependency>
<!-- Easy mock -->
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>2.4</version>
<scope>test</scope>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
@ -257,15 +262,17 @@
</dependency>
</dependencies>
</dependencyManagement>
<build>
<!-- =============================================================== -->
<!-- Filtering -->
<resources>
<!-- Apply filtering to files matching the following expressions
in src/main/resources. -->
<!--
Apply filtering to files matching the following
expressions in src/main/resources.
-->
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
@ -274,13 +281,15 @@
<include>*hibernate.cfg.xml</include>
</includes>
</resource>
<!-- Continue considering resources the files in src/main/resources,
but without applying filtering. -->
<!--
Continue considering resources the files in
src/main/resources, but without applying filtering.
-->
<resource>
<directory>src/main/resources</directory>
</resource>
<!-- Filter Jetty configuration -->
<resource>
<directory>../src/main/jetty</directory>
@ -291,11 +300,13 @@
<filtering>true</filtering>
</resource>
</resources>
<testResources>
<!-- Apply filtering to files matching the following expressions
in src/test/resources. -->
<!--
Apply filtering to files matching the following
expressions in src/test/resources.
-->
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
@ -305,12 +316,14 @@
</includes>
</testResource>
<!-- Continue considering resources the files in src/test/resources,
but without applying filtering. -->
<!--
Continue considering resources the files in
src/test/resources, but without applying filtering.
-->
<testResource>
<directory>src/test/resources</directory>
</testResource>
</testResource>
</testResources>
<plugins>
@ -324,7 +337,7 @@
<verbose>true</verbose>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
@ -338,11 +351,11 @@
</descriptors>
</configuration>
</plugin>
<!-- =========================================================== -->
<!-- Jetty configuration -->
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<!-- FIXME: try to not to specify version. -->
@ -361,17 +374,17 @@
<!-- Log to the console. -->
<requestLog implementation="org.mortbay.jetty.NCSARequestLog">
<!-- This do anything for Jetty, but is a workaround
for a Maven bug that prevents the requestLog from
being set. -->
<!--
This do anything for Jetty, but is a
workaround for a Maven bug that prevents the
requestLog from being set.
-->
<append>true</append>
</requestLog>
<!--
<connectors>
<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
<port>9090</port>
</connector>
</connectors>
<connectors> <connector
implementation="org.mortbay.jetty.nio.SelectChannelConnector">
<port>9090</port> </connector> </connectors>
-->
</configuration>
@ -382,11 +395,11 @@
<version>${jdbcDriver.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>