I’ve been developing an Application since 2015 March (moreover). From the beginning, what I wanted was using Hibernate and a DAO pattern for Data Access (I’m using PostgreSql database). This would be the architecture (don’t laugh at me, I drawed using paint :p):
Everything has been working, somehow, correctly. Now, we need to introduce Google Charts to our application. Google charts. To use common and plain javascript code, my solution has been creating a Custom Component with a Label, containing HTML code (div). Then executing a javascript function, which loads a google chart and renders it in the div. So, I developed a Restful WS to interact with the database. The architecture is what follows:
However, I’m facing some problems.
- When I execute the methods of the WS, the results are always identical (you’ll know afterwards why I say identical).
- When the page is loaded (the View), the results returned by the WS aren’t correct. This is a DAO method to fetch some values:
public HashMap<LocalDate, Integer> getCantidadDeRutasPorPlanes(LocalDate pInicio, LocalDate pFin){
System.out.println("getCantidadDeRutasPorPlanes() entre "
+ DateTimeFormatters.JavaDateTimeFormatter.formatDate(pInicio)
+ " y "
+ DateTimeFormatters.JavaDateTimeFormatter.formatDate(pFin));
HashMap<LocalDate, Integer> ret = new HashMap<LocalDate, Integer>();
for(LocalDate aux = pInicio;
aux.isBefore(pFin) || aux.isEqual(pFin);
aux = aux.plusDays(1)){
Integer value = getCantidadDeRutasPorPlan(aux);
ret.put(aux, value);
}
return ret;
}
private Integer getCantidadDeRutasPorPlan(LocalDate pFecha) {
try{
Query q = session
.createQuery("select size(p.lasRutas) from Plan p where day(p.laFecha)=:dia and month(p.laFecha)=:mes and year(p.laFecha)=:anyo");
q.setInteger("dia", pFecha.getDayOfMonth());
q.setInteger("mes", pFecha.getMonthValue());
q.setInteger("anyo", pFecha.getYear());
Integer cantidad = 0;
List lista = q.list();
if(lista != null){
if(!lista.isEmpty()){
for (Object obj : lista) {
if(obj != null){
Integer cant = (Integer) obj;
cantidad += cant;
}
}
}
}
System.out.println("getCantidadDeRutasPorPlan(): " + cantidad);
return cantidad;
}catch(HibernateException e){
logger.error("Error HibernateException en getCantidadDeRutasPorPlan(): " + e.getMessage());
System.err.println("Error HibernateException en getCantidadDeRutasPorPlan(): " + e.getMessage());
e.printStackTrace();
return -1;
}
}
As you can see, when an exception is caught the returned value is -1. So, when loading the page and drawing charts, several exceptions happen and pseudo-random data is loaded. E.g: 0,0,-1,-1,-1,0,0,-1,0,-1…
However, when calling manually (with SOAP UI) the WS method which executes the same DB method, the results are correct, e.g. 0,0,0,2,0,0,1,0,0,…
With regard to the web service i guess there is no problem. So, there are two possible reasons why this doesn’t work correctly:
- I’m using a trick to make google charts work on Vaadin. Perhaps I should integrate it with server-client side methodology of Vaadin as said
here
. I know JavaScript is executed on the client side. Vaadin, on the other hand, is server side. The
Web Service
is executed on the server,
using the same dao
. - Otherwise, as you can see in bold, the problem may be the following: vaadin application and the web service both share the same DAO class. I didn’t want to introduce code (at least the relevant code) regarding the DAO, but now I consider helpful so that anybody can comment out her/his impression.
- PtDao is the DAO class itself and follows
Singleton
pattern, where all the stuff related to Hibernate, HQL and session is located. - PtService is an interface. It contains every method of PtDao which is wanted to be usable.
- PtDaoService implements PtService and it contains the instance of PtDao as attribute. So, in every method (which is named equally as in PtDao) it’s called dao.theMethod(params);
Let’s see in action:
PtDao
public class PtDao {
/*
* Atributos
*/
private Logger logger = LoggerFactory.getLogger(PtDao.class);
private ConfiguracionNueva config;
private static PtDao myPtDao = null;
private Configuration cfg;
private SessionFactory factory;
private Transaction tx;
private static Session session;
private static ServiceRegistry serviceRegistry;
// Flota is a singleton which contains cars and drivers (two lists)
private Flota flota = Flota.getInstance();
/*
* Métodos
*/
private PtDao() {
try {
config = new ConfiguracionNueva();
config.leerConfiguracion();
//cfg = new Configuration().configure("hibernate.cfg.xml"); // configures settings from hibernate.cfg.xml
cfg = new Configuration();
//cfg.configure();
cfg.setProperty("hibernate.hbm2ddl.auto", "update");
cfg.setProperty("hibernate.transaction.auto_close_session", "false");
cfg.setProperty("hibernate.connection.autocommit", "false");
// Configuración PostgreSQL
cfg.setProperty("hibernate.connection.driver_class", "org.postgresql.Driver");
cfg.setProperty("hibernate.connection.url", "jdbc:postgresql://"
+ config.getIP_POSTGRESQL() + ":"
+ config.getPORT_POSTGRESQL() + "/"
+ config.getDATABASE_POSTGRESQL());
cfg.setProperty("hibernate.connection.username", config.getUSERNAME_POSTGRESQL());
cfg.setProperty("hibernate.connection.password", config.getPASSWORD_POSTGRESQL());
cfg.setProperty("dialect", "org.hibernate.dialect.PostgreSQLDialect");
// C3p0 connection pool
cfg.setProperty("connection.provider_class", "org.hibernate.connection.C3P0ConnectionProvider");
cfg.setProperty("c3p0.min_size", "3");
cfg.setProperty("c3p0.max_size", "10");
cfg.setProperty("c3p0.timeout", "1000");
cfg.setProperty("c3p0.idle_test_period", "2000");
cfg.setProperty("c3p0.preferredTestQuery", "select 1;");
cfg.setProperty("hibernate.connection.release_mode", "after_transaction");
cfg.setProperty("hibernate.show_sql", "false");
cfg.setProperty("hibernate.format_sql", "true");
cfg.setProperty("hibernate.generate_statistics", "true");
// Meter clases y ficheros HBM
cfg.addResource("com/ingartek/cavwebapp/model/LatLng.hbm.xml");
// more hibernate mappings
StandardServiceRegistryBuilder serviceRegistryBuilder = new StandardServiceRegistryBuilder();
// If you miss the below line then it will complain about a missing
// dialect setting
serviceRegistryBuilder.applySettings(cfg.getProperties());
serviceRegistry = serviceRegistryBuilder.build();
factory = cfg.buildSessionFactory(serviceRegistry);
this.openSession();
} catch (ConfigurationException e) {
System.err.println("Error ConfigurationException en PtDao(): " + e.getMessage() + ". Causa: " + e.getCause());
logger.error("Error ConfigurationException en PtDao(): " + e.getMessage() + ". Causa: " + e.getCause());
e.printStackTrace();
} catch (HibernateException e) {
System.err.println("Error HibernateException en PtDao(): " + e.getMessage() + ". Causa: " + e.getCause());
logger.error("Error HibernateException en PtDao(): " + e.getMessage() + ". Causa: " + e.getCause());
e.printStackTrace();
}
}
private void openSession() throws HibernateException {
session = factory.openSession();
}
private void closeSession() {
session.close();
}
private void beginTransaction() {
this.tx = null;
this.tx = session.beginTransaction();
}
private void commitTransaction() throws HibernateException {
this.tx.commit();
}
private void rollbackTransaction() throws HibernateException {
if (this.tx != null)
this.tx.rollback();
}
public static PtDao getPtDao() {
if (myPtDao == null) {
myPtDao = new PtDao();
}
return myPtDao;
}
// Login: simple login
public Administrador loginAdministrador(String pUsername, String pPassword)
throws IncorrectPasswordOrUserNotFoundException {
System.out.println("Intentando identificar a " + pUsername);
Query q = session
.createQuery("from Administrador as ad where ad.user=:username and ad.pass=:password");
q.setString("username", pUsername);
q.setString("password", pPassword);
@SuppressWarnings("unchecked")
Iterator<List<Administrador>> it = q.list().iterator();
if (!it.hasNext()) {
throw new IncorrectPasswordOrUserNotFoundException(pUsername);
} else {
Administrador admin = (Administrador) it.next();
return admin;
}
}
...
// Simple write method
public Vehiculo anadirVehiculo(String pMatricula, String pNombre,
Integer pAsientos) throws ExisteVehiculoException {
System.out.println("Creando nuevo vehículo");
if (!isMatriculaUsada(pMatricula)) {
Vehiculo unVehiculo = new Vehiculo(pMatricula, pNombre, pAsientos);
if (!flota.existeVehiculo(unVehiculo)) {
flota.anadirVehiculo(unVehiculo);
}
try {
beginTransaction();
session.save(unVehiculo);
commitTransaction();
return unVehiculo;
} catch (HibernateException e) {
System.err
.println("Error HibernateException en anadirVehiculo(): "
+ e.getMessage() + ". Causa: " + e.getCause());
e.printStackTrace();
return null;
}
} else {
rollbackTransaction();
throw new ExisteVehiculoException();
}
}
...
// One of the methods to draw Google Charts
public HashMap<LocalDate, Integer> getCantidadDeRutasPorPlanes(LocalDate pInicio, LocalDate pFin){
System.out.println("getCantidadDeRutasPorPlanes() entre "
+ DateTimeFormatters.JavaDateTimeFormatter.formatDate(pInicio)
+ " y "
+ DateTimeFormatters.JavaDateTimeFormatter.formatDate(pFin));
HashMap<LocalDate, Integer> ret = new HashMap<LocalDate, Integer>();
for(LocalDate aux = pInicio;
aux.isBefore(pFin) || aux.isEqual(pFin);
aux = aux.plusDays(1)){
Integer value = getCantidadDeRutasPorPlan(aux);
ret.put(aux, value);
}
return ret;
}
private Integer getCantidadDeRutasPorPlan(LocalDate pFecha) {
try{
Query q = session
.createQuery("select size(p.lasRutas) from Plan p where day(p.laFecha)=:dia and month(p.laFecha)=:mes and year(p.laFecha)=:anyo");
q.setInteger("dia", pFecha.getDayOfMonth());
q.setInteger("mes", pFecha.getMonthValue());
q.setInteger("anyo", pFecha.getYear());
Integer cantidad = 0;
List lista = q.list();
if(lista != null){
if(!lista.isEmpty()){
for (Object obj : lista) {
if(obj != null){
Integer cant = (Integer) obj;
cantidad += cant;
}
}
}
}
System.out.println("getCantidadDeRutasPorPlan(): " + cantidad);
return cantidad;
}catch(HibernateException e){
logger.error("Error HibernateException en getCantidadDeRutasPorPlan(): " + e.getMessage());
System.err.println("Error HibernateException en getCantidadDeRutasPorPlan(): " + e.getMessage());
e.printStackTrace();
return -1;
}
}
PtService
public interface PtService {
public Administrador loginAdministrador(String pUsername, String pPassword) throws IncorrectPasswordOrUserNotFoundException;
public Vehiculo anadirVehiculo(String pMatricula, String pNombre, Integer pAsientos) throws ExisteVehiculoException;
public HashMap<LocalDate, Integer> getCantidadDeRutasPorPlanes(LocalDate pInicio, LocalDate pFin);
}
PtDaoService
[code]
public class PtDaoService implements PtService {
/*
* Atributos
*/
private PtDao dao;
/*
* Métodos
*/
public PtDaoService(){
this.dao = PtDao.getPtDao();
}
@Override
public Administrador loginAdministrador(String pUsername, String pPassword)
throws IncorrectPasswordOrUserNotFoundException {
return dao.loginAdministrador(pUsername, pPassword);
}
@Override
public Vehiculo anadirVehiculo(String pMatricula, String pNombre,
Integer pAsientos) throws ExisteVehiculoException{
return dao.anadirVehiculo(pMatricula, pNombre, pAsientos);
}
@Override
public HashMap<LocalDate, Integer> getCantidadDeRutasPorPlanes(LocalDate pInicio, LocalDate pFin) {
return dao.getCantidadDeRutasPorPlanes(pInicio, pFin);
}
}
[/code]Do you see any trouble in here?
What do you think of my approach?
Thanks in advance…