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,5 +1,4 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@ -37,6 +36,11 @@
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId> <artifactId>spring-test</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
</project> </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.io.Serializable;
import java.util.List;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException; import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
@ -27,4 +28,6 @@ public interface IGenericDao <E, PK extends Serializable>{
public void remove(PK id) throws InstanceNotFoundException; 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.io.Serializable;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.util.List;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.SessionFactory; import org.hibernate.SessionFactory;
import org.hibernate.criterion.Projections; import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions; import org.hibernate.criterion.Restrictions;
import org.navalplanner.business.common.daos.IGenericDao; import org.navalplanner.business.common.daos.IGenericDao;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException; import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -33,8 +33,8 @@ import org.springframework.orm.hibernate3.SessionFactoryUtils;
* @param <E> Entity class * @param <E> Entity class
* @param <PK> Primary key class * @param <PK> Primary key class
*/ */
public class GenericDaoHibernate<E, PK extends Serializable> public class GenericDaoHibernate<E, PK extends Serializable> implements
implements IGenericDao<E, PK> { IGenericDao<E, PK> {
private Class<E> entityClass; private Class<E> entityClass;
@ -43,8 +43,8 @@ public class GenericDaoHibernate<E, PK extends Serializable>
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public GenericDaoHibernate() { public GenericDaoHibernate() {
this.entityClass = (Class<E>) ((ParameterizedType) getClass(). this.entityClass = (Class<E>) ((ParameterizedType) getClass()
getGenericSuperclass()).getActualTypeArguments()[0]; .getGenericSuperclass()).getActualTypeArguments()[0];
} }
protected Session getSession() { protected Session getSession() {
@ -52,9 +52,9 @@ public class GenericDaoHibernate<E, PK extends Serializable>
} }
protected DataAccessException convertHibernateAccessException( protected DataAccessException convertHibernateAccessException(
HibernateException e) { HibernateException e) {
return SessionFactoryUtils.convertHibernateAccessException(e); return SessionFactoryUtils.convertHibernateAccessException(e);
} }
@ -91,10 +91,9 @@ public class GenericDaoHibernate<E, PK extends Serializable>
try { try {
return getSession().createCriteria(entityClass). return getSession().createCriteria(entityClass).add(
add(Restrictions.idEq(id)). Restrictions.idEq(id)).setProjection(Projections.id())
setProjection(Projections.id()). .uniqueResult() != null;
uniqueResult() != null;
} catch (HibernateException e) { } catch (HibernateException e) {
throw convertHibernateAccessException(e); throw convertHibernateAccessException(e);
@ -112,4 +111,10 @@ public class GenericDaoHibernate<E, PK extends Serializable>
} }
@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.io.Serializable;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.util.List;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.SessionFactory; import org.hibernate.SessionFactory;
import org.hibernate.criterion.Projections; import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions; import org.hibernate.criterion.Restrictions;
import org.navalplanner.business.common.daos.IGenericDao; import org.navalplanner.business.common.daos.IGenericDao;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException; import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -33,8 +33,8 @@ import org.springframework.orm.hibernate3.HibernateTemplate;
* @param <E> Entity class * @param <E> Entity class
* @param <PK> Primary key class * @param <PK> Primary key class
*/ */
public class GenericDaoHibernateTemplate<E, PK extends Serializable> public class GenericDaoHibernateTemplate<E, PK extends Serializable> implements
implements IGenericDao<E, PK> { IGenericDao<E, PK> {
private Class<E> entityClass; private Class<E> entityClass;
@ -42,8 +42,8 @@ public class GenericDaoHibernateTemplate<E, PK extends Serializable>
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public GenericDaoHibernateTemplate() { public GenericDaoHibernateTemplate() {
this.entityClass = (Class<E>) ((ParameterizedType) getClass(). this.entityClass = (Class<E>) ((ParameterizedType) getClass()
getGenericSuperclass()).getActualTypeArguments()[0]; .getGenericSuperclass()).getActualTypeArguments()[0];
} }
protected HibernateTemplate getHibernateTemplate() { protected HibernateTemplate getHibernateTemplate() {
@ -76,10 +76,9 @@ public class GenericDaoHibernateTemplate<E, PK extends Serializable>
return (Boolean) hibernateTemplate.execute(new HibernateCallback() { return (Boolean) hibernateTemplate.execute(new HibernateCallback() {
public Object doInHibernate(Session session) { public Object doInHibernate(Session session) {
return session.createCriteria(entityClass). return session.createCriteria(entityClass).add(
add(Restrictions.idEq(id)). Restrictions.idEq(id)).setProjection(Projections.id())
setProjection(Projections.id()). .uniqueResult() != null;
uniqueResult() != null;
} }
}); });
@ -89,4 +88,10 @@ public class GenericDaoHibernateTemplate<E, PK extends Serializable>
hibernateTemplate.delete(find(id)); 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; package org.navalplanner.business.resources.services;
import java.util.List;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException; import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.resources.entities.Resource; import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.business.resources.entities.Worker;
/** /**
* Interface for the resource management service. * Interface for the resource management service.
@ -12,14 +15,14 @@ import org.navalplanner.business.resources.entities.Resource;
public interface ResourceService { public interface ResourceService {
/** /**
* It updates or inserts the resource passed as a parameter. If the * It updates or inserts the resource passed as a parameter. If the resource
* resource is a composite resource, updating or inserting is cascaded to * is a composite resource, updating or inserting is cascaded to the
* the resources contained in it. * resources contained in it.
*/ */
public void saveResource(Resource resource); public void saveResource(Resource resource);
public Resource findResource(Long resourceId) public Resource findResource(Long resourceId)
throws InstanceNotFoundException; 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
@ -36,6 +39,8 @@ public interface ResourceService {
* resources contained in it are not removed. * resources contained in it are not removed.
*/ */
public void removeResource(Long resourceId) public void removeResource(Long resourceId)
throws InstanceNotFoundException; throws InstanceNotFoundException;
public List<Worker> getWorkers();
} }

View file

@ -1,10 +1,13 @@
package org.navalplanner.business.resources.services.impl; package org.navalplanner.business.resources.services.impl;
import java.util.List;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException; import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.resources.daos.IResourceDao; import org.navalplanner.business.resources.daos.IResourceDao;
import org.navalplanner.business.resources.daos.IResourceGroupDao; import org.navalplanner.business.resources.daos.IResourceGroupDao;
import org.navalplanner.business.resources.entities.Resource; import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.business.resources.entities.ResourceGroup; import org.navalplanner.business.resources.entities.ResourceGroup;
import org.navalplanner.business.resources.entities.Worker;
import org.navalplanner.business.resources.services.ResourceService; import org.navalplanner.business.resources.services.ResourceService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -31,14 +34,14 @@ public class ResourceServiceImpl implements ResourceService {
@Transactional(readOnly = true) @Transactional(readOnly = true)
public Resource findResource(Long resourceId) public Resource findResource(Long resourceId)
throws InstanceNotFoundException { throws InstanceNotFoundException {
return resourceDao.find(resourceId); return resourceDao.find(resourceId);
} }
public void addResourceToResourceGroup(Long resourceId, public void addResourceToResourceGroup(Long resourceId, Long resourceGroupId)
Long resourceGroupId) throws InstanceNotFoundException { throws InstanceNotFoundException {
ResourceGroup resourceGroup = resourceGroupDao.find(resourceGroupId); ResourceGroup resourceGroup = resourceGroupDao.find(resourceGroupId);
@ -48,16 +51,20 @@ public class ResourceServiceImpl implements ResourceService {
@Transactional(readOnly = true) @Transactional(readOnly = true)
public int getResourceDailyCapacity(Long resourceId) public int getResourceDailyCapacity(Long resourceId)
throws InstanceNotFoundException { throws InstanceNotFoundException {
return resourceDao.find(resourceId).getDailyCapacity(); return resourceDao.find(resourceId).getDailyCapacity();
} }
public void removeResource(Long resourceId) public void removeResource(Long resourceId)
throws InstanceNotFoundException { throws InstanceNotFoundException {
resourceDao.find(resourceId).remove(); resourceDao.find(resourceId).remove();
} }
@Override
public List<Worker> getWorkers() {
return resourceDao.list(Worker.class);
}
} }

View file

@ -27,8 +27,8 @@ import org.springframework.transaction.annotation.Transactional;
* *
*/ */
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={BUSINESS_SPRING_CONFIG_FILE, @ContextConfiguration(locations = { BUSINESS_SPRING_CONFIG_FILE,
BUSINESS_SPRING_CONFIG_TEST_FILE}) BUSINESS_SPRING_CONFIG_TEST_FILE })
@Transactional @Transactional
public class ResourceServiceTest { public class ResourceServiceTest {
@ -40,13 +40,13 @@ public class ResourceServiceTest {
@Test @Test
public void testAddResourceToResourceGroup() public void testAddResourceToResourceGroup()
throws InstanceNotFoundException { throws InstanceNotFoundException {
/* Two workers. One of them belongs to a resource group. */ /* Two workers. One of them belongs to a resource group. */
Worker worker1 = new Worker("worker-1", "worker-1-surname", Worker worker1 = new Worker("worker-1", "worker-1-surname",
"11111111A", 8); "11111111A", 8);
Worker worker2 = new Worker("worker-2", "worker-2-surname", Worker worker2 = new Worker("worker-2", "worker-2-surname",
"22222222B", 7); "22222222B", 7);
ResourceGroup resourceGroup1 = new ResourceGroup(); ResourceGroup resourceGroup1 = new ResourceGroup();
resourceGroup1.addResource(worker1); resourceGroup1.addResource(worker1);
resourceService.saveResource(resourceGroup1); // worker1 is also saved. resourceService.saveResource(resourceGroup1); // worker1 is also saved.
@ -58,13 +58,13 @@ public class ResourceServiceTest {
/* Add workers to resource group. */ /* Add workers to resource group. */
resourceService.addResourceToResourceGroup(worker1.getId(), resourceService.addResourceToResourceGroup(worker1.getId(),
resourceGroup2.getId()); resourceGroup2.getId());
resourceService.addResourceToResourceGroup(worker2.getId(), resourceService.addResourceToResourceGroup(worker2.getId(),
resourceGroup2.getId()); resourceGroup2.getId());
/* Check resource group. */ /* Check resource group. */
ResourceGroup resourceGroup = (ResourceGroup) ResourceGroup resourceGroup = (ResourceGroup) resourceService
resourceService.findResource(resourceGroup2.getId()); .findResource(resourceGroup2.getId());
assertEquals(2, resourceGroup.getResources().size()); assertEquals(2, resourceGroup.getResources().size());
assertTrue(resourceGroup.getResources().contains(worker1)); assertTrue(resourceGroup.getResources().contains(worker1));
@ -76,23 +76,22 @@ public class ResourceServiceTest {
} }
@Test @Test
public void testGetResourceDailyCapacity() public void testGetResourceDailyCapacity() throws InstanceNotFoundException {
throws InstanceNotFoundException {
/* Three workers. */ /* Three workers. */
Worker worker1 = new Worker("worker-1", "worker-1-surname", Worker worker1 = new Worker("worker-1", "worker-1-surname",
"11111111A", 8); "11111111A", 8);
Worker worker2 = new Worker("worker-2", "worker-2-surname", Worker worker2 = new Worker("worker-2", "worker-2-surname",
"22222222B", 7); "22222222B", 7);
Worker worker3 = new Worker("worker-3", "worker-3-surname", Worker worker3 = new Worker("worker-3", "worker-3-surname",
"33333333C", 6); "33333333C", 6);
/* A group of two workers. */ /* A group of two workers. */
ResourceGroup resourceGroup1 = new ResourceGroup(); ResourceGroup resourceGroup1 = new ResourceGroup();
Worker worker4 = new Worker("worker-4", "worker-4-surname", Worker worker4 = new Worker("worker-4", "worker-4-surname",
"44444444D", 5); "44444444D", 5);
Worker worker5 = new Worker("worker-5", "worker-5-surname", Worker worker5 = new Worker("worker-5", "worker-5-surname",
"55555555E", 4); "55555555E", 4);
resourceGroup1.addResource(worker4); resourceGroup1.addResource(worker4);
resourceGroup1.addResource(worker5); resourceGroup1.addResource(worker5);
@ -107,17 +106,16 @@ public class ResourceServiceTest {
resourceGroup2.addResource(resourceGroup1); resourceGroup2.addResource(resourceGroup1);
/* Calculate total daily capacity. */ /* Calculate total daily capacity. */
int totalDailyCapacity = int totalDailyCapacity = worker1.getDailyCapacity()
worker1.getDailyCapacity() + worker2.getDailyCapacity() + + worker2.getDailyCapacity() + worker3.getDailyCapacity()
worker3.getDailyCapacity() + worker4.getDailyCapacity() + + worker4.getDailyCapacity() + worker5.getDailyCapacity();
worker5.getDailyCapacity();
/* Save the second group (and in consequence all resources). */ /* Save the second group (and in consequence all resources). */
resourceService.saveResource(resourceGroup2); resourceService.saveResource(resourceGroup2);
/* Test ResourceService's getResourceDailyCapacity. */ /* Test ResourceService's getResourceDailyCapacity. */
int resourceGroupDailyCapacity = int resourceGroupDailyCapacity = resourceService
resourceService.getResourceDailyCapacity(resourceGroup2.getId()); .getResourceDailyCapacity(resourceGroup2.getId());
assertEquals(totalDailyCapacity, resourceGroupDailyCapacity); assertEquals(totalDailyCapacity, resourceGroupDailyCapacity);
@ -129,11 +127,11 @@ public class ResourceServiceTest {
/* A group of three workers. */ /* A group of three workers. */
ResourceGroup resourceGroup = new ResourceGroup(); ResourceGroup resourceGroup = new ResourceGroup();
Worker worker1 = new Worker("worker-1", "worker-2-surname", Worker worker1 = new Worker("worker-1", "worker-2-surname",
"11111111A", 8); "11111111A", 8);
Worker worker2 = new Worker("worker-2", "worker-3-surname", Worker worker2 = new Worker("worker-2", "worker-3-surname",
"22222222B", 6); "22222222B", 6);
Worker worker3 = new Worker("worker-3", "worker-3-surname", Worker worker3 = new Worker("worker-3", "worker-3-surname",
"33333333C", 4); "33333333C", 4);
resourceGroup.addResource(worker1); resourceGroup.addResource(worker1);
resourceGroup.addResource(worker2); resourceGroup.addResource(worker2);
resourceGroup.addResource(worker3); resourceGroup.addResource(worker3);
@ -146,8 +144,8 @@ public class ResourceServiceTest {
assertFalse(resourceDao.exists(worker3.getId())); assertFalse(resourceDao.exists(worker3.getId()));
/* /*
* Check worker 3 is not in resource group and the other workers * Check worker 3 is not in resource group and the other workers are
* are still in the group. * still in the group.
*/ */
assertFalse(resourceGroup.getResources().contains(worker3)); assertFalse(resourceGroup.getResources().contains(worker3));
assertTrue(resourceGroup.getResources().contains(worker1)); assertTrue(resourceGroup.getResources().contains(worker1));
@ -177,4 +175,24 @@ public class ResourceServiceTest {
} }
@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,5 +1,4 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@ -55,6 +54,14 @@
<groupId>org.navalplanner</groupId> <groupId>org.navalplanner</groupId>
<artifactId>navalplanner-business</artifactId> <artifactId>navalplanner-business</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </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"?> <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" <beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation=" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 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/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"> 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") --> For enabling annotation-based configuration (in particular,
<context:annotation-config/> required for "@Autowired")
-->
<context:annotation-config />
<bean id="workerModel" class="org.navalplanner.web.resources.WorkerModel"
scope="prototype" />
</beans> </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);
}
}

147
pom.xml
View file

@ -1,5 +1,4 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@ -9,7 +8,9 @@
<version>1.0.0</version> <version>1.0.0</version>
<name>Naval Planner</name> <name>Naval Planner</name>
<!-- =================================================================== --> <!--
===================================================================
-->
<!-- Modules --> <!-- Modules -->
<modules> <modules>
<module>navalplanner-business</module> <module>navalplanner-business</module>
@ -17,10 +18,13 @@
<module>navalplanner-webapp</module> <module>navalplanner-webapp</module>
</modules> </modules>
<!-- =================================================================== --> <!--
<!-- Default values for properties. These default values are expected to be ===================================================================
valid for most profiles. Specific profiles can overwrite values when -->
necessary. <!--
Default values for properties. These default values are expected
to be valid for most profiles. Specific profiles can overwrite
values when necessary.
--> -->
<properties> <properties>
<!-- Data source properties --> <!-- Data source properties -->
@ -31,46 +35,34 @@
<testDataSource.password>${dataSource.password}</testDataSource.password> <testDataSource.password>${dataSource.password}</testDataSource.password>
</properties> </properties>
<!-- =================================================================== --> <!--
<!-- Profiles. ===================================================================
-->
* The build is always executed by selecting at least two non-exclusive <!--
profiles. By default, such profiles are "dev" and "postgresql" Profiles. * The build is always executed by selecting at least
(meaning "use PostgreSQL assuming a development environment"). two non-exclusive profiles. By default, such profiles are "dev"
and "postgresql" (meaning "use PostgreSQL assuming a development
* General profiles. There are two general (database-independent) environment"). * General profiles. There are two general
profiles: "dev" and "prod". The former is used for development (database-independent) profiles: "dev" and "prod". The former is
(including testing) and the latter is used for production (including used for development (including testing) and the latter is used
testing). As shown below, two dataSources (databases schemas) are for production (including testing). As shown below, two
used in both profiles: one for running (dataSource) and another one dataSources (databases schemas) are used in both profiles: one
for the Maven test fase (testDataSource). Note the Maven test fase for running (dataSource) and another one for the Maven test fase
is executed both with development and production profiles. (testDataSource). Note the Maven test fase is executed both with
development and production profiles. * Database-specific
* Database-specific profiles. There is a profile for each supported profiles. There is a profile for each supported database. *
database. Specific profiles can be defined to better adapt to a particular
environment by overwriting/adding properties and/or including
* Specific profiles can be defined to better adapt to a particular other chunks of valid XML. * Usage: + mvn <<goal>> => Execute
environment by overwriting/adding properties and/or including other <<goal>> with default profiles. + mvn -Pdev,<<database>> <<goal>
chunks of valid XML. => Execute <<goal>> with "dev" and <<database>> profiles. + mvn
-Pprod,<<database>> <<goal>> => Execute <<goal>> with "prod" and
* Usage: <<database>> profiles. + Note that when using -P option all
desired profiles must be specified (e.g. "-Pprod" with the
+ mvn <<goal>> => Execute <<goal>> with default profiles. intention to select "prod" and the default database profile is
+ mvn -Pdev,<<database>> <<goal> => Execute <<goal>> with "dev" not correct; "-Pprod,<<database>>" must be used instead). *
and <<database>> profiles. Examples: + mvn <<goal>> + mvn -Ppostgresql,prod <<goal>> + mvn
+ mvn -Pprod,<<database>> <<goal>> => Execute <<goal>> with -Ppostgresql,dev <<goal>>
"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>
@ -153,7 +145,7 @@
<jdbcDriver.className>org.hsqldb.jdbcDriver</jdbcDriver.className> <jdbcDriver.className>org.hsqldb.jdbcDriver</jdbcDriver.className>
<!-- Data source properties --> <!-- Data source properties -->
<dataSource.user>sa</dataSource.user> <dataSource.user>sa</dataSource.user>
<dataSource.password/> <dataSource.password />
<dataSource.url>jdbc:hsqldb:${java.io.tmpdir}/naval${navalplanner.mode};shutdown=true</dataSource.url> <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> <testDataSource.url>jdbc:hsqldb:${java.io.tmpdir}/naval${navalplanner.mode}test;shutdown=true</testDataSource.url>
<!-- Hibernate properties --> <!-- Hibernate properties -->
@ -163,7 +155,9 @@
</profiles> </profiles>
<!-- =================================================================== --> <!--
===================================================================
-->
<!-- Dependency management --> <!-- Dependency management -->
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
@ -181,14 +175,25 @@
<version>3.2.6.ga</version> <version>3.2.6.ga</version>
</dependency> </dependency>
<!-- JUnit --> <!-- 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> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.4</version> <version>4.4</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- Easy mock -->
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>2.4</version>
<scope>test</scope>
</dependency>
<!-- Spring --> <!-- Spring -->
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
@ -264,8 +269,10 @@
<!-- Filtering --> <!-- Filtering -->
<resources> <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> <resource>
<directory>src/main/resources</directory> <directory>src/main/resources</directory>
<filtering>true</filtering> <filtering>true</filtering>
@ -275,8 +282,10 @@
</includes> </includes>
</resource> </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> <resource>
<directory>src/main/resources</directory> <directory>src/main/resources</directory>
</resource> </resource>
@ -294,8 +303,10 @@
<testResources> <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> <testResource>
<directory>src/test/resources</directory> <directory>src/test/resources</directory>
<filtering>true</filtering> <filtering>true</filtering>
@ -305,8 +316,10 @@
</includes> </includes>
</testResource> </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> <testResource>
<directory>src/test/resources</directory> <directory>src/test/resources</directory>
</testResource> </testResource>
@ -361,17 +374,17 @@
<!-- Log to the console. --> <!-- Log to the console. -->
<requestLog implementation="org.mortbay.jetty.NCSARequestLog"> <requestLog implementation="org.mortbay.jetty.NCSARequestLog">
<!-- This do anything for Jetty, but is a workaround <!--
for a Maven bug that prevents the requestLog from This do anything for Jetty, but is a
being set. --> workaround for a Maven bug that prevents the
requestLog from being set.
-->
<append>true</append> <append>true</append>
</requestLog> </requestLog>
<!-- <!--
<connectors> <connectors> <connector
<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector"> implementation="org.mortbay.jetty.nio.SelectChannelConnector">
<port>9090</port> <port>9090</port> </connector> </connectors>
</connector>
</connectors>
--> -->
</configuration> </configuration>