diff --git a/docs-core/pom.xml b/docs-core/pom.xml index 3281d683..a168bfc7 100644 --- a/docs-core/pom.xml +++ b/docs-core/pom.xml @@ -173,6 +173,12 @@ com.github.jai-imageio jai-imageio-jpeg2000 + + + org.postgresql + postgresql + 42.2.2.jre7 + @@ -214,20 +220,6 @@ prod - - - - demo - - - - - src/demo/resources - true - - - - diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/AuthenticationTokenDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/AuthenticationTokenDao.java index 39e7d571..1f53d1c8 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/AuthenticationTokenDao.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/AuthenticationTokenDao.java @@ -86,7 +86,7 @@ public class AuthenticationTokenDao { */ public void updateLastConnectionDate(String id) { StringBuilder sb = new StringBuilder("update T_AUTHENTICATION_TOKEN ato "); - sb.append(" set ato.AUT_LASTCONNECTIONDATE_D = :currentDate "); + sb.append(" set AUT_LASTCONNECTIONDATE_D = :currentDate "); sb.append(" where ato.AUT_ID_C = :id"); EntityManager em = ThreadLocalContext.get().getEntityManager(); diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java index f853d531..15300a17 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/DocumentDao.java @@ -92,8 +92,8 @@ public class DocumentDao { EntityManager em = ThreadLocalContext.get().getEntityManager(); StringBuilder sb = new StringBuilder("select distinct d.DOC_ID_C, d.DOC_TITLE_C, d.DOC_DESCRIPTION_C, d.DOC_SUBJECT_C, d.DOC_IDENTIFIER_C, d.DOC_PUBLISHER_C, d.DOC_FORMAT_C, d.DOC_SOURCE_C, d.DOC_TYPE_C, d.DOC_COVERAGE_C, d.DOC_RIGHTS_C, d.DOC_CREATEDATE_D, d.DOC_UPDATEDATE_D, d.DOC_LANGUAGE_C, "); - sb.append(" (select count(s.SHA_ID_C) from T_SHARE s, T_ACL ac where ac.ACL_SOURCEID_C = d.DOC_ID_C and ac.ACL_TARGETID_C = s.SHA_ID_C and ac.ACL_DELETEDATE_D is null and s.SHA_DELETEDATE_D is null), "); - sb.append(" (select count(f.FIL_ID_C) from T_FILE f where f.FIL_DELETEDATE_D is null and f.FIL_IDDOC_C = d.DOC_ID_C), "); + sb.append(" (select count(s.SHA_ID_C) from T_SHARE s, T_ACL ac where ac.ACL_SOURCEID_C = d.DOC_ID_C and ac.ACL_TARGETID_C = s.SHA_ID_C and ac.ACL_DELETEDATE_D is null and s.SHA_DELETEDATE_D is null) shareCount, "); + sb.append(" (select count(f.FIL_ID_C) from T_FILE f where f.FIL_DELETEDATE_D is null and f.FIL_IDDOC_C = d.DOC_ID_C) fileCount, "); sb.append(" u.USE_USERNAME_C "); sb.append(" from T_DOCUMENT d "); sb.append(" join T_USER u on d.DOC_IDUSER_C = u.USE_ID_C "); diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/RouteDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/RouteDao.java index 59e35681..2be48840 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/RouteDao.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/RouteDao.java @@ -95,12 +95,12 @@ public class RouteDao { public void deleteRoute(String routeId) { EntityManager em = ThreadLocalContext.get().getEntityManager(); - em.createNativeQuery("update T_ROUTE_STEP rs set rs.RTP_DELETEDATE_D = :dateNow where rs.RTP_IDROUTE_C = :routeId and rs.RTP_DELETEDATE_D is null") + em.createNativeQuery("update T_ROUTE_STEP rs set RTP_DELETEDATE_D = :dateNow where rs.RTP_IDROUTE_C = :routeId and rs.RTP_DELETEDATE_D is null") .setParameter("routeId", routeId) .setParameter("dateNow", new Date()) .executeUpdate(); - em.createNativeQuery("update T_ROUTE r set r.RTE_DELETEDATE_D = :dateNow where r.RTE_ID_C = :routeId and r.RTE_DELETEDATE_D is null") + em.createNativeQuery("update T_ROUTE r set RTE_DELETEDATE_D = :dateNow where r.RTE_ID_C = :routeId and r.RTE_DELETEDATE_D is null") .setParameter("routeId", routeId) .setParameter("dateNow", new Date()) .executeUpdate(); diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/RouteStepDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/RouteStepDao.java index ebb01595..60112096 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/RouteStepDao.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/RouteStepDao.java @@ -141,7 +141,7 @@ public class RouteStepDao { */ public void endRouteStep(String id, RouteStepTransition transition, String comment, String validatorUserId) { StringBuilder sb = new StringBuilder("update T_ROUTE_STEP r "); - sb.append(" set r.RTP_ENDDATE_D = :endDate, r.RTP_TRANSITION_C = :transition, r.RTP_COMMENT_C = :comment, r.RTP_IDVALIDATORUSER_C = :validatorUserId "); + sb.append(" set RTP_ENDDATE_D = :endDate, RTP_TRANSITION_C = :transition, RTP_COMMENT_C = :comment, RTP_IDVALIDATORUSER_C = :validatorUserId "); sb.append(" where r.RTP_ID_C = :id"); EntityManager em = ThreadLocalContext.get().getEntityManager(); diff --git a/docs-core/src/main/java/com/sismics/util/jpa/DbOpenHelper.java b/docs-core/src/main/java/com/sismics/util/jpa/DbOpenHelper.java index fcc4f3f2..c16383d0 100644 --- a/docs-core/src/main/java/com/sismics/util/jpa/DbOpenHelper.java +++ b/docs-core/src/main/java/com/sismics/util/jpa/DbOpenHelper.java @@ -1,7 +1,19 @@ package com.sismics.util.jpa; -import java.io.File; -import java.io.FilenameFilter; +import com.google.common.base.Strings; +import com.google.common.io.CharStreams; +import com.sismics.docs.core.util.ConfigUtil; +import com.sismics.util.ResourceUtil; +import org.hibernate.HibernateException; +import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; +import org.hibernate.engine.jdbc.internal.FormatStyle; +import org.hibernate.engine.jdbc.internal.Formatter; +import org.hibernate.engine.jdbc.spi.JdbcServices; +import org.hibernate.engine.jdbc.spi.SqlStatementLogger; +import org.hibernate.service.ServiceRegistry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -15,22 +27,6 @@ import java.util.Collections; import java.util.List; import java.util.ResourceBundle; -import org.hibernate.HibernateException; -import org.hibernate.JDBCException; -import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; -import org.hibernate.engine.jdbc.internal.FormatStyle; -import org.hibernate.engine.jdbc.internal.Formatter; -import org.hibernate.engine.jdbc.spi.JdbcServices; -import org.hibernate.engine.jdbc.spi.SqlStatementLogger; -import org.hibernate.service.ServiceRegistry; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Strings; -import com.google.common.io.CharStreams; -import com.sismics.docs.core.util.ConfigUtil; -import com.sismics.util.ResourceUtil; - /** * A helper to update the database incrementally. * @@ -48,8 +44,6 @@ abstract class DbOpenHelper { private Formatter formatter; - private boolean haltOnError; - private Statement stmt; DbOpenHelper(ServiceRegistry serviceRegistry) throws HibernateException { @@ -85,12 +79,13 @@ abstract class DbOpenHelper { oldVersion = Integer.parseInt(oldVersionStr); } } catch (Exception e) { - if (e.getMessage().contains("not found")) { + if (DialectUtil.isObjectNotFound(e.getMessage())) { log.info("Unable to get database version: Table T_CONFIG not found"); } else { log.error("Unable to get database version", e); } } finally { + connection.commit(); if (stmt != null) { stmt.close(); stmt = null; @@ -133,15 +128,12 @@ abstract class DbOpenHelper { * Execute all upgrade scripts in ascending order for a given version. * * @param version Version number - * @throws Exception + * @throws Exception e */ void executeAllScript(final int version) throws Exception { - List fileNameList = ResourceUtil.list(getClass(), "/db/update/", new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - String versionString = String.format("%03d", version); - return name.matches("dbupdate-" + versionString + "-\\d+\\.sql"); - } + List fileNameList = ResourceUtil.list(getClass(), "/db/update/", (dir, name) -> { + String versionString = String.format("%03d", version); + return name.matches("dbupdate-" + versionString + "-\\d+\\.sql"); }); Collections.sort(fileNameList); @@ -158,33 +150,28 @@ abstract class DbOpenHelper { * Execute a SQL script. All statements must be one line only. * * @param inputScript Script to execute - * @throws IOException - * @throws SQLException + * @throws IOException e */ - void executeScript(InputStream inputScript) throws IOException, SQLException { + private void executeScript(InputStream inputScript) throws IOException { List lines = CharStreams.readLines(new InputStreamReader(inputScript)); for (String sql : lines) { if (Strings.isNullOrEmpty(sql) || sql.startsWith("--")) { continue; } - - String formatted = formatter.format(sql); - try { - log.debug(formatted); - stmt.executeUpdate(formatted); - } catch (SQLException e) { - if (haltOnError) { - if (stmt != null) { - stmt.close(); - stmt = null; + + String transformed = DialectUtil.transform(sql); + if (transformed != null) { + String formatted = formatter.format(transformed); + try { + log.debug(formatted); + stmt.executeUpdate(formatted); + } catch (SQLException e) { + exceptions.add(e); + if (log.isErrorEnabled()) { + log.error("Error executing SQL statement: {}", sql); + log.error(e.getMessage()); } - throw new JDBCException("Error during script execution", e); - } - exceptions.add(e); - if (log.isErrorEnabled()) { - log.error("Error executing SQL statement: {}", sql); - log.error(e.getMessage()); } } } @@ -203,10 +190,6 @@ abstract class DbOpenHelper { return exceptions; } - public void setHaltOnError(boolean haltOnError) { - this.haltOnError = haltOnError; - } - /** * Format the output SQL statements. * diff --git a/docs-core/src/main/java/com/sismics/util/jpa/DialectUtil.java b/docs-core/src/main/java/com/sismics/util/jpa/DialectUtil.java new file mode 100644 index 00000000..a4f8b8f1 --- /dev/null +++ b/docs-core/src/main/java/com/sismics/util/jpa/DialectUtil.java @@ -0,0 +1,55 @@ +package com.sismics.util.jpa; + +/** + * Dialect utilities. + * + * @author jtremeaux + */ +public class DialectUtil { + /** + * Checks if the error from the drivers relates to an object not found. + * + * @param message Error message + * @return Object not found + */ + public static boolean isObjectNotFound(String message) { + return EMF.isDriverH2() && message.contains("object not found") || + EMF.isDriverPostgresql() && message.contains("does not exist"); + } + + + /** + * Transform SQL dialect to current dialect. + * + * @param sql SQL to transform + * @return Transformed SQL + */ + public static String transform(String sql) { + if (sql.startsWith("!PGSQL!")) { + return EMF.isDriverH2() ? null : sql.substring(7); + } + if (sql.startsWith("!H2!")) { + return EMF.isDriverPostgresql() ? null : sql.substring(4); + } + + if (EMF.isDriverPostgresql()) { + sql = transformToPostgresql(sql); + } + return sql; + } + + /** + * Transform SQL from HSQLDB dialect to current dialect. + * + * @param sql SQL to transform + * @return Transformed SQL + */ + public static String transformToPostgresql(String sql) { + sql = sql.replaceAll("(cached|memory) table", "table"); + sql = sql.replaceAll("datetime", "timestamp"); + sql = sql.replaceAll("longvarchar", "text"); + sql = sql.replaceAll("bit not null", "bool not null"); + sql = sql.replaceAll("bit default 0", "bool default false"); + return sql; + } +} diff --git a/docs-core/src/main/java/com/sismics/util/jpa/EMF.java b/docs-core/src/main/java/com/sismics/util/jpa/EMF.java index c0073ce3..e6736e47 100644 --- a/docs-core/src/main/java/com/sismics/util/jpa/EMF.java +++ b/docs-core/src/main/java/com/sismics/util/jpa/EMF.java @@ -1,16 +1,6 @@ package com.sismics.util.jpa; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - -import javax.persistence.EntityManagerFactory; -import javax.persistence.Persistence; - +import com.sismics.docs.core.util.DirectoryUtil; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Environment; import org.hibernate.internal.util.config.ConfigurationHelper; @@ -18,7 +8,15 @@ import org.hibernate.service.ServiceRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.sismics.docs.core.util.DirectoryUtil; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; /** * Entity manager factory. @@ -28,18 +26,19 @@ import com.sismics.docs.core.util.DirectoryUtil; public final class EMF { private static final Logger log = LoggerFactory.getLogger(EMF.class); + private static Map properties; + private static EntityManagerFactory emfInstance; static { try { - Map properties = getEntityManagerProperties(); + properties = getEntityManagerProperties(); Environment.verifyProperties(properties); ConfigurationHelper.resolvePlaceHolders(properties); ServiceRegistry reg = new StandardServiceRegistryBuilder().applySettings(properties).build(); DbOpenHelper openHelper = new DbOpenHelper(reg) { - @Override public void onCreate() throws Exception { executeAllScript(0); @@ -78,15 +77,27 @@ public final class EMF { } // Use environment parameters + String databaseUrl = System.getenv("DATABASE_URL"); + String databaseUsername = System.getenv("DATABASE_USER"); + String databasePassword = System.getenv("DATABASE_PASSWORD"); + log.info("Configuring EntityManager from environment parameters"); - Map props = new HashMap(); - props.put("hibernate.connection.driver_class", "org.h2.Driver"); + Map props = new HashMap<>(); Path dbDirectory = DirectoryUtil.getDbDirectory(); String dbFile = dbDirectory.resolve("docs").toAbsolutePath().toString(); - props.put("hibernate.connection.url", "jdbc:h2:file:" + dbFile + ";CACHE_SIZE=65536"); - props.put("hibernate.connection.username", "sa"); + if (databaseUrl == null) { + props.put("hibernate.connection.driver_class", "org.h2.Driver"); + props.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect"); + props.put("hibernate.connection.url", "jdbc:h2:file:" + dbFile + ";CACHE_SIZE=65536"); + props.put("hibernate.connection.username", "sa"); + } else { + props.put("hibernate.connection.driver_class", "org.postgresql.Driver"); + props.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQL94Dialect"); + props.put("hibernate.connection.url", databaseUrl); + props.put("hibernate.connection.username", databaseUsername); + props.put("hibernate.connection.password", databasePassword); + } props.put("hibernate.hbm2ddl.auto", ""); - props.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect"); props.put("hibernate.show_sql", "false"); props.put("hibernate.format_sql", "false"); props.put("hibernate.max_fetch_depth", "5"); @@ -112,4 +123,18 @@ public final class EMF { public static EntityManagerFactory get() { return emfInstance; } + + public static boolean isDriverH2() { + String driver = getDriver(); + return driver.contains("h2"); + } + + public static boolean isDriverPostgresql() { + String driver = getDriver(); + return driver.contains("postgresql"); + } + + public static String getDriver() { + return (String) properties.get("hibernate.connection.driver_class"); + } } \ No newline at end of file diff --git a/docs-core/src/main/resources/db/update/dbupdate-000-0.sql b/docs-core/src/main/resources/db/update/dbupdate-000-0.sql index b8fa4a2a..a28cb0d8 100644 --- a/docs-core/src/main/resources/db/update/dbupdate-000-0.sql +++ b/docs-core/src/main/resources/db/update/dbupdate-000-0.sql @@ -1,4 +1,4 @@ -SET IGNORECASE TRUE; +!H2!SET IGNORECASE TRUE; create memory table T_AUTHENTICATION_TOKEN ( AUT_ID_C varchar(36) not null, AUT_IDUSER_C varchar(36) not null, AUT_LONGLASTED_B bit not null, AUT_CREATIONDATE_D datetime not null, AUT_LASTCONNECTIONDATE_D datetime, AUT_IP_C varchar(45), AUT_UA_C varchar(1000), primary key (AUT_ID_C) ); create memory table T_BASE_FUNCTION ( BAF_ID_C varchar(20) not null, primary key (BAF_ID_C) ); create cached table T_FILE ( FIL_ID_C varchar(36) not null, FIL_IDDOC_C varchar(36), FIL_IDUSER_C varchar(36) not null, FIL_MIMETYPE_C varchar(100) not null, FIL_CREATEDATE_D datetime, FIL_DELETEDATE_D datetime, FIL_ORDER_N int, FIL_CONTENT_C longvarchar, primary key (FIL_ID_C) ); diff --git a/docs-core/src/main/resources/db/update/dbupdate-012-0.sql b/docs-core/src/main/resources/db/update/dbupdate-012-0.sql index 4cc23461..52f2fdc3 100644 --- a/docs-core/src/main/resources/db/update/dbupdate-012-0.sql +++ b/docs-core/src/main/resources/db/update/dbupdate-012-0.sql @@ -1,2 +1,5 @@ -alter table T_DOCUMENT alter column DOC_LANGUAGE_C varchar(7) default 'eng' not null; +!H2!alter table T_DOCUMENT alter column DOC_LANGUAGE_C varchar(7) default 'eng' not null; +!PGSQL!alter table T_DOCUMENT alter column DOC_LANGUAGE_C type varchar(7); +!PGSQL!alter table T_DOCUMENT alter column DOC_LANGUAGE_C set default 'eng'; +!PGSQL!alter table T_DOCUMENT alter column DOC_LANGUAGE_C set not null; update T_CONFIG set CFG_VALUE_C = '12' where CFG_ID_C = 'DB_VERSION'; diff --git a/docs-core/src/main/resources/db/update/dbupdate-018-0.sql b/docs-core/src/main/resources/db/update/dbupdate-018-0.sql index bb11c357..d63b8476 100644 --- a/docs-core/src/main/resources/db/update/dbupdate-018-0.sql +++ b/docs-core/src/main/resources/db/update/dbupdate-018-0.sql @@ -1,5 +1,7 @@ alter table T_DOCUMENT add column DOC_UPDATEDATE_D datetime; update T_DOCUMENT set DOC_UPDATEDATE_D = DOC_CREATEDATE_D; -alter table T_DOCUMENT alter column DOC_UPDATEDATE_D datetime not null; +!H2!alter table T_DOCUMENT alter column DOC_UPDATEDATE_D datetime not null; +!PGSQL!alter table T_DOCUMENT alter column DOC_UPDATEDATE_D type timestamp; +!PGSQL!alter table T_DOCUMENT alter column DOC_UPDATEDATE_D set not null; alter table T_ROUTE_STEP add column RTP_TRANSITIONS_C varchar(2000); update T_CONFIG set CFG_VALUE_C = '18' where CFG_ID_C = 'DB_VERSION';