ItEr07S06ArquitecturaServidorItEr06S04: pom.xml files improved and JavaDoc for navalplanner-business.
Relocated dependencies in Maven central repository haven been updated (pom.xml files), style of inclusion of dependencies has been improved (pom.xml files), profile-based approach (root pom.xml) has been improved (bug fixed for supporting multiple databases, PostgreSQL has been set as the default database, and addition of HSQLDB), README.txt updated, and JavDoc for navalplanner-business code.
This commit is contained in:
parent
f061d5c1d3
commit
47da4948bf
26 changed files with 297 additions and 158 deletions
46
README.txt
46
README.txt
|
|
@ -1,25 +1,19 @@
|
||||||
* DB creation
|
* Database creation
|
||||||
-----------
|
-----------------
|
||||||
|
|
||||||
+ Start MySQL:
|
+ Current databases supported: PostgreSQL (default), MySQL, and
|
||||||
- Unix: mysqld --default-table-type=InnoDB
|
HQLDB (In-Process/Standalone Mode).
|
||||||
- Windows: mysqld-nt --default-table-type=InnoDB(Windows).
|
|
||||||
|
+ For PostgreSQL and MySQL:
|
||||||
+ Create DB "navaldev" (for development):
|
|
||||||
- mysqladmin -u root create navaldev
|
- Create a database with name "navaldev" (for development).
|
||||||
|
- Create a database with name "navaldevtest" (for the test fase in
|
||||||
+ Create user "naval" with password "naval":
|
development).
|
||||||
- mysql -u root
|
- Create user "naval" with password "naval" with necessary privileges for
|
||||||
GRANT ALL PRIVILEGES ON navaldev.* to naval@localhost IDENTIFIED BY 'naval';
|
accessing (creating tables, selecting data from tables, etc.) the
|
||||||
|
previous databases.
|
||||||
|
|
||||||
+ Create another DB with name "navaldevtest" (for testing). The user created
|
* For HSQLDB. There is nothing to do.
|
||||||
above will need to access this new DB.
|
|
||||||
|
|
||||||
- mysqladmin -u root create navaldevtest
|
|
||||||
- mysql -u root
|
|
||||||
GRANT ALL PRIVILEGES ON navaldevtest.* to naval@localhost IDENTIFIED BY 'naval';
|
|
||||||
|
|
||||||
+ PostgreSQL -> DB name=navaldev, user=naval, password=naval.
|
|
||||||
|
|
||||||
* Compilation
|
* Compilation
|
||||||
-----------
|
-----------
|
||||||
|
|
@ -43,12 +37,18 @@
|
||||||
+ To install the web application in a web container, use the WAR file:
|
+ To install the web application in a web container, use the WAR file:
|
||||||
navalplanner-webapp/target/navalplanner-webapp.war
|
navalplanner-webapp/target/navalplanner-webapp.war
|
||||||
|
|
||||||
+ NOTE: For PostgreSQL: mvn -Pdev,postgresql install
|
+ NOTES:
|
||||||
|
|
||||||
|
- Use "-Pdev,mysql" with "mvn" command if using MySQL.
|
||||||
|
e.g. mvn -Pdev,mysql install
|
||||||
|
|
||||||
|
- Use "-Pdev,hsqldb" with "mvn" command if using HSQLDB.
|
||||||
|
e.g. mvn -Pdev,hsqldb install
|
||||||
|
|
||||||
* Profiles
|
* Profiles
|
||||||
--------
|
--------
|
||||||
|
|
||||||
Check <profiles> section in the root pom.xml to see the profile-based approach
|
Check <profiles> section in the root pom.xml to see the profile-based approach
|
||||||
used in the project. The default profiles (the one assumed by the above
|
used in the project. The default profiles (the one assumed by the above
|
||||||
instructions) are "dev" and "mysql" (meaning "use MySQL assuming a development
|
instructions) are "dev" and "postgresql" (meaning "use PostgreSQL assuming a
|
||||||
environment").
|
development environment").
|
||||||
|
|
|
||||||
|
|
@ -13,18 +13,22 @@
|
||||||
<name>Naval Planner Business Module</name>
|
<name>Naval Planner Business Module</name>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<!-- JDBC driver -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${jdbcDriver.groupId}</groupId>
|
<groupId>${jdbcDriver.groupId}</groupId>
|
||||||
<artifactId>${jdbcDriver.artifactId}</artifactId>
|
<artifactId>${jdbcDriver.artifactId}</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- Hibernate -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate</groupId>
|
<groupId>org.hibernate</groupId>
|
||||||
<artifactId>hibernate</artifactId>
|
<artifactId>hibernate</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- JUnit -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- Spring -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring</artifactId>
|
<artifactId>spring</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
package org.navalplanner.business;
|
package org.navalplanner.business;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class containing constants for global names.
|
||||||
|
*
|
||||||
|
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class BusinessGlobalNames {
|
public class BusinessGlobalNames {
|
||||||
|
|
||||||
public final static String BUSINESS_SPRING_CONFIG_FILE =
|
public final static String BUSINESS_SPRING_CONFIG_FILE =
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,16 @@ import java.io.Serializable;
|
||||||
|
|
||||||
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
|
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface all DAOs (Data Access Objects) must implement. In general,
|
||||||
|
* a DAO must be implemented for each persistent entity. Concrete DAOs may
|
||||||
|
* provide (and usually will provide) additional methods.
|
||||||
|
*
|
||||||
|
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||||
|
*
|
||||||
|
* @param <E> Entity class
|
||||||
|
* @param <PK> Primary key class
|
||||||
|
*/
|
||||||
public interface IGenericDao <E, PK extends Serializable>{
|
public interface IGenericDao <E, PK extends Serializable>{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -16,16 +16,22 @@ import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.orm.hibernate3.SessionFactoryUtils;
|
import org.springframework.orm.hibernate3.SessionFactoryUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All Hibernate DAOs must extend directly from this class. This constraint is
|
* An implementation of <code>IGenericDao</code> based on Hibernate's native
|
||||||
* imposed by the constructor of this class that must infer the type of the
|
* API. Concrete DAOs must extend directly from this class. This constraint is
|
||||||
* entity from the concrete DAO declaration.
|
* imposed by the constructor of this class that must infer the type of the
|
||||||
|
* entity from the declaration of the concrete DAO. <p/>
|
||||||
*
|
*
|
||||||
* The class autowires a SessionFactory bean and allows to implement DAOs with
|
* This class autowires a <code>SessionFactory</code> bean and allows to
|
||||||
* the Hibernate's native API. Subclasses access Hibernate's Session by calling
|
* implement DAOs with Hibernate's native API. Subclasses access Hibernate's
|
||||||
* on getSession() method. Operations must be implemented by catching
|
* <code>Session</code> by calling on <code>getSession()</code> method.
|
||||||
* HibernateException and rethrowing it by using
|
* Operations must be implemented by catching <code>HibernateException</code>
|
||||||
* convertHibernateAccessException() method. See source code of this class
|
* and rethrowing it by using <code>convertHibernateAccessException()</code>
|
||||||
* for an example.
|
* method. See source code of this class for an example.
|
||||||
|
*
|
||||||
|
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||||
|
*
|
||||||
|
* @param <E> Entity class
|
||||||
|
* @param <PK> Primary key class
|
||||||
*/
|
*/
|
||||||
public class GenericDaoHibernate<E, PK extends Serializable>
|
public class GenericDaoHibernate<E, PK extends Serializable>
|
||||||
implements IGenericDao<E, PK> {
|
implements IGenericDao<E, PK> {
|
||||||
|
|
|
||||||
|
|
@ -14,16 +14,24 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.orm.hibernate3.HibernateCallback;
|
import org.springframework.orm.hibernate3.HibernateCallback;
|
||||||
import org.springframework.orm.hibernate3.HibernateTemplate;
|
import org.springframework.orm.hibernate3.HibernateTemplate;
|
||||||
|
|
||||||
// FIXME: This class is not currently used. I prefer GenericDaoHibernate.
|
// FIXME: This class is not currently used. I prefer GenericDaoHibernate, since
|
||||||
|
// it represents a non-intrusive use of Spring.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All Hibernate DAOs must extend directly from this class. This constraint is
|
* An implementation of <code>IGenericDao</code> based on Spring's
|
||||||
* imposed by the constructor of this class that must infer the type of the
|
* <code>HibernateTemplate</code>. Concrete DAOs must extend directly from
|
||||||
* entity from the concrete DAO declaration.
|
* this class. This constraint is imposed by the constructor of this class that
|
||||||
|
* must infer the type of the entity from the concrete DAO declaration. <p/>
|
||||||
*
|
*
|
||||||
* The class autowires a SessionFactory bean and allows to implement Spring's
|
* This class autowires a <code>SessionFactory</code> bean and allows to
|
||||||
* HibernateTemplate-based DAOs. Subclasses access HibernateTemplate by calling
|
* implement Spring's HibernateTemplate-based DAOs. Subclasses access
|
||||||
* on getHibernateTemplate() method.
|
* <code>HibernateTemplate</code> by calling on
|
||||||
|
* <code>getHibernateTemplate()</code> method.
|
||||||
|
*
|
||||||
|
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||||
|
*
|
||||||
|
* @param <E> Entity class
|
||||||
|
* @param <PK> Primary key class
|
||||||
*/
|
*/
|
||||||
public class GenericDaoHibernateTemplate<E, PK extends Serializable>
|
public class GenericDaoHibernateTemplate<E, PK extends Serializable>
|
||||||
implements IGenericDao<E, PK> {
|
implements IGenericDao<E, PK> {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
package org.navalplanner.business.common.exceptions;
|
package org.navalplanner.business.common.exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An exception for modeling an attempt to create a persistent instance with
|
||||||
|
* the same key than another existent instance.
|
||||||
|
*
|
||||||
|
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||||
|
*
|
||||||
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class DuplicateInstanceException extends InstanceException {
|
public class DuplicateInstanceException extends InstanceException {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
package org.navalplanner.business.common.exceptions;
|
package org.navalplanner.business.common.exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An exception for modeling a problem with an instance of a persistent entity.
|
||||||
|
* It contains a message, the key of the instance, and its class name.
|
||||||
|
*
|
||||||
|
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||||
|
*
|
||||||
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public abstract class InstanceException extends Exception {
|
public abstract class InstanceException extends Exception {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
package org.navalplanner.business.common.exceptions;
|
package org.navalplanner.business.common.exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An exception for modeling that no persistent instance can be located from
|
||||||
|
* a given key.
|
||||||
|
*
|
||||||
|
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||||
|
*
|
||||||
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class InstanceNotFoundException extends InstanceException {
|
public class InstanceNotFoundException extends InstanceException {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,10 @@ package org.navalplanner.business.resources.daos;
|
||||||
import org.navalplanner.business.common.daos.IGenericDao;
|
import org.navalplanner.business.common.daos.IGenericDao;
|
||||||
import org.navalplanner.business.resources.entities.Resource;
|
import org.navalplanner.business.resources.entities.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DAO interface for the <code>Resource</code> entity.
|
||||||
|
*
|
||||||
|
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||||
|
*
|
||||||
|
*/
|
||||||
public interface IResourceDao extends IGenericDao<Resource, Long> {}
|
public interface IResourceDao extends IGenericDao<Resource, Long> {}
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,10 @@ package org.navalplanner.business.resources.daos;
|
||||||
import org.navalplanner.business.common.daos.IGenericDao;
|
import org.navalplanner.business.common.daos.IGenericDao;
|
||||||
import org.navalplanner.business.resources.entities.ResourceGroup;
|
import org.navalplanner.business.resources.entities.ResourceGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DAO interface for the <code>ResourceGroup</code> entity.
|
||||||
|
*
|
||||||
|
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||||
|
*
|
||||||
|
*/
|
||||||
public interface IResourceGroupDao extends IGenericDao<ResourceGroup, Long> {}
|
public interface IResourceGroupDao extends IGenericDao<ResourceGroup, Long> {}
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,10 @@ package org.navalplanner.business.resources.daos;
|
||||||
import org.navalplanner.business.common.daos.IGenericDao;
|
import org.navalplanner.business.common.daos.IGenericDao;
|
||||||
import org.navalplanner.business.resources.entities.Worker;
|
import org.navalplanner.business.resources.entities.Worker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DAO interface for the <code>Worker</code> entity.
|
||||||
|
*
|
||||||
|
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||||
|
*
|
||||||
|
*/
|
||||||
public interface IWorkerDao extends IGenericDao<Worker, Long> {}
|
public interface IWorkerDao extends IGenericDao<Worker, Long> {}
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,13 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
// (I think it is not necessary).
|
// (I think it is not necessary).
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Classes in which dependency injection (DI) is not directly supported by
|
* A registry of resource DAOs. Classes in which dependency injection (DI) is
|
||||||
* Spring (e.g. entities) must use ResourcesDaoRegistry to access
|
* not directly supported by Spring (e.g. entities) must use this class to
|
||||||
* resource DAOs. For the rest of classes (e.g. services, tests, etc.) Spring
|
* access resource DAOs. For the rest of classes (e.g. services, tests, etc.),
|
||||||
* DI will be a more convenient option.
|
* Spring DI is a more convenient option.
|
||||||
|
*
|
||||||
|
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public final class ResourcesDaoRegistry {
|
public final class ResourcesDaoRegistry {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,5 +4,11 @@ import org.navalplanner.business.common.daos.impl.GenericDaoHibernate;
|
||||||
import org.navalplanner.business.resources.daos.IResourceDao;
|
import org.navalplanner.business.resources.daos.IResourceDao;
|
||||||
import org.navalplanner.business.resources.entities.Resource;
|
import org.navalplanner.business.resources.entities.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hibernate DAO for the <code>Resource</code> entity.
|
||||||
|
*
|
||||||
|
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class ResourceDaoHibernate extends GenericDaoHibernate<Resource, Long>
|
public class ResourceDaoHibernate extends GenericDaoHibernate<Resource, Long>
|
||||||
implements IResourceDao {}
|
implements IResourceDao {}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,12 @@ import org.navalplanner.business.common.daos.impl.GenericDaoHibernate;
|
||||||
import org.navalplanner.business.resources.daos.IResourceGroupDao;
|
import org.navalplanner.business.resources.daos.IResourceGroupDao;
|
||||||
import org.navalplanner.business.resources.entities.ResourceGroup;
|
import org.navalplanner.business.resources.entities.ResourceGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hibernate DAO for the <code>ResourceGroup</code> entity.
|
||||||
|
*
|
||||||
|
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class ResourceGroupDaoHibernate
|
public class ResourceGroupDaoHibernate
|
||||||
extends GenericDaoHibernate<ResourceGroup, Long>
|
extends GenericDaoHibernate<ResourceGroup, Long>
|
||||||
implements IResourceGroupDao {}
|
implements IResourceGroupDao {}
|
||||||
|
|
|
||||||
|
|
@ -4,5 +4,11 @@ import org.navalplanner.business.common.daos.impl.GenericDaoHibernate;
|
||||||
import org.navalplanner.business.resources.daos.IWorkerDao;
|
import org.navalplanner.business.resources.daos.IWorkerDao;
|
||||||
import org.navalplanner.business.resources.entities.Worker;
|
import org.navalplanner.business.resources.entities.Worker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hibernate DAO for the <code>Worker</code> entity.
|
||||||
|
*
|
||||||
|
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class WorkerDaoHibernate extends GenericDaoHibernate<Worker, Long>
|
public class WorkerDaoHibernate extends GenericDaoHibernate<Worker, Long>
|
||||||
implements IWorkerDao {}
|
implements IWorkerDao {}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,13 @@ import org.navalplanner.business.resources.daos.ResourcesDaoRegistry;
|
||||||
// child another simple resource, general methods like getChilds() do not make
|
// child another simple resource, general methods like getChilds() do not make
|
||||||
// sense for simple entities, etc.). In consequence, I prefer the modeling
|
// sense for simple entities, etc.). In consequence, I prefer the modeling
|
||||||
// option shown below.
|
// option shown below.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class acts as the base class for all resources.
|
||||||
|
*
|
||||||
|
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||||
|
*
|
||||||
|
*/
|
||||||
public abstract class Resource {
|
public abstract class Resource {
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,13 @@ import java.util.Set;
|
||||||
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
|
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
|
||||||
import org.navalplanner.business.resources.daos.ResourcesDaoRegistry;
|
import org.navalplanner.business.resources.daos.ResourcesDaoRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class models a resource group. A resource group represents a resource
|
||||||
|
* containing other resources.
|
||||||
|
*
|
||||||
|
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class ResourceGroup extends Resource {
|
public class ResourceGroup extends Resource {
|
||||||
|
|
||||||
private Set<Resource> resources = new HashSet<Resource>();
|
private Set<Resource> resources = new HashSet<Resource>();
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
package org.navalplanner.business.resources.entities;
|
package org.navalplanner.business.resources.entities;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class models a worker.
|
||||||
|
*
|
||||||
|
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class Worker extends Resource {
|
public class Worker extends Resource {
|
||||||
|
|
||||||
private String firstName;
|
private String firstName;
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,12 @@ package org.navalplanner.business.resources.services;
|
||||||
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;
|
||||||
|
|
||||||
// FIXME: Define validation approach for creating and updating entities.
|
/**
|
||||||
|
* Interface for the resource management service.
|
||||||
// FIXME: Originally we though the interface in a less generic way (e.g.
|
*
|
||||||
// createWorker, createResourceGroup, etc.). Now it is completely generic.
|
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||||
|
*
|
||||||
// FIXME: The interface must be oriented to detached objects (e.g.
|
*/
|
||||||
// removeResource(resource) instead of removeResource(resourceId))??? - It
|
|
||||||
// depends on final requirements.
|
|
||||||
public interface ResourceService {
|
public interface ResourceService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -30,11 +28,6 @@ public interface ResourceService {
|
||||||
public void addResourceToResourceGroup(Long resourceId,
|
public void addResourceToResourceGroup(Long resourceId,
|
||||||
Long resourceGroupId) throws InstanceNotFoundException;
|
Long resourceGroupId) throws InstanceNotFoundException;
|
||||||
|
|
||||||
// FIXME: Is the following signature better than the previous one??? - I prefer
|
|
||||||
// the previous one.
|
|
||||||
// public void addResourceToResourceGroup(Long resourceId, Long resourceGroupId)
|
|
||||||
// throws ResourceNotFoundException, ResourceGroupNotFoundException;
|
|
||||||
|
|
||||||
public int getResourceDailyCapacity(Long resourceId)
|
public int getResourceDailyCapacity(Long resourceId)
|
||||||
throws InstanceNotFoundException;
|
throws InstanceNotFoundException;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,13 @@ 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of the resource management service. Resource DAOs are
|
||||||
|
* autowired.
|
||||||
|
*
|
||||||
|
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||||
|
*
|
||||||
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
public class ResourceServiceImpl implements ResourceService {
|
public class ResourceServiceImpl implements ResourceService {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
package org.navalplanner.business.test;
|
package org.navalplanner.business.test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class containing constants for global names.
|
||||||
|
*
|
||||||
|
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class BusinessGlobalNames {
|
public class BusinessGlobalNames {
|
||||||
|
|
||||||
public final static String BUSINESS_SPRING_CONFIG_TEST_FILE =
|
public final static String BUSINESS_SPRING_CONFIG_TEST_FILE =
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,13 @@ import org.springframework.test.context.ContextConfiguration;
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class for testing <code>ResourceService</code>. The service and the
|
||||||
|
* resource DAOs are autowired.
|
||||||
|
*
|
||||||
|
* @author Fernando Bellas Permuy <fbellas@udc.es>
|
||||||
|
*
|
||||||
|
*/
|
||||||
@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})
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,11 @@
|
||||||
<name>Naval Planner ZK Components Module</name>
|
<name>Naval Planner ZK Components Module</name>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<!-- Commons Logging -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-logging</groupId>
|
||||||
|
<artifactId>commons-logging</artifactId>
|
||||||
|
</dependency>
|
||||||
<!-- ZK -->
|
<!-- ZK -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.zkoss.zk</groupId>
|
<groupId>org.zkoss.zk</groupId>
|
||||||
|
|
@ -26,14 +31,10 @@
|
||||||
<groupId>org.zkoss.zk</groupId>
|
<groupId>org.zkoss.zk</groupId>
|
||||||
<artifactId>zk</artifactId>
|
<artifactId>zk</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- Commons Logging -->
|
<!-- JGraphT -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-logging</groupId>
|
<groupId>org.jgrapht</groupId>
|
||||||
<artifactId>commons-logging</artifactId>
|
<artifactId>jgrapht-jdk1.5</artifactId>
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>jgrapht</groupId>
|
|
||||||
<artifactId>jgrapht</artifactId>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,21 @@
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<!-- Spring -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- BeanShell (required by ZK) -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.beanshell</groupId>
|
||||||
|
<artifactId>bsh</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- Apache Commons Fileupload (required by ZK) -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-fileupload</groupId>
|
||||||
|
<artifactId>commons-fileupload</artifactId>
|
||||||
|
</dependency>
|
||||||
<!-- ZK -->
|
<!-- ZK -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.zkoss.zk</groupId>
|
<groupId>org.zkoss.zk</groupId>
|
||||||
|
|
@ -29,7 +44,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.zkoss.zk</groupId>
|
<groupId>org.zkoss.zk</groupId>
|
||||||
<artifactId>zk</artifactId>
|
<artifactId>zk</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- Naval Planner ZK Components -->
|
<!-- Naval Planner ZK Components -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.navalplanner</groupId>
|
<groupId>org.navalplanner</groupId>
|
||||||
|
|
@ -40,25 +55,6 @@
|
||||||
<groupId>org.navalplanner</groupId>
|
<groupId>org.navalplanner</groupId>
|
||||||
<artifactId>navalplanner-business</artifactId>
|
<artifactId>navalplanner-business</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- Spring -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<!-- BeanShell (required by ZK)-->
|
|
||||||
<dependency>
|
|
||||||
<groupId>bsh</groupId>
|
|
||||||
<artifactId>bsh</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<!-- Apache Commons Fileupload (required by ZK) -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>commons-fileupload</groupId>
|
|
||||||
<artifactId>commons-fileupload</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.navalplanner</groupId>
|
|
||||||
<artifactId>navalplanner-business</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|
|
||||||
163
pom.xml
163
pom.xml
|
|
@ -19,9 +19,9 @@
|
||||||
|
|
||||||
<!-- =================================================================== -->
|
<!-- =================================================================== -->
|
||||||
<!-- Default values for properties. These default values are expected to be
|
<!-- Default values for properties. These default values are expected to be
|
||||||
valid for most profiles. In any case, profiles can overwrite values
|
valid for most profiles. Specific profiles can overwrite values when
|
||||||
when necessary.
|
necessary.
|
||||||
-->
|
-->
|
||||||
<properties>
|
<properties>
|
||||||
<!-- Data source properties -->
|
<!-- Data source properties -->
|
||||||
<dataSource.user>naval</dataSource.user>
|
<dataSource.user>naval</dataSource.user>
|
||||||
|
|
@ -35,8 +35,8 @@
|
||||||
<!-- Profiles.
|
<!-- Profiles.
|
||||||
|
|
||||||
* The build is always executed by selecting at least two non-exclusive
|
* The build is always executed by selecting at least two non-exclusive
|
||||||
profiles. By default, such profiles are "dev" and "mysql" (meaning
|
profiles. By default, such profiles are "dev" and "postgresql"
|
||||||
"use MySQL assuming a development environment").
|
(meaning "use PostgreSQL assuming a development environment").
|
||||||
|
|
||||||
* General profiles. There are two general (database-independent)
|
* General profiles. There are two general (database-independent)
|
||||||
profiles: "dev" and "prod". The former is used for development
|
profiles: "dev" and "prod". The former is used for development
|
||||||
|
|
@ -45,10 +45,10 @@
|
||||||
used in both profiles: one for running (dataSource) and another one
|
used in both profiles: one for running (dataSource) and another one
|
||||||
for the Maven test fase (testDataSource). Note the Maven test fase
|
for the Maven test fase (testDataSource). Note the Maven test fase
|
||||||
is executed both with development and production profiles.
|
is executed both with development and production profiles.
|
||||||
|
|
||||||
* Database-specific profiles. There is a profile for each supported
|
* Database-specific profiles. There is a profile for each supported
|
||||||
database.
|
database.
|
||||||
|
|
||||||
* Specific profiles can be defined to better adapt to a particular
|
* Specific profiles can be defined to better adapt to a particular
|
||||||
environment by overwriting/adding properties and/or including other
|
environment by overwriting/adding properties and/or including other
|
||||||
chunks of valid XML.
|
chunks of valid XML.
|
||||||
|
|
@ -56,24 +56,23 @@
|
||||||
* Usage:
|
* Usage:
|
||||||
|
|
||||||
+ mvn <<goal>> => Execute <<goal>> with default profiles.
|
+ mvn <<goal>> => Execute <<goal>> with default profiles.
|
||||||
+ mvn -Pdev,<<database>> <<goal> => Execute <<goal>> with
|
+ mvn -Pdev,<<database>> <<goal> => Execute <<goal>> with "dev"
|
||||||
development and <<database>> profiles.
|
and <<database>> profiles.
|
||||||
+ mvn -Pprod,<<database>> <<goal>> => Execute <<goal>> with
|
+ mvn -Pprod,<<database>> <<goal>> => Execute <<goal>> with
|
||||||
production and <<database>> profiles.
|
"prod" and <<database>> profiles.
|
||||||
|
|
||||||
+ Note that when using -P option all desired profiles must be
|
+ Note that when using -P option all desired profiles must be
|
||||||
specified (e.g. "-Pprod" with the intention to select "prod"
|
specified (e.g. "-Pprod" with the intention to select "prod" and
|
||||||
and the default database profiles is not correct;
|
the default database profile is not correct;
|
||||||
"-Pprod,<<database>>" must be used instead).
|
"-Pprod,<<database>>" must be used instead).
|
||||||
|
|
||||||
* Examples:
|
* Examples:
|
||||||
|
|
||||||
+ mvn <<goal>>
|
+ mvn <<goal>>
|
||||||
+ mvn -Pdev,mysql <<goal>>
|
+ mvn -Ppostgresql,prod <<goal>>
|
||||||
+ mvn -Pprod,mysql <<goal>>
|
+ mvn -Ppostgresql,dev <<goal>>
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<profiles>
|
<profiles>
|
||||||
|
|
||||||
<!-- Development profile -->
|
<!-- Development profile -->
|
||||||
<profile>
|
<profile>
|
||||||
|
|
@ -82,9 +81,8 @@
|
||||||
<activeByDefault>true</activeByDefault>
|
<activeByDefault>true</activeByDefault>
|
||||||
</activation>
|
</activation>
|
||||||
<properties>
|
<properties>
|
||||||
<!-- Data source properties -->
|
<!-- Naval Planner environment properties -->
|
||||||
<dataSource.url>jdbc:mysql://localhost/navaldev</dataSource.url>
|
<navalplanner.mode>dev</navalplanner.mode>
|
||||||
<testDataSource.url>${dataSource.url}test</testDataSource.url>
|
|
||||||
<!-- Hibernate properties -->
|
<!-- Hibernate properties -->
|
||||||
<hibernate.show_sql>true</hibernate.show_sql>
|
<hibernate.show_sql>true</hibernate.show_sql>
|
||||||
<hibernate.format_sql>true</hibernate.format_sql>
|
<hibernate.format_sql>true</hibernate.format_sql>
|
||||||
|
|
@ -97,39 +95,22 @@
|
||||||
<profile>
|
<profile>
|
||||||
<id>prod</id>
|
<id>prod</id>
|
||||||
<properties>
|
<properties>
|
||||||
<!-- Data source properties -->
|
<!-- Naval Planner environment properties -->
|
||||||
<!-- NOTE: particular production profiles will probably wish to
|
<navalplanner.mode>prod</navalplanner.mode>
|
||||||
overwrite "dataSource.url" property and also maybe
|
|
||||||
"testDataSource.url".-->
|
|
||||||
<dataSource.url>jdbc:mysql://localhost/navalprod</dataSource.url>
|
|
||||||
<testDataSource.url>${dataSource.url}test</testDataSource.url>
|
|
||||||
<!-- Hibernate properties -->
|
<!-- Hibernate properties -->
|
||||||
<hibernate.show_sql>false</hibernate.show_sql>
|
<hibernate.show_sql>false</hibernate.show_sql>
|
||||||
<hibernate.format_sql>false</hibernate.format_sql>
|
<hibernate.format_sql>false</hibernate.format_sql>
|
||||||
<hibernate.use_sql_comments>false</hibernate.use_sql_comments>
|
<hibernate.use_sql_comments>false</hibernate.use_sql_comments>
|
||||||
<hibernate.hbm2ddl.auto>update</hibernate.hbm2ddl.auto>
|
<hibernate.hbm2ddl.auto>update</hibernate.hbm2ddl.auto>
|
||||||
</properties>
|
</properties>
|
||||||
</profile>
|
</profile>
|
||||||
|
|
||||||
<!-- MySQL profile -->
|
<!-- PostgreSQL profile -->
|
||||||
<profile>
|
<profile>
|
||||||
<id>mysql</id>
|
<id>postgresql</id>
|
||||||
<activation>
|
<activation>
|
||||||
<activeByDefault>true</activeByDefault>
|
<activeByDefault>true</activeByDefault>
|
||||||
</activation>
|
</activation>
|
||||||
<properties>
|
|
||||||
<!-- JDBC driver properties -->
|
|
||||||
<jdbcDriver.groupId>mysql</jdbcDriver.groupId>
|
|
||||||
<jdbcDriver.artifactId>mysql-connector-java</jdbcDriver.artifactId>
|
|
||||||
<jdbcDriver.version>5.0.5</jdbcDriver.version>
|
|
||||||
<jdbcDriver.className>com.mysql.jdbc.Driver</jdbcDriver.className>
|
|
||||||
<!-- Hibernate properties -->
|
|
||||||
<hibernate.dialect>org.hibernate.dialect.MySQLDialect</hibernate.dialect>
|
|
||||||
</properties>
|
|
||||||
</profile>
|
|
||||||
|
|
||||||
<profile>
|
|
||||||
<id>postgresql</id>
|
|
||||||
<properties>
|
<properties>
|
||||||
<!-- JDBC driver properties -->
|
<!-- JDBC driver properties -->
|
||||||
<jdbcDriver.groupId>postgresql</jdbcDriver.groupId>
|
<jdbcDriver.groupId>postgresql</jdbcDriver.groupId>
|
||||||
|
|
@ -137,17 +118,49 @@
|
||||||
<jdbcDriver.version>8.3-603.jdbc4</jdbcDriver.version>
|
<jdbcDriver.version>8.3-603.jdbc4</jdbcDriver.version>
|
||||||
<jdbcDriver.className>org.postgresql.Driver</jdbcDriver.className>
|
<jdbcDriver.className>org.postgresql.Driver</jdbcDriver.className>
|
||||||
<!-- Data source properties -->
|
<!-- Data source properties -->
|
||||||
<!-- FIXME: Workaround for current bug in profile-based
|
<dataSource.url>jdbc:postgresql://localhost/naval${navalplanner.mode}</dataSource.url>
|
||||||
approach. -->
|
<testDataSource.url>${dataSource.url}test</testDataSource.url>
|
||||||
<dataSource.url>jdbc:postgresql://localhost/navaldev</dataSource.url>
|
|
||||||
<!-- Hibernate properties -->
|
<!-- Hibernate properties -->
|
||||||
<hibernate.dialect>org.hibernate.dialect.PostgreSQLDialect</hibernate.dialect>
|
<hibernate.dialect>org.hibernate.dialect.PostgreSQLDialect</hibernate.dialect>
|
||||||
</properties>
|
</properties>
|
||||||
|
</profile>
|
||||||
</profile>
|
|
||||||
|
|
||||||
<!-- Add here other profiles. -->
|
|
||||||
|
|
||||||
|
<!-- MySQL profile -->
|
||||||
|
<profile>
|
||||||
|
<id>mysql</id>
|
||||||
|
<properties>
|
||||||
|
<!-- JDBC driver properties -->
|
||||||
|
<jdbcDriver.groupId>mysql</jdbcDriver.groupId>
|
||||||
|
<jdbcDriver.artifactId>mysql-connector-java</jdbcDriver.artifactId>
|
||||||
|
<jdbcDriver.version>5.0.5</jdbcDriver.version>
|
||||||
|
<jdbcDriver.className>com.mysql.jdbc.Driver</jdbcDriver.className>
|
||||||
|
<!-- Data source properties -->
|
||||||
|
<dataSource.url>jdbc:mysql://localhost/naval${navalplanner.mode}</dataSource.url>
|
||||||
|
<testDataSource.url>${dataSource.url}test</testDataSource.url>
|
||||||
|
<!-- Hibernate properties -->
|
||||||
|
<hibernate.dialect>org.hibernate.dialect.MySQLDialect</hibernate.dialect>
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
|
|
||||||
|
<!-- HSQLDB profile -->
|
||||||
|
<profile>
|
||||||
|
<id>hsqldb</id>
|
||||||
|
<properties>
|
||||||
|
<!-- JDBC driver properties -->
|
||||||
|
<jdbcDriver.groupId>hsqldb</jdbcDriver.groupId>
|
||||||
|
<jdbcDriver.artifactId>hsqldb</jdbcDriver.artifactId>
|
||||||
|
<jdbcDriver.version>1.8.0.7</jdbcDriver.version>
|
||||||
|
<jdbcDriver.className>org.hsqldb.jdbcDriver</jdbcDriver.className>
|
||||||
|
<!-- Data source properties -->
|
||||||
|
<dataSource.user>sa</dataSource.user>
|
||||||
|
<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>
|
||||||
|
|
||||||
</profiles>
|
</profiles>
|
||||||
|
|
||||||
<!-- =================================================================== -->
|
<!-- =================================================================== -->
|
||||||
|
|
@ -187,7 +200,27 @@
|
||||||
<artifactId>spring-test</artifactId>
|
<artifactId>spring-test</artifactId>
|
||||||
<version>2.5.6</version>
|
<version>2.5.6</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- Commons Logging (required by many frameworks)-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-logging</groupId>
|
||||||
|
<artifactId>commons-logging</artifactId>
|
||||||
|
<version>1.0.4</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- BeanShell (required by ZK)-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.beanshell</groupId>
|
||||||
|
<artifactId>bsh</artifactId>
|
||||||
|
<version>2.0b4</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- Apache Commons Fileupload (required by ZK) -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-fileupload</groupId>
|
||||||
|
<artifactId>commons-fileupload</artifactId>
|
||||||
|
<version>1.2.1</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
<!-- ZK -->
|
<!-- ZK -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.zkoss.zk</groupId>
|
<groupId>org.zkoss.zk</groupId>
|
||||||
|
|
@ -204,11 +237,11 @@
|
||||||
<artifactId>zk</artifactId>
|
<artifactId>zk</artifactId>
|
||||||
<version>3.6.0.1</version>
|
<version>3.6.0.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- Commons Logging (required by many frameworks)-->
|
<!-- JGraphT -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-logging</groupId>
|
<groupId>org.jgrapht</groupId>
|
||||||
<artifactId>commons-logging</artifactId>
|
<artifactId>jgrapht-jdk1.5</artifactId>
|
||||||
<version>1.0.4</version>
|
<version>0.7.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- Naval Planner ZK Components -->
|
<!-- Naval Planner ZK Components -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
@ -216,30 +249,12 @@
|
||||||
<artifactId>navalplanner-gantt-zk</artifactId>
|
<artifactId>navalplanner-gantt-zk</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<!-- Naval Planner Business -->
|
||||||
|
<dependency>
|
||||||
<groupId>org.navalplanner</groupId>
|
<groupId>org.navalplanner</groupId>
|
||||||
<artifactId>navalplanner-business</artifactId>
|
<artifactId>navalplanner-business</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- BeanShell (required by ZK)-->
|
|
||||||
<dependency>
|
|
||||||
<groupId>bsh</groupId>
|
|
||||||
<artifactId>bsh</artifactId>
|
|
||||||
<version>2.0b4</version>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
<!-- Apache Commons Fileupload (required by ZK) -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>commons-fileupload</groupId>
|
|
||||||
<artifactId>commons-fileupload</artifactId>
|
|
||||||
<version>1.2.1</version>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>jgrapht</groupId>
|
|
||||||
<artifactId>jgrapht</artifactId>
|
|
||||||
<version>0.7.3</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue