vertigo-io/vertigo-core

[Dynamo] JpaDataStore Sql Error handling.

forhanp opened this issue · 0 comments

The actual JpaDataStorePlugin doesn't manage the Sql Error in a user friendly way for the developers.
Typically, you can't define resources to display accurate messages to the users. You have to test and not let the exception fly.

JpaDataStorePlugin doesn't use the standard way of Tasks that allow this mechanism.

We actually handle this with the following modification :

private void handle(final PersistenceException pse) {
        Logger.getLogger(getClass()).error("erreur sql ", pse);
        Throwable t = pse.getCause();
        // On ne traite que les violations de contraintes
        if (!(t instanceof ConstraintViolationException)) {
            throw pse;
        }
        final ConstraintViolationException cve = (ConstraintViolationException) t;
        // On récupère l'erreur SQL associé
        t = cve.getCause();
        if (!(t instanceof SQLException)) {
            throw pse;
        }
        final SQLException sqle = (SQLException) t;
        final SqlDataBase dataBase = dataBaseManager.getMainConnectionProvider().getDataBase();
        dataBase.getSqlExceptionHandler().handleSQLException(sqle, null);
    }

This is called in :

private void put(final String prefixServiceName, final DtObject dto, final boolean persist) {

        final EntityManager em = obtainEntityManager();
        final DtDefinition dtDefinition = DtObjectUtil.findDtDefinition(dto);
        final long start = System.currentTimeMillis();

        boolean executed = false;
        final String serviceName = prefixServiceName + dtDefinition.getName();
        dataBaseListener.onStart(serviceName);
        try {
            if (persist) { // si pas de PK exception
                // Si l'objet est en cours de création (pk null)
                // (l'objet n'est pas géré par jpa car les objets sont toujours en mode détaché :
                // sinon on ferait persist aussi si em.contains(dto)).
                em.persist(dto);
            } else {
                em.merge(dto);
            }
            em.flush();
            em.clear();
            executed = true;
        } catch (final PersistenceException pse) {
            // Il faut faire le même traitement que dans AbstractSqlExceptionHandler
            // sur la cause racine.
            handle(pse);
        } finally {
            dataBaseListener.onFinish(serviceName, executed, System.currentTimeMillis() - start, executed ? 1 : 0, null);
        }
    }

and in :

public void delete(final DtDefinition dtDefinition, final URI uri) {
        final EntityManager em = obtainEntityManager();
        final String serviceName = "Jpa:remove " + uri.getDefinition().getName();
        final long start = System.currentTimeMillis();
        boolean executed = false;
        dataBaseListener.onStart(serviceName);
        try {
            final Object dto = loadWithoutClear(uri);
            if (dto == null) {
                throw new VSystemException("Aucune ligne supprimée");
            }
            em.remove(dto);
            em.flush();
            em.clear();
            executed = true;
        } catch (final PersistenceException pse) {
            // Il faut faire le même traitement que dans AbstractSqlExceptionHandler
            // sur la cause racine.
            handle(pse);
        } finally {
            dataBaseListener.onFinish(serviceName, executed, System.currentTimeMillis() - start, executed ? 1 : 0, null);
        }
    }

Thank you to provide the best way to do it and implement it in the next release.