diff --git a/bonita-engine-spring-boot-starter/build.gradle b/bonita-engine-spring-boot-starter/build.gradle index 0ab3c9d4db5..3640e903d9e 100644 --- a/bonita-engine-spring-boot-starter/build.gradle +++ b/bonita-engine-spring-boot-starter/build.gradle @@ -12,7 +12,6 @@ dependencies { api(libs.springBootStarter) { exclude(module: 'snakeyaml') } - api(libs.snakeyaml) implementation(project(":bonita-engine-standalone")) implementation(project(":bpm:bonita-server")) @@ -20,7 +19,6 @@ dependencies { annotationProcessor(libs.springBootConfigurationProcessor) testImplementation(libs.springBootTest) - testImplementation(libs.junit4) testImplementation(libs.assertj) } diff --git a/bonita-engine-standalone/build.gradle b/bonita-engine-standalone/build.gradle index 43dc6df225d..55abd444abf 100644 --- a/bonita-engine-standalone/build.gradle +++ b/bonita-engine-standalone/build.gradle @@ -22,11 +22,12 @@ dependencies { compileOnly libs.lombok testImplementation libs.assertj - testImplementation libs.junit4 testImplementation libs.systemRules - testImplementation libs.postgresql - testImplementation libs.mysql - testImplementation libs.h2 + + // These 3 drivers are used for some specific tests: + testImplementation(libs.postgresql) + testImplementation(libs.mysql) + testImplementation(libs.h2) } diff --git a/bonita-engine-standalone/src/main/java/org/bonitasoft/engine/BonitaEngine.java b/bonita-engine-standalone/src/main/java/org/bonitasoft/engine/BonitaEngine.java index b9233db3862..2e5e5ff6b97 100644 --- a/bonita-engine-standalone/src/main/java/org/bonitasoft/engine/BonitaEngine.java +++ b/bonita-engine-standalone/src/main/java/org/bonitasoft/engine/BonitaEngine.java @@ -53,8 +53,8 @@ public class BonitaEngine { private BasicDataSource notManagedBizDataSource; private javax.transaction.UserTransaction userTransaction; private javax.transaction.TransactionManager arjunaTransactionManager; - public static final String BONITA_BDM_DB_VENDOR = "sysprop.bonita.bdm.db.vendor"; - public static final String BONITA_DB_VENDOR = "sysprop.bonita.db.vendor"; + public static final String BONITA_BDM_DB_VENDOR = PlatformSetup.BONITA_BDM_DB_VENDOR_PROPERTY; + public static final String BONITA_DB_VENDOR = PlatformSetup.BONITA_DB_VENDOR_PROPERTY; public void initializeEnvironment() throws Exception { if (!initialized) { @@ -115,7 +115,7 @@ private void initializeJNDI() throws NamingException { public void start() throws Exception { initializeEnvironment(); - PlatformSetup platformSetup = PlatformSetupAccessor.getPlatformSetup(); + PlatformSetup platformSetup = getPlatformSetup(); platformSetup.init(); PlatformSession platformSession = loginOnPlatform(); @@ -126,6 +126,10 @@ public void start() throws Exception { logoutFromPlatform(platformSession); } + protected PlatformSetup getPlatformSetup() throws NamingException { + return PlatformSetupAccessor.getInstance().getPlatformSetup(); + } + private void logoutFromPlatform(PlatformSession platformSession) throws PlatformLogoutException, SessionNotFoundException, BonitaHomeNotSetException, ServerAPIException, UnknownAPITypeException { diff --git a/bonita-engine/build.gradle b/bonita-engine/build.gradle index d0bd90f181e..f85dd329344 100644 --- a/bonita-engine/build.gradle +++ b/bonita-engine/build.gradle @@ -32,7 +32,7 @@ dependencyManagement { } dependency(libs.hibernateJCache.get() as String) dependency(libs.jcache.get() as String) - dependency libs.javaxPersistenceApi.get() as String + dependency(libs.javaxPersistenceApi.get() as String) dependency libs.commonsIO.get() as String dependency libs.commonsFileUpload.get() as String dependency(libs.commonsBeanUtils.get() as String) { @@ -51,19 +51,14 @@ dependencyManagement { dependency libs.tomcatDbcp.get() as String dependency libs.narayanaJta.get() as String dependency libs.jakartaActivation.get() as String - dependency libs.snakeyaml.get() as String dependency(libs.quartz.get() as String) dependency(libs.eclipseCompiler.get() as String) dependency(libs.javaxAnnotations.get() as String) - dependencySet(group: "io.micrometer", version: libs.versions.micrometerVersion.get()) { - entry "micrometer-core" - entry "micrometer-registry-jmx" - entry "micrometer-registry-prometheus" - } - dependencySet(group: 'com.hazelcast', version: libs.versions.hazelcastVersion.get()) { - entry 'hazelcast' - entry 'hazelcast-spring' - } + dependency(libs.micrometerCore.get() as String) + dependency(libs.micrometerRegistryJmx.get() as String) + dependency(libs.micrometerRegistryPrometheus.get() as String) + dependency(libs.hazelcast.get() as String) + dependency(libs.hazelcastSpring.get() as String) // declared here because it is used by web-extension and by distrib dependency(libs.jakartaServletApi.get() as String) // To be removed only when client projects (rest api extension) have all moved their deps to jakarta diff --git a/bonita-integration-tests/benchmarks/build.gradle b/bonita-integration-tests/benchmarks/build.gradle index 9bff078646b..3a1542c5858 100644 --- a/bonita-integration-tests/benchmarks/build.gradle +++ b/bonita-integration-tests/benchmarks/build.gradle @@ -3,14 +3,10 @@ plugins { } dependencies { - api libs.junit4 api libs.assertj api libs.mockitoCore api project(':bonita-integration-tests:bonita-integration-tests-client') api project(':bpm:bonita-server') - runtimeOnly libs.mysql - runtimeOnly libs.msSqlServer - runtimeOnly libs.postgresql testRuntimeOnly libs.logback } diff --git a/bonita-integration-tests/bonita-integration-tests-client/build.gradle b/bonita-integration-tests/bonita-integration-tests-client/build.gradle index 368a05a71ee..47b1c49d3eb 100644 --- a/bonita-integration-tests/bonita-integration-tests-client/build.gradle +++ b/bonita-integration-tests/bonita-integration-tests-client/build.gradle @@ -5,7 +5,6 @@ plugins { } dependencies { api project(':bonita-test-api') - api libs.junit4 api libs.commonsIO api project(':bpm:bonita-common') api project(':bpm:bonita-client') diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/main/java/org/bonitasoft/engine/CommonAPIIT.java b/bonita-integration-tests/bonita-integration-tests-client/src/main/java/org/bonitasoft/engine/CommonAPIIT.java index cb0b23b3240..af2866c2475 100644 --- a/bonita-integration-tests/bonita-integration-tests-client/src/main/java/org/bonitasoft/engine/CommonAPIIT.java +++ b/bonita-integration-tests/bonita-integration-tests-client/src/main/java/org/bonitasoft/engine/CommonAPIIT.java @@ -60,10 +60,6 @@ public void clean() throws Exception { } }; - /** - * @return warning list of unclean elements - * @throws BonitaException - */ private void clean() throws BonitaException { loginOnDefaultTenantWithDefaultTechnicalUser(); cleanCommands(); diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/main/java/org/bonitasoft/engine/business/application/TestWithLivingApplication.java b/bonita-integration-tests/bonita-integration-tests-client/src/main/java/org/bonitasoft/engine/business/application/TestWithLivingApplication.java index 8c28a39fdb2..6c31599214c 100644 --- a/bonita-integration-tests/bonita-integration-tests-client/src/main/java/org/bonitasoft/engine/business/application/TestWithLivingApplication.java +++ b/bonita-integration-tests/bonita-integration-tests-client/src/main/java/org/bonitasoft/engine/business/application/TestWithLivingApplication.java @@ -54,12 +54,10 @@ public void setUp() throws Exception { @After public void tearDown() throws Exception { - final SearchResult searchResult = getLivingApplicationAPI() - .searchApplications(new SearchOptionsBuilder(0, 1000).done()); - for (final Application app : searchResult.getResult()) { - if (app.isEditable()) { - getLivingApplicationAPI().deleteApplication(app.getId()); - } + final SearchResult searchResult = getLivingApplicationAPI() + .searchIApplications(new SearchOptionsBuilder(0, 1000).done()); + for (final IApplication app : searchResult.getResult()) { + getLivingApplicationAPI().deleteApplication(app.getId()); } logoutThenlogin(); deleteUser(user); diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/main/java/org/bonitasoft/engine/business/data/ClassloaderRefresher.java b/bonita-integration-tests/bonita-integration-tests-client/src/main/java/org/bonitasoft/engine/business/data/ClassloaderRefresher.java index 97ca18be325..f8bb0757987 100644 --- a/bonita-integration-tests/bonita-integration-tests-client/src/main/java/org/bonitasoft/engine/business/data/ClassloaderRefresher.java +++ b/bonita-integration-tests/bonita-integration-tests-client/src/main/java/org/bonitasoft/engine/business/data/ClassloaderRefresher.java @@ -15,7 +15,6 @@ import java.io.File; import java.io.IOException; -import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; @@ -42,9 +41,9 @@ public class ClassloaderRefresher { */ public ClassLoader loadClientModelInClassloader(final byte[] clientZipContent, final ClassLoader contextClassLoader, final String modelClass, - final File fsFolderToPutJars) throws IOException, MalformedURLException { + final File fsFolderToPutJars) throws IOException { final Map ressources = IOUtils.unzip(clientZipContent); - final List urls = new ArrayList(); + final List urls = new ArrayList<>(); for (final Entry e : ressources.entrySet()) { final File file = new File(fsFolderToPutJars, e.getKey()); if (file.getName().endsWith(".jar")) { @@ -58,7 +57,7 @@ public ClassLoader loadClientModelInClassloader(final byte[] clientZipContent, f } if (file.getName().contains("dao")) { try { - contextClassLoader.loadClass(modelClass + "DAO"); + contextClassLoader.loadClass(modelClass + "DAOImpl"); } catch (final ClassNotFoundException e1) { FileUtils.writeByteArrayToFile(file, e.getValue()); urls.add(file.toURI().toURL()); @@ -76,7 +75,7 @@ public ClassLoader loadClientModelInClassloader(final byte[] clientZipContent, f } ClassLoader classLoaderWithBDM = contextClassLoader; if (!urls.isEmpty()) { - classLoaderWithBDM = new URLClassLoader(urls.toArray(new URL[urls.size()]), contextClassLoader); + classLoaderWithBDM = new URLClassLoader(urls.toArray(new URL[0]), contextClassLoader); } return classLoaderWithBDM; } diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/Application_Data.xml b/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/Application_Data.xml deleted file mode 100644 index 8493e0d6fa7..00000000000 --- a/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/Application_Data.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - Loan request - This is were we ask a loan. - /icon.jpg - - - - - - Loan request - - - Ask a loan - - - - - Empty menu - - - - - Leave request application - This is were we manage leave requests - - - - - - Leave management - - - Vacation balance - - - - - - \ No newline at end of file diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/Organization_Data.xml b/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/Organization_Data.xml deleted file mode 100644 index 578a283c31f..00000000000 --- a/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/Organization_Data.xml +++ /dev/null @@ -1,664 +0,0 @@ - - - - - - LcTkpvvquKf4KO+prsfXrQ== - Anthony - Nichols - Mr - Account manager - true - - -
Renwick Drive
- 70 - Philadelphia - United States - anthony.nichols@acme.com - 484-302-0222 - 484-302-5222 - PA - 19108 -
- - daniela.angelo -
- - LcTkpvvquKf4KO+prsfXrQ== - April - Sanchez - Mrs - Compensation specialist - true - - -
Renwick Drive
- 70 - Philadelphia - United States - april.sanchez@acme.com - 484-302-0158 - 484-302-5158 - PA - 19108 -
- - helen.kelly -
- - LcTkpvvquKf4KO+prsfXrQ== - Daniela - Angelo - Mrs - Vice President of Sales - true - - -
Renwick Drive
- 70 - Philadelphia - United States - daniela.angelo@acme.com - 484-302-0222 - 484-302-5222 - PA - 19108 -
- - william.jobs -
- - LcTkpvvquKf4KO+prsfXrQ== - Favio - Rivera - Mr - Vice President of Marketing - true - - -
Renwick Drive
- 70 - Philadelphia - United States - favio.riviera@acme.com - 484-302-0582 - 484-302-5582 - PA - 19108 -
- - william.jobs -
- - LcTkpvvquKf4KO+prsfXrQ== - Giovanna - Almeida - Mrs - Account manager - true - - -
Renwick Drive
- 70 - Philadelphia - United States - giovanna.almeida@acme.com - 484-302-0350 - 484-302-5350 - PA - 19108 -
- - daniela.angelo -
- - LcTkpvvquKf4KO+prsfXrQ== - Helen - Kelly - Mrs - Human resource manager - true - - -
Renwick Drive
- 70 - Philadelphia - United States - helen.kelly@acme.com - 484-302-0158 - 484-302-5158 - PA - 19108 -
- - william.jobs -
- - LcTkpvvquKf4KO+prsfXrQ== - Isabel - Bleasdale - Mrs - Product marketing manager - true - - -
Renwick Drive
- 70 - Philadelphia - United States - isabel.bleasdale@acme.com - 484-302-0582 - 484-302-5582 - PA - 19108 -
- - favio.riviera -
- - LcTkpvvquKf4KO+prsfXrQ== - Jan - Fisher - Mr - Infrastucture specialist - true - - -
Renwick Drive
- 70 - Philadelphia - United States - jan.fisher@acme.com - 484-302-0582 - 484-302-5582 - PA - 19108 -
- - favio.riviera -
- - LcTkpvvquKf4KO+prsfXrQ== - Joseph - Hovell - Mr - Engineer - true - - -
Renwick Drive
- 70 - Philadelphia - United States - joseph.hovell@acme.com - 484-302-0222 - 484-302-5222 - PA - 19108 -
- - michael.morrison -
- - LcTkpvvquKf4KO+prsfXrQ== - Marc - Marseau - Mr - Engineer - true - - -
Renwick Drive
- 70 - Philadelphia - United States - marc.marseau@acme.com - 484-302-0222 - 484-302-5222 - PA - 19108 -
- - michael.morrison -
- - LcTkpvvquKf4KO+prsfXrQ== - Mauro - Zetticci - Mr - Consultant - true - - -
Renwick Drive
- 70 - Philadelphia - United States - mauro.zetticci@acme.com - 484-302-0222 - 484-302-5222 - PA - 19108 -
- - michael.morrison -
- - LcTkpvvquKf4KO+prsfXrQ== - Michael - Morrison - Mr - Chief Technical Officer - true - - -
Renwick Drive
- 70 - Philadelphia - United States - michael.morrison@acme.com - 484-302-0222 - 484-302-5222 - PA - 19108 -
- - william.jobs -
- - LcTkpvvquKf4KO+prsfXrQ== - Misa - Kumagai - Mrs - Account manager - true - - -
Renwick Drive
- 70 - Philadelphia - United States - misa.kumagai@acme.com - 484-302-0350 - 484-302-5350 - PA - 19108 -
- - daniela.angelo -
- - LcTkpvvquKf4KO+prsfXrQ== - Norio - Yamazaki - Mr - Account manager - true - - -
Renwick Drive
- 70 - Philadelphia - United States - norio.yamazaki@acme.com - 484-302-0350 - 484-302-5350 - PA - 19108 -
- - daniela.angelo -
- - LcTkpvvquKf4KO+prsfXrQ== - Patrick - Gardenier - Mr - Financial controller - true - - -
Renwick Drive
- 70 - Philadelphia - United States - patrick.gardenier@acme.com - 484-302-0582 - 484-302-5582 - PA - 19108 -
- - zachary.williamson -
- - LcTkpvvquKf4KO+prsfXrQ== - Studio - Studio technical user for preview - true - - - - - - LcTkpvvquKf4KO+prsfXrQ== - Thomas - Wallis - Mr - Consultant - true - - -
Renwick Drive
- 70 - Philadelphia - United States - thomas.wallis@acme.com - 484-302-0222 - 484-302-5222 - PA - 19108 -
- - michael.morrison -
- - LcTkpvvquKf4KO+prsfXrQ== - Thorsten - Hartmann - Mr - Financial planning manager - true - - -
Renwick Drive
- 70 - Philadelphia - United States - thorsten.hartmann@acme.com - 484-302-0582 - 484-302-5582 - PA - 19108 -
- - zachary.williamson -
- - LcTkpvvquKf4KO+prsfXrQ== - Virgine - Jomphe - Mrs - Accountant - true - - -
Renwick Drive
- 70 - Philadelphia - United States - virginie.jomphe@acme.com - 484-302-0582 - 484-302-5582 - PA - 19108 -
- - zachary.williamson -
- - LcTkpvvquKf4KO+prsfXrQ== - Walter - Bates - Mr - Human resources benefits - true - - -
Renwick Drive
- 70 - Philadelphia - United States - walter.bates@acme.com - 484-302-0158 - 484-302-5158 - PA - 19108 -
- - helen.kelly -
- - LcTkpvvquKf4KO+prsfXrQ== - William - Jobs - Mr - Chief Executive Officer - true - - -
Renwick Drive
- 70 - Philadelphia - United States - william.jobs@acme.com - 484-302-0710 - 484-302-5710 - PA - 19108 -
- -
- - LcTkpvvquKf4KO+prsfXrQ== - Zachary - Williamson - Mr - Chief Financial Officer - true - - -
Renwick Drive
- 70 - Philadelphia - United States - zachary.williamson@acme.com - 484-302-0158 - 484-302-5158 - PA - 19108 -
- - william.jobs -
-
- - - Member - - - - - - Acme - This group represents the acme department of the ACME organization - - - Finance - This group represents the finance department of the ACME organization - - - Human Resources - This group represents the human resources department of the ACME organization - - - Infrastructure - This group represents the infrastructure department of the ACME organization - - - Marketing - This group represents the marketing department of the ACME organization - - - Production - This group represents the production department of the ACME organization - - - Sales - This group represents the sales department of the ACME organization - - - Research & Development - This group represents the research & development department of the ACME organization - - - Services - This group represents the services department of the ACME organization - - - Asia - This group represents the asia department of the ACME organization - - - Europe - This group represents the europe department of the ACME organization - - - Latin America - This group represents the latin america department of the ACME organization - - - North America - This group represents the north america department of the ACME organization - - - - - william.jobs - member - acme - - - - april.sanchez - member - hr - /acme - - - helen.kelly - member - hr - /acme - - - walter.bates - member - hr - /acme - - - zachary.williamson - member - finance - /acme - - - patrick.gardenier - member - finance - /acme - - - virginie.jomphe - member - finance - /acme - - - thorsten.hartmann - member - finance - /acme - - - jan.fisher - member - it - /acme - - - isabel.bleasdale - member - marketing - /acme - - - favio.riviera - member - marketing - /acme - - - michael.morrison - member - production - /acme - - - marc.marseau - member - rd - /acme/production - - - joseph.hovell - member - rd - /acme/production - - - mauro.zetticci - member - services - /acme/production - - - thomas.wallis - member - services - /acme/production - - - daniela.angelo - member - europe - /acme/sales - - - anthony.nichols - member - north_america - /acme/sales - - - misa.kumagai - member - asia - /acme/sales - - - norio.yamazaki - member - asia - /acme/sales - - - giovanna.almeida - member - latin_america - /acme/sales - - -
diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/bdm.zip b/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/bdm.zip deleted file mode 100644 index 0f4eef73bf4..00000000000 Binary files a/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/bdm.zip and /dev/null differ diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/custom-theme.zip b/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/custom-theme.zip deleted file mode 100644 index 1d2b78dbc27..00000000000 Binary files a/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/custom-theme.zip and /dev/null differ diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/layout.zip b/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/layout.zip deleted file mode 100644 index 9673ae87ce9..00000000000 Binary files a/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/layout.zip and /dev/null differ diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/myProcess--1.0.bar b/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/myProcess--1.0.bar deleted file mode 100644 index 35f5e550810..00000000000 Binary files a/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/myProcess--1.0.bar and /dev/null differ diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/page1.zip b/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/page1.zip deleted file mode 100644 index ed8095facd5..00000000000 Binary files a/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/page1.zip and /dev/null differ diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/resourceNameRestAPI-1.0.0.zip b/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/resourceNameRestAPI-1.0.0.zip deleted file mode 100644 index 13a8fe6e58a..00000000000 Binary files a/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/complete_app/resourceNameRestAPI-1.0.0.zip and /dev/null differ diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/org/bonitasoft/engine/business/application/applicationWithUnavailableInfo.xml b/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/org/bonitasoft/engine/business/application/applicationWithUnavailableInfo.xml index 84b252f3c37..520747074b0 100644 --- a/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/org/bonitasoft/engine/business/application/applicationWithUnavailableInfo.xml +++ b/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/org/bonitasoft/engine/business/application/applicationWithUnavailableInfo.xml @@ -8,7 +8,7 @@ ~ or BonitaSoft US, 51 Federal Street, Suite 305, San Francisco, CA 94107 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> - + My HR dashboard This is the HR dashboard. diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/org/bonitasoft/engine/business/application/applications.xml b/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/org/bonitasoft/engine/business/application/applications.xml index d7de48a9d32..e1daf9b4aeb 100644 --- a/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/org/bonitasoft/engine/business/application/applications.xml +++ b/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/org/bonitasoft/engine/business/application/applications.xml @@ -13,7 +13,7 @@ ~ Floor, Boston, MA 02110-1301, USA. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> - + My HR dashboard This is the HR dashboard. diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/activity/HumanTasksIT.java b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/activity/HumanTasksIT.java index 88be4073403..77711d43323 100644 --- a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/activity/HumanTasksIT.java +++ b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/activity/HumanTasksIT.java @@ -54,7 +54,7 @@ public class HumanTasksIT extends TestWithUser { - final static int INTIALIZING_STATE_ID = 32; + final static int INITIALIZING_STATE_ID = 32; @Test public void cannotGetHumanTaskInstances() throws Exception { @@ -433,7 +433,7 @@ public void setState() throws Exception { HumanTaskInstance step1 = waitForUserTaskAndGetIt(processInstance, "step1"); final long activityInstanceId = step1.getId(); - getProcessAPI().setActivityStateById(activityInstanceId, INTIALIZING_STATE_ID); + getProcessAPI().setActivityStateById(activityInstanceId, INITIALIZING_STATE_ID); step1 = getProcessAPI().getHumanTaskInstance(activityInstanceId); assertEquals(ActivityStates.INITIALIZING_STATE, step1.getState()); @@ -472,7 +472,7 @@ public void setStateShouldTerminateATaskWithBoundaryEvent() throws Exception { assertThat(eventInstances.size()).isEqualTo(1); final long activityInstanceId = step1.getId(); - getProcessAPI().setActivityStateById(activityInstanceId, INTIALIZING_STATE_ID); + getProcessAPI().setActivityStateById(activityInstanceId, INITIALIZING_STATE_ID); step1 = getProcessAPI().getHumanTaskInstance(activityInstanceId); assertEquals(ActivityStates.INITIALIZING_STATE, step1.getState()); diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/application/ApplicationIT.java b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/application/ApplicationIT.java index 70c38268ec7..47fb49d8392 100644 --- a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/application/ApplicationIT.java +++ b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/application/ApplicationIT.java @@ -14,115 +14,26 @@ package org.bonitasoft.engine.application; import static org.assertj.core.api.Assertions.assertThat; -import static org.bonitasoft.engine.io.FileAndContentUtils.file; -import static org.bonitasoft.engine.io.FileAndContentUtils.zip; -import static org.bonitasoft.engine.io.FileOperations.resource; -import java.io.IOException; import java.util.List; import org.apache.commons.io.IOUtils; import org.bonitasoft.engine.TestWithTechnicalUser; import org.bonitasoft.engine.api.ImportStatus; import org.bonitasoft.engine.api.permission.APICallContext; -import org.bonitasoft.engine.api.result.ExecutionResult; -import org.bonitasoft.engine.bpm.process.ActivationState; -import org.bonitasoft.engine.bpm.process.ConfigurationState; -import org.bonitasoft.engine.bpm.process.ProcessDeploymentInfo; -import org.bonitasoft.engine.business.application.Application; -import org.bonitasoft.engine.business.application.ApplicationCreator; -import org.bonitasoft.engine.business.application.ApplicationImportPolicy; -import org.bonitasoft.engine.business.application.ApplicationSearchDescriptor; +import org.bonitasoft.engine.business.application.*; import org.bonitasoft.engine.identity.User; -import org.bonitasoft.engine.page.ContentType; -import org.bonitasoft.engine.page.PageSearchDescriptor; import org.bonitasoft.engine.profile.Profile; import org.bonitasoft.engine.search.Order; import org.bonitasoft.engine.search.SearchOptionsBuilder; import org.bonitasoft.engine.search.SearchResult; -import org.junit.Ignore; import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * @author Emmanuel Duchastenier */ public class ApplicationIT extends TestWithTechnicalUser { - private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationIT.class); - - @Test - @Ignore("API not released") - public void should_deploy_all_artifacts_from_application() throws Exception { - // given: - final byte[] completeApplicationZip = createCompleteApplication(); - - // when: - ExecutionResult result = null; - //getApiClient().getApplicationAPI().deployApplication(completeApplicationZip); - - // then: - assertThat(result.hasErrors()).isFalse(); - - result.getAllStatus().forEach(s -> LOGGER.info(s.toString())); - - assertThat(getPageAPI() - .searchPages(new SearchOptionsBuilder(0, 10) - .filter(PageSearchDescriptor.PROVIDED, false) - .and() - .leftParenthesis() - .filter(PageSearchDescriptor.CONTENT_TYPE, ContentType.PAGE) - .or() - .filter(PageSearchDescriptor.CONTENT_TYPE, ContentType.FORM) - .rightParenthesis() - .sort(PageSearchDescriptor.NAME, Order.ASC).done()) - .getResult()).extracting("name").containsExactly("custompage_loanindex", "custompage_newForm"); - - assertThat(getPageAPI() - .searchPages(new SearchOptionsBuilder(0, 10) - .filter(PageSearchDescriptor.PROVIDED, false) - .filter(PageSearchDescriptor.CONTENT_TYPE, ContentType.THEME) - .done()) - .getResult()).extracting("name").containsExactly("custompage_customtheme"); - - assertThat(getPageAPI() - .searchPages(new SearchOptionsBuilder(0, 10) - .filter(PageSearchDescriptor.PROVIDED, false) - .filter(PageSearchDescriptor.CONTENT_TYPE, ContentType.LAYOUT) - .done()) - .getResult()).extracting("name").containsExactly("custompage_customlayout"); - - assertThat(getPageAPI() - .searchPages(new SearchOptionsBuilder(0, 10) - .filter(PageSearchDescriptor.PROVIDED, false) - .filter(PageSearchDescriptor.CONTENT_TYPE, ContentType.API_EXTENSION) - .done()) - .getResult()).extracting("name").containsExactly("custompage_resourceNameRestAPI"); - - final long processDefinitionId = getProcessAPI().getProcessDefinitionId("myProcess", "1.0"); - assertThat(processDefinitionId).isGreaterThan(0L); - - final ProcessDeploymentInfo deploymentInfo = getProcessAPI().getProcessDeploymentInfo(processDefinitionId); - assertThat(deploymentInfo.getConfigurationState()).isEqualTo(ConfigurationState.UNRESOLVED); - assertThat(deploymentInfo.getActivationState()).isEqualTo(ActivationState.DISABLED); - - List insertedApplicationList = getLivingApplicationAPI() - .searchApplications(getApplicationSearchOptionsOrderByToken(0, 10).done()).getResult(); - assertThat(insertedApplicationList).hasSize(2); - assertThat(insertedApplicationList.get(0).getDisplayName()).isEqualToIgnoringCase("Loan request"); // token LoanApp - assertThat(insertedApplicationList.get(1).getDisplayName()).isEqualToIgnoringCase("Leave request application"); // token Tahiti - - // We must be able to redeploy the same application: - // result = getApiClient().getApplicationAPI().deployApplication(completeApplicationZip); - - // then: - assertThat(result.hasErrors()).isFalse(); - - result.getAllStatus().forEach(s -> LOGGER.info(s.toString())); - - } - @Test public void searchApplications_can_filter_by_user_id() throws Exception { //given @@ -154,39 +65,44 @@ public void searchApplications_can_filter_by_user_id() throws Exception { final SearchOptionsBuilder builderUser1 = new SearchOptionsBuilder(0, 10); builderUser1.filter(ApplicationSearchDescriptor.USER_ID, user1.getId()); builderUser1.sort(ApplicationSearchDescriptor.DISPLAY_NAME, Order.ASC); - final SearchResult applicationsUser1 = getApplicationAPI().searchApplications(builderUser1.done()); + final SearchResult applicationsUser1 = getApplicationAPI() + .searchIApplications(builderUser1.done()); assertThat(applicationsUser1).isNotNull(); assertThat(applicationsUser1.getResult()).contains(engineering, hr).doesNotContain(marketing); final SearchOptionsBuilder builderUser2 = new SearchOptionsBuilder(0, 10); builderUser2.filter(ApplicationSearchDescriptor.USER_ID, user2.getId()); builderUser2.sort(ApplicationSearchDescriptor.DISPLAY_NAME, Order.ASC); - final SearchResult applicationsUser2 = getApplicationAPI().searchApplications(builderUser2.done()); + final SearchResult applicationsUser2 = getApplicationAPI() + .searchIApplications(builderUser2.done()); assertThat(applicationsUser2).isNotNull(); assertThat(applicationsUser2.getResult()).contains(marketing).doesNotContain(engineering, hr); final SearchOptionsBuilder builderUser3 = new SearchOptionsBuilder(0, 10); builderUser3.filter(ApplicationSearchDescriptor.USER_ID, user3.getId()); builderUser3.sort(ApplicationSearchDescriptor.DISPLAY_NAME, Order.ASC); - final SearchResult applicationsUser3 = getApplicationAPI().searchApplications(builderUser3.done()); + final SearchResult applicationsUser3 = getApplicationAPI() + .searchIApplications(builderUser3.done()); assertThat(applicationsUser3).isNotNull(); assertThat(applicationsUser3.getResult()).contains(engineering, hr, marketing); final SearchOptionsBuilder builderUser4 = new SearchOptionsBuilder(0, 10); builderUser4.filter(ApplicationSearchDescriptor.USER_ID, user4.getId()); builderUser4.sort(ApplicationSearchDescriptor.DISPLAY_NAME, Order.ASC); - final SearchResult applicationsUser4 = getApplicationAPI().searchApplications(builderUser4.done()); + final SearchResult applicationsUser4 = getApplicationAPI() + .searchIApplications(builderUser4.done()); assertThat(applicationsUser4.getResult()).isEmpty(); // Let's check SAM (=tenant admin), has access to applications mapped to "_BONITA_INTERNAL_PROFILE_SUPER_ADMIN": final List importStatus = getLivingApplicationAPI().importApplications( IOUtils.toByteArray(ApplicationIT.class.getResourceAsStream("superAdminApp.xml")), ApplicationImportPolicy.FAIL_ON_DUPLICATES); - assertThat(importStatus).allMatch(status -> status.getStatus().equals(ImportStatus.Status.ADDED)); + assertThat(importStatus).isNotEmpty().allMatch(status -> status.getStatus().equals(ImportStatus.Status.ADDED)); final SearchOptionsBuilder soSystemAdmin = new SearchOptionsBuilder(0, 10); soSystemAdmin.filter(ApplicationSearchDescriptor.USER_ID, "-1"); // -1 is userId for SAM (= tenant admin) - final SearchResult samApplications = getApplicationAPI().searchApplications(soSystemAdmin.done()); - final List applications = samApplications.getResult(); + final SearchResult samApplications = getApplicationAPI() + .searchIApplications(soSystemAdmin.done()); + final List applications = samApplications.getResult(); assertThat(applications).hasSize(1); assertThat(applications.get(0).getToken()).isEqualTo("superAdminAppBonita"); @@ -218,32 +134,23 @@ public void searchApplications_can_filter_by_user_id_and_process_display_name() final SearchOptionsBuilder builderUser1 = new SearchOptionsBuilder(0, 10); builderUser1.filter(ApplicationSearchDescriptor.USER_ID, user1.getId()); builderUser1.filter(ApplicationSearchDescriptor.DISPLAY_NAME, "Engineering dashboard"); - final SearchResult applicationsUser1 = getApplicationAPI().searchApplications(builderUser1.done()); + final SearchResult applicationsUser1 = getApplicationAPI() + .searchIApplications(builderUser1.done()); assertThat(applicationsUser1).isNotNull(); assertThat(applicationsUser1.getCount()).isEqualTo(1); assertThat(applicationsUser1.getResult()).containsExactly(engineering); } - private byte[] createCompleteApplication() throws IOException { - return zip( - file("applications/Application_Data.xml", resource("/complete_app/Application_Data.xml")), - file("pages/page1.zip", resource("/complete_app/page1.zip")), - file("processes/myProcess--1.0.bar", resource("/complete_app/myProcess--1.0.bar")), - file("extensions/resourceNameRestAPI-1.0.0.zip", - resource("/complete_app/resourceNameRestAPI-1.0.0.zip")), - file("layouts/layout.zip", resource("/complete_app/layout.zip")), - file("themes/custom-theme.zip", resource("/complete_app/custom-theme.zip"))); - } - - private SearchOptionsBuilder getApplicationSearchOptionsOrderByToken(final int startIndex, final int maxResults) { - return new SearchOptionsBuilder(startIndex, maxResults).sort(ApplicationSearchDescriptor.TOKEN, Order.ASC); - } - @Test public void should_access_identity_api_using_default_application_permissions() throws Exception { - + // Given + var testPage = getPageAPI().createPage("page-to-test-permissions.zip", + IOUtils.toByteArray(ApplicationIT.class.getResourceAsStream("/page-to-test-permissions.zip"))); + var testApp = getApplicationAPI().importApplications( + IOUtils.toByteArray(ApplicationIT.class.getResourceAsStream("/application-to-test-permissions.xml")), + ApplicationImportPolicy.FAIL_ON_DUPLICATES); // Uses page-to-test-permissions.zip - // Uses application-to-test-permissions.zip + // Uses application-to-test-permissions.xml User user = createUser("baptiste", "bpm"); loginOnDefaultTenantWith("baptiste", "bpm"); diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/business/application/LivingApplicationIT.java b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/business/application/LivingApplicationIT.java index ff889f3cc3d..b703d2fb8df 100644 --- a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/business/application/LivingApplicationIT.java +++ b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/business/application/LivingApplicationIT.java @@ -63,6 +63,35 @@ public void createApplication_returns_application_based_on_ApplicationCreator_in getLivingApplicationAPI().deleteApplication(application.getId()); } + @Test + public void createApplicationLink_returns_application_based_on_ApplicationCreator_information() throws Exception { + //given + final Profile profile = getProfileUser(); + final ApplicationLinkCreator creator = new ApplicationLinkCreator("My-Application", + "My application display name", + "1.0"); + creator.setDescription("This is my application"); + creator.setIconPath("/icon.jpg"); + creator.setProfileId(profile.getId()); + + //when + final ApplicationLink application = getLivingApplicationAPI().createApplicationLink(creator); + + //then + assertThat(application).isNotNull(); + assertThat(application.getToken()).isEqualTo("My-Application"); + assertThat(application.getDisplayName()).isEqualTo("My application display name"); + assertThat(application.getVersion()).isEqualTo("1.0"); + assertThat(application.getId()).isGreaterThan(0); + assertThat(application.getDescription()).isEqualTo("This is my application"); + assertThat(application.getIconPath()).isEqualTo("/icon.jpg"); + assertThat(application.getCreatedBy()).isEqualTo(getUser().getId()); + assertThat(application.getUpdatedBy()).isEqualTo(getUser().getId()); + assertThat(application.getProfileId()).isEqualTo(profile.getId()); + + getLivingApplicationAPI().deleteApplication(application.getId()); + } + @Test public void createApplication_without_profile_should_have_null_profileId() throws Exception { //given @@ -112,6 +141,42 @@ public void updateApplication_should_return_application_up_to_date() throws Exce getLivingApplicationAPI().deleteApplication(application.getId()); } + @Test + public void updateApplicationLink_should_return_application_up_to_date() throws Exception { + //given + final Profile profile = getProfileUser(); + final ApplicationLinkCreator creator = new ApplicationLinkCreator("My-Application", + "My application display name", + "1.0"); + final ApplicationLink application = getLivingApplicationAPI().createApplicationLink(creator); + + final ApplicationLinkUpdater updater = new ApplicationLinkUpdater(); + updater.setToken("My-updated-app"); + updater.setDisplayName("Updated display name"); + updater.setVersion("1.1"); + updater.setDescription("Up description"); + updater.setIconPath("/newIcon.jpg"); + updater.setProfileId(profile.getId()); + updater.setState(ApplicationState.ACTIVATED.name()); + + //when + final ApplicationLink updatedApplication = getLivingApplicationAPI().updateApplicationLink(application.getId(), + updater); + + //then + assertThat(updatedApplication).isNotNull(); + assertThat(updatedApplication.getToken()).isEqualTo("My-updated-app"); + assertThat(updatedApplication.getDisplayName()).isEqualTo("Updated display name"); + assertThat(updatedApplication.getVersion()).isEqualTo("1.1"); + assertThat(updatedApplication.getDescription()).isEqualTo("Up description"); + assertThat(updatedApplication.getIconPath()).isEqualTo("/newIcon.jpg"); + assertThat(updatedApplication.getProfileId()).isEqualTo(profile.getId()); + assertThat(updatedApplication.getState()).isEqualTo(ApplicationState.ACTIVATED.name()); + assertThat(updatedApplication).isEqualTo(getLivingApplicationAPI().getIApplication(application.getId())); + + getLivingApplicationAPI().deleteApplication(application.getId()); + } + @Test public void getApplication_returns_application_with_the_given_id() throws Exception { //given @@ -121,7 +186,7 @@ public void getApplication_returns_application_with_the_given_id() throws Except assertThat(createdApp).isNotNull(); //when - final Application retrievedApp = getLivingApplicationAPI().getApplication(createdApp.getId()); + final IApplication retrievedApp = getLivingApplicationAPI().getIApplication(createdApp.getId()); //then assertThat(retrievedApp).isEqualTo(createdApp); @@ -136,7 +201,7 @@ public void getApplicationByToken_returns_application_with_the_given_token() thr assertThat(createdApp).isNotNull(); //when - final Application retrievedApp = getLivingApplicationAPI().getApplicationByToken(createdApp.getToken()); + final IApplication retrievedApp = getLivingApplicationAPI().getIApplicationByToken(createdApp.getToken()); //then assertThat(retrievedApp).isEqualTo(createdApp); @@ -177,8 +242,8 @@ public void searchApplications_without_filter_return_all_elements_based_on_pagin final Application marketing = getLivingApplicationAPI().createApplication(marketingCreator); //when - final SearchResult firstPage = getLivingApplicationAPI() - .searchApplications(buildSearchOptions("AAA", 0, 2)); + final SearchResult firstPage = getLivingApplicationAPI() + .searchIApplications(buildSearchOptions("AAA", 0, 2)); //then assertThat(firstPage).isNotNull(); @@ -186,8 +251,8 @@ public void searchApplications_without_filter_return_all_elements_based_on_pagin assertThat(firstPage.getResult()).containsExactly(engineering, hr); //when - final SearchResult secondPage = getLivingApplicationAPI() - .searchApplications(buildSearchOptions("AAA", 2, 2)); + final SearchResult secondPage = getLivingApplicationAPI() + .searchIApplications(buildSearchOptions("AAA", 2, 2)); //then assertThat(secondPage).isNotNull(); @@ -212,7 +277,7 @@ public void searchApplications_can_filter_on_name() throws Exception { final SearchOptionsBuilder builder = getAppSearchBuilderOrderByToken(0, 10); builder.filter(ApplicationSearchDescriptor.TOKEN, "Engineering-dashboard"); - final SearchResult applications = getLivingApplicationAPI().searchApplications(builder.done()); + final SearchResult applications = getLivingApplicationAPI().searchIApplications(builder.done()); assertThat(applications).isNotNull(); assertThat(applications.getCount()).isEqualTo(1); assertThat(applications.getResult()).containsExactly(engineering); @@ -235,7 +300,7 @@ public void searchApplications_can_filter_on_display_name() throws Exception { final SearchOptionsBuilder builder = getAppSearchBuilderOrderByToken(0, 10); builder.filter(ApplicationSearchDescriptor.DISPLAY_NAME, "HR dashboard"); - final SearchResult applications = getLivingApplicationAPI().searchApplications(builder.done()); + final SearchResult applications = getLivingApplicationAPI().searchIApplications(builder.done()); assertThat(applications).isNotNull(); assertThat(applications.getCount()).isEqualTo(1); assertThat(applications.getResult()).containsExactly(hr); @@ -258,7 +323,7 @@ public void searchApplications_can_filter_on_version() throws Exception { final SearchOptionsBuilder builder = getAppSearchBuilderOrderByToken(0, 10); builder.filter(ApplicationSearchDescriptor.VERSION, "2.0"); - final SearchResult applications = getLivingApplicationAPI().searchApplications(builder.done()); + final SearchResult applications = getLivingApplicationAPI().searchIApplications(builder.done()); assertThat(applications).isNotNull(); assertThat(applications.getCount()).isEqualTo(2); assertThat(applications.getResult()).containsExactly(hr, marketing); @@ -270,7 +335,7 @@ public void searchApplications_can_filter_on_profileId() throws Exception { //given final Profile profile = getProfileUser(); final SearchOptionsBuilder builder = getAppSearchBuilderOrderByToken(0, 10); - long initialCount = getLivingApplicationAPI().searchApplications(builder.done()).getCount(); + long initialCount = getLivingApplicationAPI().searchIApplications(builder.done()).getCount(); builder.filter(ApplicationSearchDescriptor.PROFILE_ID, profile.getId()); final ApplicationCreator hrCreator = new ApplicationCreator("HR-dashboard", "HR dash board", "1.0"); final ApplicationCreator engineeringCreator = new ApplicationCreator("Engineering-dashboard", @@ -285,7 +350,7 @@ public void searchApplications_can_filter_on_profileId() throws Exception { //when - final SearchResult applications = getLivingApplicationAPI().searchApplications(builder.done()); + final SearchResult applications = getLivingApplicationAPI().searchIApplications(builder.done()); assertThat(applications).isNotNull(); assertThat(applications.getCount()).isEqualTo(initialCount + 1); assertThat(applications.getResult()).contains(engineering); @@ -311,7 +376,7 @@ public void searchApplications_can_use_search_term() throws Exception { final SearchOptionsBuilder builder = getAppSearchBuilderOrderByToken(0, 10); builder.searchTerm("My"); - final SearchResult applications = getLivingApplicationAPI().searchApplications(builder.done()); + final SearchResult applications = getLivingApplicationAPI().searchIApplications(builder.done()); assertThat(applications).isNotNull(); assertThat(applications.getCount()).isEqualTo(2); assertThat(applications.getResult()).containsExactly(hr, marketing); diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/business/application/LivingApplicationImportExportIT.java b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/business/application/LivingApplicationImportExportIT.java index 9a9ac643c78..d59fa8a8ef0 100644 --- a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/business/application/LivingApplicationImportExportIT.java +++ b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/business/application/LivingApplicationImportExportIT.java @@ -92,12 +92,12 @@ public void exportApplications_should_return_the_byte_content_of_xml_file_contai } @Test - public void importApplications_should_create_all_applications_contained_by_xml_file_and_return_status_ok_() + public void importApplications_should_create_all_applications_contained_by_xml_file_and_return_status_ok() throws Exception { //given final Profile profile = getProfileUser(); long initialCount = getLivingApplicationAPI() - .searchApplications(buildSearchOptions(0, 10)).getCount(); + .searchIApplications(buildSearchOptions(0, 10)).getCount(); // create page necessary to import application hr (real page name is defined in zip/page.properties): final Page myPage = getPageAPI().createPage("not_used", @@ -117,15 +117,16 @@ public void importApplications_should_create_all_applications_contained_by_xml_f assertIsAddOkStatus(importStatus.get(0), "HR-dashboard"); assertIsAddOkStatus(importStatus.get(1), "My"); - // check applications ware created - final SearchResult searchResult = getLivingApplicationAPI() - .searchApplications(buildSearchOptions(0, 10)); + // check applications were created + final SearchResult searchResult = getLivingApplicationAPI() + .searchIApplications(buildSearchOptions(0, 10)); assertThat(searchResult.getCount()).isEqualTo(initialCount + 2); - Application hrApp = searchResult.getResult().stream().filter(a -> a.getToken().contains("HR")).findFirst() - .get(); + Application hrApp = (Application) searchResult.getResult().stream().filter(a -> a.getToken().contains("HR")) + .findFirst().orElseThrow(); assertIsHRApplication(profile, defaultLayout, defaultTheme, hrApp); assertIsMarketingApplication( - searchResult.getResult().stream().filter(a -> a.getToken().contains("My")).findFirst().get()); + (Application) searchResult.getResult().stream().filter(a -> a.getToken().contains("My")) + .findFirst().orElseThrow()); //check pages were created SearchOptionsBuilder builder = getAppSearchBuilderOrderById(0, 10); @@ -152,17 +153,16 @@ public void importApplications_should_create_all_applications_contained_by_xml_f getLivingApplicationAPI().deleteApplication(hrApp.getId()); getPageAPI().deletePage(myPage.getId()); - } @Test public void importApplications_should_create_applications_contained_by_xml_file_and_return_error_if_there_is_unavailable_info() throws Exception { long initialCount = getLivingApplicationAPI() - .searchApplications(buildSearchOptions(0, 10)).getCount(); + .searchIApplications(buildSearchOptions(0, 10)).getCount(); //given final byte[] applicationsByteArray = IOUtils.toByteArray(LivingApplicationIT.class - .getResourceAsStream("applicationWithUnavailableInfo.xml")); + .getResourceAsStream("/org/bonitasoft/engine/business/application/applicationWithUnavailableInfo.xml")); // create page necessary to import application hr (real page name is defined in zip/page.properties): final Page myPage = getPageAPI().createPage("not_used", @@ -183,12 +183,13 @@ public void importApplications_should_create_applications_contained_by_xml_file_ assertThat(importStatus.get(0).getErrors()).containsExactly(profileError, customPageError, appPageError1, appPageError2); - // check applications ware created - final SearchResult searchResult = getLivingApplicationAPI() - .searchApplications(buildSearchOptions(0, 10)); + // check applications were created + final SearchResult searchResult = getLivingApplicationAPI() + .searchIApplications(buildSearchOptions(0, 10)); assertThat(searchResult.getCount()).isEqualTo(initialCount + 1); - final Application app1 = searchResult.getResult().stream().filter(a -> a.getToken().contains("HR")).findFirst() - .get(); + final Application app1 = (Application) searchResult.getResult().stream() + .filter(a -> a.getToken().contains("HR")) + .findFirst().orElseThrow(); assertThat(app1.getToken()).isEqualTo("HR-dashboard"); assertThat(app1.getVersion()).isEqualTo("2.0"); assertThat(app1.getDisplayName()).isEqualTo("My HR dashboard"); @@ -213,22 +214,21 @@ public void importApplications_should_create_applications_contained_by_xml_file_ .searchApplicationMenus(builder.done()); assertThat(menuSearchResult.getCount()).isEqualTo(3); assertThat(menuSearchResult.getResult().get(0).getDisplayName()).isEqualTo("HR follow-up"); - assertThat(menuSearchResult.getResult().get(0).getIndex()).isEqualTo(2); + assertThat(menuSearchResult.getResult().get(0).getIndex()).isEqualTo(1); assertThat(menuSearchResult.getResult().get(1).getDisplayName()).isEqualTo("Daily HR follow-up"); assertThat(menuSearchResult.getResult().get(1).getIndex()).isEqualTo(1); assertThat(menuSearchResult.getResult().get(2).getDisplayName()).isEqualTo("Empty menu"); - assertThat(menuSearchResult.getResult().get(1).getIndex()).isEqualTo(1); + assertThat(menuSearchResult.getResult().get(2).getIndex()).isEqualTo(2); getLivingApplicationAPI().deleteApplication(app1.getId()); getPageAPI().deletePage(myPage.getId()); - } @Test public void export_after_import_should_return_the_same_xml_file() throws Exception { //given long initialCount = getLivingApplicationAPI() - .searchApplications(buildSearchOptions(0, 10)).getCount(); + .searchIApplications(buildSearchOptions(0, 10)).getCount(); // create page necessary to import application hr (real page name is defined in zip/page.properties): final Page myPage = getPageAPI().createPage("not_used", IOUtils.toByteArray(LivingApplicationIT.class.getResourceAsStream("dummy-bizapp-page.zip"))); @@ -237,15 +237,17 @@ public void export_after_import_should_return_the_same_xml_file() throws Excepti .getResourceAsStream("applications.xml")); getLivingApplicationAPI().importApplications(importedByteArray, ApplicationImportPolicy.FAIL_ON_DUPLICATES); - final SearchResult searchResult = getLivingApplicationAPI() - .searchApplications(buildSearchOptions(0, 10)); + final SearchResult searchResult = getLivingApplicationAPI() + .searchIApplications(buildSearchOptions(0, 10)); assertThat(searchResult.getCount()).isEqualTo(initialCount + 2); //when - Application hrApplication = searchResult.getResult().stream().filter(a -> a.getToken().contains("HR")) - .findFirst().get(); + Application hrApplication = (Application) searchResult.getResult().stream() + .filter(a -> a.getToken().contains("HR")) + .findFirst().orElseThrow(); byte[] exportedByteArray = getLivingApplicationAPI().exportApplications(hrApplication.getId(), - searchResult.getResult().stream().filter(a -> a.getToken().contains("My")).findFirst().get().getId()); + searchResult.getResult().stream().filter(a -> a.getToken().contains("My")).findFirst().orElseThrow() + .getId()); //then final String xmlPrettyFormatExpected = XmlStringPrettyFormatter.xmlPrettyFormat(new String(importedByteArray)); @@ -254,7 +256,6 @@ public void export_after_import_should_return_the_same_xml_file() throws Excepti getLivingApplicationAPI().deleteApplication(hrApplication.getId()); getPageAPI().deletePage(myPage.getId()); - } } diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/business/application/LivingApplicationMenuIT.java b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/business/application/LivingApplicationMenuIT.java index a675bfa9ac7..9fdd183a2da 100644 --- a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/business/application/LivingApplicationMenuIT.java +++ b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/business/application/LivingApplicationMenuIT.java @@ -63,9 +63,9 @@ public void createApplicationMenu_ApplicationPage_should_return_applicationMenu_ assertThat(createdAppMenu.getDisplayName()).isEqualTo("Main"); assertThat(createdAppMenu.getApplicationId()).isEqualTo(application.getId()); assertThat(createdAppMenu.getApplicationPageId()).isNull(); - assertThat(createdAppMenu.getIndex()).isGreaterThan(1); + assertThat(createdAppMenu.getIndex()).isEqualTo(1); assertThat(createdAppMenu.getParentId()).isNull(); - assertThat(createdAppMenu.getId()).isGreaterThan(0); + assertThat(createdAppMenu.getId()).isPositive(); //when //create a second menu @@ -166,7 +166,7 @@ public void updateApplicationMenu_should_update_application_menu_based_on_update // updated: assertThat(updatedChildMenu.getApplicationPageId()).isNull(); assertThat(updatedChildMenu.getParentId()).isNull(); - assertThat(updatedChildMenu.getIndex()).isEqualTo(3); //because parent changed + assertThat(updatedChildMenu.getIndex()).isEqualTo(2); //because parent changed //not changed: assertThat(updatedChildMenu.getDisplayName()).isEqualTo("Updated child"); assertThat(updatedChildMenu.getApplicationId()).isEqualTo(application.getId()); diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/business/application/LivingApplicationPageIT.java b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/business/application/LivingApplicationPageIT.java index 1ac8e7652f3..82b7bfef666 100644 --- a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/business/application/LivingApplicationPageIT.java +++ b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/business/application/LivingApplicationPageIT.java @@ -64,7 +64,7 @@ public void setApplicationHomePage_should_update_the_application_homePage() thro getLivingApplicationAPI().setApplicationHomePage(application.getId(), appPage.getId()); //then - final Application upToDateApp = getLivingApplicationAPI().getApplication(application.getId()); + final Application upToDateApp = (Application) getLivingApplicationAPI().getApplication(application.getId()); assertThat(upToDateApp.getHomePageId()).isEqualTo(appPage.getId()); getLivingApplicationAPI().deleteApplication(application.getId()); @@ -368,10 +368,10 @@ public void getAllAccessiblePageForAProfile() throws Exception { //then assertThat(allPagesForProfile1).containsExactlyInAnyOrder("custompage_themeBonita", "custompage_layoutBonita", - "custompage_page1", "custompage_page2", "custompage_page3", "custompage_pageToTestPermissions"); + "custompage_page1", "custompage_page2", "custompage_page3"); assertThat(getLivingApplicationAPI().getAllPagesForProfile(profile1.getName())).containsExactlyInAnyOrder( "custompage_themeBonita", "custompage_layoutBonita", "custompage_page1", "custompage_page2", - "custompage_page3", "custompage_pageToTestPermissions"); + "custompage_page3"); assertThat(allPagesForProfile2).containsExactlyInAnyOrder("custompage_themeBonita", "custompage_layoutBonita", "custompage_page4"); assertThat(getLivingApplicationAPI().getAllPagesForProfile(profile2.getName())) diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/business/data/BDMUpdateIT.java b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/business/data/BDMUpdateIT.java index 1ea58b879fd..2f322186b6b 100644 --- a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/business/data/BDMUpdateIT.java +++ b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/business/data/BDMUpdateIT.java @@ -32,17 +32,15 @@ import org.bonitasoft.engine.tenant.TenantResource; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.xml.sax.SAXException; /** - * Those tests fail because after installing the second BDM version, Hibernate is not aware of + * Those tests fail on MySQL and SQLServer because after installing the second BDM version, Hibernate is not aware of * previous FK_ that stay in database, so it does not drop them, and then the 'drop table' fails on test cleanup. * Those cases should be handled when we support more "BDM update" scenarios, leveraging Hibernate poor level of * support on HBM2DDL. */ -@Ignore("FIXME: Not working on mysql and sql server") public class BDMUpdateIT extends CommonAPIIT { public static final String DOT = "."; diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/identity/UserIT.java b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/identity/UserIT.java index aa9738ee2e5..2f944216900 100644 --- a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/identity/UserIT.java +++ b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/identity/UserIT.java @@ -27,7 +27,13 @@ import org.bonitasoft.engine.api.PlatformAPI; import org.bonitasoft.engine.api.PlatformAPIAccessor; import org.bonitasoft.engine.api.TenantAPIAccessor; -import org.bonitasoft.engine.exception.*; +import org.bonitasoft.engine.exception.AlreadyExistsException; +import org.bonitasoft.engine.exception.BonitaException; +import org.bonitasoft.engine.exception.CreationException; +import org.bonitasoft.engine.exception.DeletionException; +import org.bonitasoft.engine.exception.NotFoundException; +import org.bonitasoft.engine.exception.SearchException; +import org.bonitasoft.engine.exception.UpdateException; import org.bonitasoft.engine.identity.impl.IconImpl; import org.bonitasoft.engine.platform.LoginException; import org.bonitasoft.engine.platform.NodeNotStartedException; @@ -35,7 +41,6 @@ import org.bonitasoft.engine.search.SearchOptionsBuilder; import org.bonitasoft.engine.search.SearchResult; import org.bonitasoft.engine.session.PlatformSession; -import org.junit.Assume; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -733,8 +738,6 @@ public void searchUserSortedById() throws BonitaException { */ @Test public void should_search_user_case_insensitively() throws BonitaException { - Assume.assumeTrue("Search is case sensitive on our docker oracle", - !System.getProperty("sysprop.bonita.bdm.db.vendor").equals("oracle")); List users = asList( getIdentityAPI().createUser("Jean_Michel", "bpm", "Jean Michel", "Jarre"), getIdentityAPI().createUser("michel.mimi", "bpm", "Michel", "Mimi")); diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/page/PageAPIIT.java b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/page/PageAPIIT.java index c2217b836ac..2cbf6418527 100644 --- a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/page/PageAPIIT.java +++ b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/page/PageAPIIT.java @@ -110,6 +110,11 @@ public void should_getPage_return_the_page() throws Exception { @Test public void updatePage_should_set_provided_field_to_false_if_provided_pages_are_modified() throws Exception { + //given: + try (var is = PageAPIIT.class.getResourceAsStream("/provided_page_ready_to_update.zip")) { + getPageAPI().createPage("provided_page_ready_to_update.zip", is.readAllBytes()); + } + // when final PageUpdater pageUpdater = new PageUpdater(); final String newDisplayName = "new display name"; diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/profile/ProfileCommunityIT.java b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/profile/ProfileCommunityIT.java new file mode 100644 index 00000000000..a1d3c4774ad --- /dev/null +++ b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/profile/ProfileCommunityIT.java @@ -0,0 +1,40 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.engine.profile; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.bonitasoft.engine.exception.BonitaException; +import org.bonitasoft.engine.search.Order; +import org.bonitasoft.engine.search.SearchOptionsBuilder; +import org.bonitasoft.engine.search.SearchResult; +import org.junit.Test; + +/** + * Specific tests for the community edition on the profile API + */ +public class ProfileCommunityIT extends AbstractProfileIT { + + @Test + public void searchProfile() throws BonitaException { + final SearchOptionsBuilder builder = new SearchOptionsBuilder(0, 10); + builder.sort(ProfileSearchDescriptor.NAME, Order.DESC); + + final SearchResult searchedProfiles = getProfileAPI().searchProfiles(builder.done()); + assertThat(searchedProfiles.getCount()).isEqualTo(2); + assertThat(searchedProfiles.getResult().get(0).getName()).isEqualTo("User"); + assertThat(searchedProfiles.getResult().get(1).getName()).isEqualTo("Administrator"); + } + +} diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/profile/ProfileIT.java b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/profile/ProfileIT.java index b9e5174f979..a00bd1f047d 100644 --- a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/profile/ProfileIT.java +++ b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/profile/ProfileIT.java @@ -59,16 +59,6 @@ private List getProfilesFromSession(User user, String password) throws L return profiles; } - @Test - public void searchProfile() throws BonitaException { - final SearchOptionsBuilder builder = new SearchOptionsBuilder(0, 10); - builder.sort(ProfileSearchDescriptor.NAME, Order.DESC); - - final SearchResult searchedProfiles = getProfileAPI().searchProfiles(builder.done()); - assertEquals(2, searchedProfiles.getCount()); - assertEquals("User", searchedProfiles.getResult().get(0).getName()); - } - @Test public void searchProfileWithSearchTerm() throws BonitaException { final SearchOptionsBuilder builder = new SearchOptionsBuilder(0, 10); diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/search/SearchActivityInstanceIT.java b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/search/SearchActivityInstanceIT.java index 48653614292..5979dbe4bce 100644 --- a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/search/SearchActivityInstanceIT.java +++ b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/search/SearchActivityInstanceIT.java @@ -31,24 +31,7 @@ import org.bonitasoft.engine.bpm.bar.BusinessArchive; import org.bonitasoft.engine.bpm.bar.BusinessArchiveBuilder; import org.bonitasoft.engine.bpm.connector.ConnectorEvent; -import org.bonitasoft.engine.bpm.flownode.ActivityInstance; -import org.bonitasoft.engine.bpm.flownode.ActivityInstanceCriterion; -import org.bonitasoft.engine.bpm.flownode.ActivityInstanceSearchDescriptor; -import org.bonitasoft.engine.bpm.flownode.ActivityStates; -import org.bonitasoft.engine.bpm.flownode.ArchivedActivityInstance; -import org.bonitasoft.engine.bpm.flownode.ArchivedActivityInstanceSearchDescriptor; -import org.bonitasoft.engine.bpm.flownode.ArchivedAutomaticTaskInstance; -import org.bonitasoft.engine.bpm.flownode.ArchivedFlowNodeInstance; -import org.bonitasoft.engine.bpm.flownode.ArchivedFlowNodeInstanceSearchDescriptor; -import org.bonitasoft.engine.bpm.flownode.ArchivedHumanTaskInstance; -import org.bonitasoft.engine.bpm.flownode.ArchivedHumanTaskInstanceSearchDescriptor; -import org.bonitasoft.engine.bpm.flownode.ArchivedManualTaskInstance; -import org.bonitasoft.engine.bpm.flownode.ArchivedUserTaskInstance; -import org.bonitasoft.engine.bpm.flownode.FlowNodeInstance; -import org.bonitasoft.engine.bpm.flownode.FlowNodeType; -import org.bonitasoft.engine.bpm.flownode.HumanTaskInstance; -import org.bonitasoft.engine.bpm.flownode.HumanTaskInstanceSearchDescriptor; -import org.bonitasoft.engine.bpm.flownode.TaskPriority; +import org.bonitasoft.engine.bpm.flownode.*; import org.bonitasoft.engine.bpm.process.DesignProcessDefinition; import org.bonitasoft.engine.bpm.process.ProcessDefinition; import org.bonitasoft.engine.bpm.process.ProcessInstance; @@ -66,6 +49,7 @@ import org.bonitasoft.engine.identity.Role; import org.bonitasoft.engine.identity.User; import org.bonitasoft.engine.test.BuildTestUtil; +import org.bonitasoft.engine.test.TestStates; import org.bonitasoft.engine.test.check.CheckNbOfActivities; import org.junit.Test; @@ -357,8 +341,8 @@ public void searchAssignedAndPendingHumanTaskInstances() throws Exception { ProcessDefinition p1 = deployAndEnableProcessWithActor(bar1, "a", user); ProcessDefinition p2 = deployAndEnableProcessWithActor(bar2, "a", user); - getProcessAPI().startProcess(p1.getId()); - getProcessAPI().startProcess(p2.getId()); + var instance1 = getProcessAPI().startProcess(p1.getId()); + var instance2 = getProcessAPI().startProcess(p2.getId()); waitForUserTask("p1task1"); long p1task2 = waitForUserTask("p1task2"); long p1task3 = waitForUserTask("p1task3"); @@ -388,6 +372,16 @@ public void searchAssignedAndPendingHumanTaskInstances() throws Exception { .filter("name", "p1task3").done()); assertThat(searchResult).matches(haveTasks(), toDescription(searchResult)); + try { + waitForTaskInState(instance1, "p1task3", TestStates.NORMAL_FINAL); + } catch (ActivityInstanceNotFoundException e) { + // ignore it, instance is already completed + } + try { + waitForTaskInState(instance2, "p2task3", TestStates.NORMAL_FINAL); + } catch (ActivityInstanceNotFoundException e) { + // ignore it, instance is already completed + } disableAndDeleteProcess(p1, p2); } @@ -1267,6 +1261,11 @@ public void searchPendingHumanTasksAssignedToUser() throws Exception { assertThat(searchHumanTaskInstancesCountOnly.getResult()).describedAs("Human tasks").isEmpty(); // -------- tear down + try { + waitForTaskInState(processInstance, "userTask6_assigned_to_John_long_execution", TestStates.NORMAL_FINAL); + } catch (ActivityInstanceNotFoundException e) { + // ignore it, activity is already finished + } disableAndDeleteProcess(processDefinition); deleteUser(john); } diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/search/SearchProcessInstanceIT.java b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/search/SearchProcessInstanceIT.java index c549f5614a3..3615bab72cd 100644 --- a/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/search/SearchProcessInstanceIT.java +++ b/bonita-integration-tests/bonita-integration-tests-client/src/test/java/org/bonitasoft/engine/search/SearchProcessInstanceIT.java @@ -144,13 +144,13 @@ public void searchFailedProcessInstances() throws Exception { TestConnectorThatThrowException.class, "TestConnectorThatThrowException.jar"); final ProcessInstance instance1 = getProcessAPI().startProcess(processDefinitionWithFailedConnector.getId()); - waitForProcessToBeInState(instance1, ProcessInstanceState.ERROR); + waitForProcessToBeInState(instance1.getId(), ProcessInstanceState.ERROR); final ProcessInstance instance2 = getProcessAPI().startProcess(processDefinitionWithFailedTask.getId()); waitForFlowNodeInFailedState(instance2); final ProcessInstance instance3 = getProcessAPI().startProcess(processDefinitionWithFailedConnector.getId()); - waitForProcessToBeInState(instance3, ProcessInstanceState.ERROR); + waitForProcessToBeInState(instance3.getId(), ProcessInstanceState.ERROR); // search and check result ASC final SearchOptionsBuilder searchOptions1 = BuildTestUtil.buildSearchOptions(0, 2, diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/test/resources/application-to-test-permissions.xml b/bonita-integration-tests/bonita-integration-tests-client/src/test/resources/application-to-test-permissions.xml new file mode 100644 index 00000000000..18b3030a970 --- /dev/null +++ b/bonita-integration-tests/bonita-integration-tests-client/src/test/resources/application-to-test-permissions.xml @@ -0,0 +1,15 @@ + + + + Bonita Editable Application + bonita-application-directory.png + + + + + + Some page + + + + diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/test/resources/logback-test.xml b/bonita-integration-tests/bonita-integration-tests-client/src/test/resources/logback-test.xml index 33746fcdf05..6d63cf30b5b 100644 --- a/bonita-integration-tests/bonita-integration-tests-client/src/test/resources/logback-test.xml +++ b/bonita-integration-tests/bonita-integration-tests-client/src/test/resources/logback-test.xml @@ -10,6 +10,8 @@ + + diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/test/resources/org/bonitasoft/engine/application/superAdminApp.xml b/bonita-integration-tests/bonita-integration-tests-client/src/test/resources/org/bonitasoft/engine/application/superAdminApp.xml index 236c5adf3ec..bc1a7bab8c0 100644 --- a/bonita-integration-tests/bonita-integration-tests-client/src/test/resources/org/bonitasoft/engine/application/superAdminApp.xml +++ b/bonita-integration-tests/bonita-integration-tests-client/src/test/resources/org/bonitasoft/engine/application/superAdminApp.xml @@ -1,5 +1,5 @@ - + Bonita Super Administrator Application bonita-super-admin-application.png diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/test/resources/org/bonitasoft/engine/application/testApp.xml b/bonita-integration-tests/bonita-integration-tests-client/src/test/resources/org/bonitasoft/engine/application/testApp.xml index 8a05343ba2a..a4f296956eb 100644 --- a/bonita-integration-tests/bonita-integration-tests-client/src/test/resources/org/bonitasoft/engine/application/testApp.xml +++ b/bonita-integration-tests/bonita-integration-tests-client/src/test/resources/org/bonitasoft/engine/application/testApp.xml @@ -1,5 +1,5 @@ - + Test App diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/test/resources/org/bonitasoft/web/application/final/application-to-test-permissions.zip b/bonita-integration-tests/bonita-integration-tests-client/src/test/resources/org/bonitasoft/web/application/final/application-to-test-permissions.zip deleted file mode 100644 index 843141f9896..00000000000 Binary files a/bonita-integration-tests/bonita-integration-tests-client/src/test/resources/org/bonitasoft/web/application/final/application-to-test-permissions.zip and /dev/null differ diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/test/resources/org/bonitasoft/web/page/final/page-to-test-permissions.zip b/bonita-integration-tests/bonita-integration-tests-client/src/test/resources/page-to-test-permissions.zip similarity index 100% rename from bonita-integration-tests/bonita-integration-tests-client/src/test/resources/org/bonitasoft/web/page/final/page-to-test-permissions.zip rename to bonita-integration-tests/bonita-integration-tests-client/src/test/resources/page-to-test-permissions.zip diff --git a/bonita-integration-tests/bonita-integration-tests-client/src/main/resources/org/bonitasoft/web/page/provided_page_ready_to_update.zip b/bonita-integration-tests/bonita-integration-tests-client/src/test/resources/provided_page_ready_to_update.zip similarity index 100% rename from bonita-integration-tests/bonita-integration-tests-client/src/main/resources/org/bonitasoft/web/page/provided_page_ready_to_update.zip rename to bonita-integration-tests/bonita-integration-tests-client/src/test/resources/provided_page_ready_to_update.zip diff --git a/bonita-integration-tests/bonita-integration-tests-local/build.gradle b/bonita-integration-tests/bonita-integration-tests-local/build.gradle index ea8a52d351d..4d71d8597cc 100644 --- a/bonita-integration-tests/bonita-integration-tests-local/build.gradle +++ b/bonita-integration-tests/bonita-integration-tests-local/build.gradle @@ -3,16 +3,12 @@ plugins { id("bonita-tests") } dependencies { - api libs.junit4 api libs.assertj api libs.mockitoCore api project(':bonita-integration-tests:bonita-integration-tests-client') implementation(project(":bpm:bonita-core:bonita-process-engine")) api project(':bpm:bonita-server') api libs.commonsIO - runtimeOnly libs.mysql - runtimeOnly libs.msSqlServer - runtimeOnly libs.postgresql testRuntimeOnly libs.logback testAnnotationProcessor libs.lombok testImplementation libs.lombok diff --git a/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/application/installer/ApplicationInstallerIT.java b/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/application/installer/ApplicationInstallerIT.java index aa92909d0c9..7cf8136a2f5 100644 --- a/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/application/installer/ApplicationInstallerIT.java +++ b/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/application/installer/ApplicationInstallerIT.java @@ -22,16 +22,7 @@ import org.bonitasoft.engine.api.impl.application.installer.ApplicationArchive; import org.bonitasoft.engine.api.impl.application.installer.ApplicationArchiveReader; import org.bonitasoft.engine.api.impl.application.installer.ApplicationInstaller; -import org.bonitasoft.engine.api.impl.application.installer.detector.ArtifactTypeDetector; -import org.bonitasoft.engine.api.impl.application.installer.detector.BdmDetector; -import org.bonitasoft.engine.api.impl.application.installer.detector.CustomPageDetector; -import org.bonitasoft.engine.api.impl.application.installer.detector.IconDetector; -import org.bonitasoft.engine.api.impl.application.installer.detector.LayoutDetector; -import org.bonitasoft.engine.api.impl.application.installer.detector.LivingApplicationDetector; -import org.bonitasoft.engine.api.impl.application.installer.detector.OrganizationDetector; -import org.bonitasoft.engine.api.impl.application.installer.detector.PageAndFormDetector; -import org.bonitasoft.engine.api.impl.application.installer.detector.ProcessDetector; -import org.bonitasoft.engine.api.impl.application.installer.detector.ThemeDetector; +import org.bonitasoft.engine.api.impl.application.installer.detector.*; import org.bonitasoft.engine.bpm.process.ActivationState; import org.bonitasoft.engine.bpm.process.ConfigurationState; import org.bonitasoft.engine.bpm.process.ProcessDeploymentInfo; @@ -55,6 +46,11 @@ public void before() throws Exception { @After public void after() throws Exception { + if (!getTenantAdministrationAPI().isPaused()) { + getTenantAdministrationAPI().pause(); + getTenantAdministrationAPI().cleanAndUninstallBusinessDataModel(); + getTenantAdministrationAPI().resume(); + } logoutOnTenant(); } @@ -62,10 +58,10 @@ public void after() throws Exception { public void custom_application_should_be_deployed_entirely() throws Exception { // ensure application did not exist initially: assertThatExceptionOfType(ApplicationNotFoundException.class) - .isThrownBy(() -> getApplicationAPI().getApplicationByToken("appsManagerBonita")); + .isThrownBy(() -> getApplicationAPI().getIApplicationByToken("appsManagerBonita")); // given: - ApplicationInstaller applicationInstallerImpl = ServiceAccessorSingleton.getInstance() + ApplicationInstaller applicationInstaller = ServiceAccessorSingleton.getInstance() .lookup(ApplicationInstaller.class); final ApplicationArchiveReader applicationArchiveReader = new ApplicationArchiveReader( new ArtifactTypeDetector(new BdmDetector(), @@ -76,7 +72,7 @@ public void custom_application_should_be_deployed_entirely() throws Exception { // when: try (var applicationAsStream = ApplicationInstallerIT.class.getResourceAsStream("/customer-application.zip")) { var applicationArchive = applicationArchiveReader.read(applicationAsStream); - applicationInstallerImpl.install(applicationArchive); + applicationInstaller.install(applicationArchive); } // then: @@ -87,7 +83,7 @@ public void custom_application_should_be_deployed_entirely() throws Exception { assertThat(getIdentityAPI().getRoleByName("appsManager")).isNotNull(); assertThat(getIdentityAPI().getGroupByPath("/appsManagement")).isNotNull(); - assertThat(getApplicationAPI().getApplicationByToken("appsManagerBonita").getDisplayName()) + assertThat(getApplicationAPI().getIApplicationByToken("appsManagerBonita").getDisplayName()) .isEqualTo("Application manager"); final long processDefinitionId = getProcessAPI().getProcessDefinitionId("CallHealthCheck", "1.0"); final ProcessDeploymentInfo deploymentInfo = getProcessAPI().getProcessDeploymentInfo(processDefinitionId); @@ -107,7 +103,7 @@ public void custom_application_should_be_deployed_entirely() throws Exception { @Test public void custom_application_should_be_installed_with_configuration() throws Exception { // given: - ApplicationInstaller applicationInstallerImpl = ServiceAccessorSingleton.getInstance() + ApplicationInstaller applicationInstaller = ServiceAccessorSingleton.getInstance() .lookup(ApplicationInstaller.class); final ApplicationArchiveReader applicationArchiveReader = new ApplicationArchiveReader( new ArtifactTypeDetector(new BdmDetector(), @@ -121,7 +117,7 @@ public void custom_application_should_be_installed_with_configuration() throws E var applicationArchive = applicationArchiveReader.read(applicationAsStream); applicationArchive.setConfigurationFile(new File(ApplicationInstallerIT.class .getResource("/simple-app-1.0.0-SNAPSHOT-local.bconf").getFile())); - applicationInstallerImpl.install(applicationArchive); + applicationInstaller.install(applicationArchive); } final long processDefinitionId = getProcessAPI().getProcessDefinitionId("Pool", "1.0"); diff --git a/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/application/installer/ApplicationInstallerUpdateIT.java b/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/application/installer/ApplicationInstallerUpdateIT.java index 3825f0be09d..770cba2e38e 100644 --- a/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/application/installer/ApplicationInstallerUpdateIT.java +++ b/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/application/installer/ApplicationInstallerUpdateIT.java @@ -26,14 +26,23 @@ import org.bonitasoft.engine.api.impl.application.installer.ApplicationArchive; import org.bonitasoft.engine.api.impl.application.installer.ApplicationArchiveReader; import org.bonitasoft.engine.api.impl.application.installer.ApplicationInstaller; -import org.bonitasoft.engine.api.impl.application.installer.detector.*; +import org.bonitasoft.engine.api.impl.application.installer.detector.ArtifactTypeDetector; +import org.bonitasoft.engine.api.impl.application.installer.detector.BdmDetector; +import org.bonitasoft.engine.api.impl.application.installer.detector.CustomPageDetector; +import org.bonitasoft.engine.api.impl.application.installer.detector.IconDetector; +import org.bonitasoft.engine.api.impl.application.installer.detector.LayoutDetector; +import org.bonitasoft.engine.api.impl.application.installer.detector.LivingApplicationDetector; +import org.bonitasoft.engine.api.impl.application.installer.detector.OrganizationDetector; +import org.bonitasoft.engine.api.impl.application.installer.detector.PageAndFormDetector; +import org.bonitasoft.engine.api.impl.application.installer.detector.ProcessDetector; +import org.bonitasoft.engine.api.impl.application.installer.detector.ThemeDetector; import org.bonitasoft.engine.bpm.process.ActivationState; import org.bonitasoft.engine.bpm.process.ConfigurationState; import org.bonitasoft.engine.bpm.process.ProcessDefinitionNotFoundException; import org.bonitasoft.engine.bpm.process.ProcessDeploymentInfo; -import org.bonitasoft.engine.business.application.Application; import org.bonitasoft.engine.business.application.ApplicationNotFoundException; import org.bonitasoft.engine.business.application.ApplicationPage; +import org.bonitasoft.engine.business.application.IApplication; import org.bonitasoft.engine.exception.ApplicationInstallationException; import org.bonitasoft.engine.exception.SearchException; import org.bonitasoft.engine.identity.User; @@ -60,31 +69,35 @@ public void before() throws Exception { loginOnDefaultTenantWithDefaultTechnicalUser(); applicationInstaller = ServiceAccessorSingleton.getInstance() - .lookup(ApplicationInstaller.class);; + .lookup(ApplicationInstaller.class); applicationArchiveReader = new ApplicationArchiveReader( new ArtifactTypeDetector(new BdmDetector(), new LivingApplicationDetector(), new OrganizationDetector(), new CustomPageDetector(), new ProcessDetector(), new ThemeDetector(), new PageAndFormDetector(), new LayoutDetector(), new IconDetector())); - initFirstInstall(); } @After public void after() throws Exception { + if (!getTenantAdministrationAPI().isPaused()) { + getTenantAdministrationAPI().pause(); + getTenantAdministrationAPI().cleanAndUninstallBusinessDataModel(); + getTenantAdministrationAPI().resume(); + } logoutOnTenant(); } private void initFirstInstall() throws Exception { // ensure application did not exist initially: assertThatExceptionOfType(ApplicationNotFoundException.class) - .isThrownBy(() -> getApplicationAPI().getApplicationByToken("appsManagerBonita")); + .isThrownBy(() -> getApplicationAPI().getIApplicationByToken("appsManagerBonita")); // given: - final InputStream applicationAsStream = this.getClass().getResourceAsStream("/customer-application.zip"); - - // when: - applicationInstaller.install(applicationArchiveReader.read(applicationAsStream)); + try (final InputStream applicationAsStream = this.getClass().getResourceAsStream("/customer-application.zip")) { + // when: + applicationInstaller.install(applicationArchiveReader.read(applicationAsStream)); + } // then: @@ -94,7 +107,7 @@ private void initFirstInstall() throws Exception { assertThat(getIdentityAPI().getRoleByName("appsManager")).isNotNull(); assertThat(getIdentityAPI().getGroupByPath("/appsManagement")).isNotNull(); - assertThat(getApplicationAPI().getApplicationByToken("appsManagerBonita").getDisplayName()) + assertThat(getApplicationAPI().getIApplicationByToken("appsManagerBonita").getDisplayName()) .isEqualTo("Application manager"); final long processDefinitionId = getProcessAPI().getProcessDefinitionId("CallHealthCheck", "1.0"); final ProcessDeploymentInfo deploymentInfo = getProcessAPI().getProcessDeploymentInfo(processDefinitionId); @@ -130,7 +143,7 @@ public void process_update_custom_application_with_same_installed_version() thro // given: //installed resources TenantResource bdm = getTenantAdministrationAPI().getBusinessDataModelResource(); - Application application = getApplicationAPI().getApplicationByToken("appsManagerBonita"); + IApplication application = getApplicationAPI().getIApplicationByToken("appsManagerBonita"); Page processStarterAPI = getPageAPI().getPageByName("custompage_processStarter"); Page healthPage = getPageAPI().getPageByName("custompage_HealthPage"); Page pmLayout = getPageAPI().getPageByName("custompage_pmLayout"); @@ -145,7 +158,7 @@ public void process_update_custom_application_with_same_installed_version() thro } // then: TenantResource updatedBdm = getTenantAdministrationAPI().getBusinessDataModelResource(); - Application updatedApplication = getApplicationAPI().getApplicationByToken("appsManagerBonita"); + IApplication updatedApplication = getApplicationAPI().getIApplicationByToken("appsManagerBonita"); Page updatedProcessStarterAPI = getPageAPI().getPageByName("custompage_processStarter"); Page updatedHealthPage = getPageAPI().getPageByName("custompage_HealthPage"); Page updatedPmLayout = getPageAPI().getPageByName("custompage_pmLayout"); @@ -173,7 +186,7 @@ public void process_update_custom_application_with_new_version() // given: //installed resources TenantResource bdm = getTenantAdministrationAPI().getBusinessDataModelResource(); - Application application = getApplicationAPI().getApplicationByToken("appsManagerBonita"); + IApplication application = getApplicationAPI().getIApplicationByToken("appsManagerBonita"); Page processStarterAPI = getPageAPI().getPageByName("custompage_processStarter"); Page healthPage = getPageAPI().getPageByName("custompage_HealthPage"); Page pmLayout = getPageAPI().getPageByName("custompage_pmLayout"); @@ -186,7 +199,7 @@ public void process_update_custom_application_with_new_version() // then: TenantResource updatedBdm = getTenantAdministrationAPI().getBusinessDataModelResource(); - Application updatedApplication = getApplicationAPI().getApplicationByToken("appsManagerBonita"); + IApplication updatedApplication = getApplicationAPI().getIApplicationByToken("appsManagerBonita"); Page updatedProcessStarterAPI = getPageAPI().getPageByName("custompage_processStarter"); Page updatedHealthPage = getPageAPI().getPageByName("custompage_HealthPage"); Page updatedPmLayout = getPageAPI().getPageByName("custompage_pmLayout"); diff --git a/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/bpm/event/LocalInterruptingTimerBoundaryEventIT.java b/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/bpm/event/LocalInterruptingTimerBoundaryEventIT.java index 0328c7fa3bf..1f2536c16aa 100644 --- a/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/bpm/event/LocalInterruptingTimerBoundaryEventIT.java +++ b/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/bpm/event/LocalInterruptingTimerBoundaryEventIT.java @@ -370,8 +370,7 @@ public void timerBoundaryEvent_should_not_trigger_and_be_deleted_at_flownode_abo waitForUserTask(processInstance.getId(), "step1"); waitForUserTaskAssignAndExecuteIt(processInstance, "step2", user, Map.of()); waitForProcessToFinish(processInstance); - List allJobs = schedulerService.getAllJobs(); - assertThat(allJobs).isEmpty(); + assertThat(schedulerService.getAllJobs()).isEmpty(); disableAndDeleteProcess(processDefinition); } diff --git a/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/business/application/importer/ApplicationImporterIT.java b/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/business/application/importer/ApplicationImporterIT.java new file mode 100644 index 00000000000..ae50a81a6a3 --- /dev/null +++ b/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/business/application/importer/ApplicationImporterIT.java @@ -0,0 +1,306 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.engine.business.application.importer; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; + +import org.bonitasoft.engine.api.ImportStatus; +import org.bonitasoft.engine.api.impl.SessionInfos; +import org.bonitasoft.engine.bpm.CommonBPMServicesTest; +import org.bonitasoft.engine.business.application.ApplicationService; +import org.bonitasoft.engine.business.application.model.SApplication; +import org.bonitasoft.engine.business.application.model.SApplicationState; +import org.bonitasoft.engine.page.PageService; +import org.bonitasoft.engine.page.SPage; +import org.bonitasoft.engine.profile.ProfileService; +import org.bonitasoft.engine.profile.model.SProfile; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class ApplicationImporterIT extends CommonBPMServicesTest { + + private ApplicationImporter applicationImporter; + private ApplicationService applicationService; + private PageService pageService; + private ProfileService profileService; + + private static final String APP_1_TOKEN = "app1"; + private static final String APP_2_TOKEN = "app2"; + private static final String APP_3_TOKEN = "app3"; + private static final String APP_4_TOKEN = "app4"; + + @Before + public void setUp() { + applicationImporter = getServiceAccessor().getApplicationImporter(); + applicationService = getServiceAccessor().getApplicationService(); + pageService = getServiceAccessor().getPageService(); + profileService = getServiceAccessor().getProfileService(); + } + + @After + public void tearDown() throws Exception { + deleteApplication(APP_1_TOKEN); + deleteApplication(APP_2_TOKEN); + deleteApplication(APP_3_TOKEN); + deleteApplication(APP_4_TOKEN); + getTransactionService().executeInTransaction(() -> { + SPage page = pageService.getPageByName("custompage_mynewcustompage"); + if (page != null) { + pageService.deletePage(page.getId()); + } + return page; + }); + } + + private void deleteApplication(String appToken) throws Exception { + getTransactionService().executeInTransaction(() -> { + SApplication app = applicationService.getApplicationByToken(appToken); + if (app != null) { + applicationService.forceDeleteApplication(app); + } + return app; + }); + } + + @Test + public void one_application_link_should_be_imported_successfully() throws Exception { + //given + String xmlToImport = "/applications-importer/oneApplicationLink.xml"; + + // ensure applications did not exist initially: + assertAppNotExists(APP_1_TOKEN); + + //when + List importStatuses = importApplicationsFromXml(xmlToImport); + + //then + assertThat(importStatuses).hasSize(1); + assertThat(importStatuses.get(0).getName()).isEqualTo(APP_1_TOKEN); + assertThat(importStatuses.get(0).getStatus()).isEqualTo(ImportStatus.Status.ADDED); + assertThat(importStatuses.get(0).getErrors()).isEmpty(); + + assertAppLink1(); + } + + @Test + public void multiple_application_links_should_be_imported_successfully() throws Exception { + //given + String xmlToImport = "/applications-importer/multipleApplicationLinks.xml"; + + // ensure applications did not exist initially: + assertAppNotExists(APP_1_TOKEN); + assertAppNotExists(APP_2_TOKEN); + + //when + List importStatuses = importApplicationsFromXml(xmlToImport); + + //then + assertThat(importStatuses).hasSize(2); + assertThat(importStatuses.get(0).getName()).isEqualTo(APP_1_TOKEN); + assertThat(importStatuses.get(0).getStatus()).isEqualTo(ImportStatus.Status.ADDED); + assertThat(importStatuses.get(0).getErrors()).isEmpty(); + assertThat(importStatuses.get(1).getName()).isEqualTo(APP_2_TOKEN); + assertThat(importStatuses.get(1).getStatus()).isEqualTo(ImportStatus.Status.ADDED); + assertThat(importStatuses.get(1).getErrors()).isEmpty(); + + assertAppLink1(); + assertAppLink2(); + } + + @Test + public void mixed_legacy_and_application_links_should_be_imported_successfully() throws Exception { + //given + String xmlToImport = "/applications-importer/mixedLegacyAndApplicationLinks.xml"; + + // ensure applications did not exist initially: + assertAppNotExists(APP_1_TOKEN); + assertAppNotExists(APP_2_TOKEN); + assertAppNotExists(APP_3_TOKEN); + assertAppNotExists(APP_4_TOKEN); + + // create page mandatory for app3 + createDummyPage(); + + //when + List importStatuses = importApplicationsFromXml(xmlToImport); + + //then + assertThat(importStatuses).hasSize(4); + assertThat(importStatuses.get(0).getName()).isEqualTo(APP_1_TOKEN); + assertThat(importStatuses.get(0).getStatus()).isEqualTo(ImportStatus.Status.ADDED); + assertThat(importStatuses.get(0).getErrors()).isEmpty(); + assertThat(importStatuses.get(1).getName()).isEqualTo(APP_2_TOKEN); + assertThat(importStatuses.get(1).getStatus()).isEqualTo(ImportStatus.Status.ADDED); + assertThat(importStatuses.get(1).getErrors()).isEmpty(); + assertThat(importStatuses.get(2).getName()).isEqualTo(APP_3_TOKEN); + assertThat(importStatuses.get(2).getStatus()).isEqualTo(ImportStatus.Status.ADDED); + assertThat(importStatuses.get(2).getErrors()).isEmpty(); + assertThat(importStatuses.get(3).getName()).isEqualTo(APP_4_TOKEN); + assertThat(importStatuses.get(3).getStatus()).isEqualTo(ImportStatus.Status.ADDED); + assertThat(importStatuses.get(3).getErrors()).isEmpty(); + + assertAppLink1(); + assertAppLink2(); + assertAppLink3(); + assertAppLink4(); + } + + @Test + public void mixed_legacy_and_application_links_should_be_imported_successfully_twice() throws Exception { + //given + String xmlToImport = "/applications-importer/mixedLegacyAndApplicationLinks.xml"; + ApplicationImportStrategy updateStrategy = (a1, a2) -> ApplicationImportStrategy.ImportStrategy.REPLACE; + + // create page mandatory for app3 + createDummyPage(); + + //when + List importStatuses = importApplicationsFromXml(xmlToImport); + assertThat(importStatuses).hasSize(4); + // and re-import + try (var xmlAsStream = this.getClass().getResourceAsStream(xmlToImport)) { + assertThat(xmlAsStream).isNotNull(); + importStatuses = getTransactionService() + .executeInTransaction(() -> applicationImporter.importApplications(xmlAsStream.readAllBytes(), null, + null, SessionInfos.getUserIdFromSession(), updateStrategy)); + } + + //then + assertThat(importStatuses).hasSize(4); + assertThat(importStatuses.get(0).getName()).isEqualTo(APP_1_TOKEN); + assertThat(importStatuses.get(0).getStatus()).isEqualTo(ImportStatus.Status.REPLACED); + assertThat(importStatuses.get(0).getErrors()).isEmpty(); + assertThat(importStatuses.get(1).getName()).isEqualTo(APP_2_TOKEN); + assertThat(importStatuses.get(1).getStatus()).isEqualTo(ImportStatus.Status.REPLACED); + assertThat(importStatuses.get(1).getErrors()).isEmpty(); + assertThat(importStatuses.get(2).getName()).isEqualTo(APP_3_TOKEN); + assertThat(importStatuses.get(2).getStatus()).isEqualTo(ImportStatus.Status.REPLACED); + assertThat(importStatuses.get(2).getErrors()).isEmpty(); + assertThat(importStatuses.get(3).getName()).isEqualTo(APP_4_TOKEN); + assertThat(importStatuses.get(3).getStatus()).isEqualTo(ImportStatus.Status.REPLACED); + assertThat(importStatuses.get(3).getErrors()).isEmpty(); + + assertAppLink1(); + assertAppLink2(); + assertAppLink3(); + assertAppLink4(); + + } + + private List importApplicationsFromXml(String xmlToImport) throws Exception { + try (var xmlAsStream = this.getClass().getResourceAsStream(xmlToImport)) { + assertThat(xmlAsStream).isNotNull(); + return getTransactionService() + .executeInTransaction(() -> applicationImporter.importApplications(xmlAsStream.readAllBytes(), null, + null, SessionInfos.getUserIdFromSession(), null)); + } + } + + private void assertAppNotExists(String appToken) throws Exception { + SApplication existingApp1 = getTransactionService() + .executeInTransaction(() -> applicationService.getApplicationByToken(appToken)); + assertThat(existingApp1).isNull(); + } + + private void assertAppLink1() throws Exception { + SApplication app = getTransactionService() + .executeInTransaction(() -> applicationService.getApplicationByToken(APP_1_TOKEN)); + assertThat(app).isNotNull(); + assertThat(app.getDisplayName()).isEqualTo("Application 1"); + assertThat(app.getDescription()).isEqualTo("Description of Application 1"); + assertThat(app.getVersion()).isEqualTo("1.0"); + assertThat(app.getIconPath()).isEqualTo("/app1.jpg"); + assertThat(app.getCreatedBy()).isEqualTo(-1L); + assertThat(app.getState()).isEqualTo(SApplicationState.ACTIVATED.name()); + assertThat(getProfile(app.getProfileId()).getName()).isEqualTo("User"); + assertThat(app.getInternalProfile()).isNull(); + assertThat(app.getHomePageId()).isNull(); + assertThat(app.getLayoutId()).isNull(); + assertThat(app.getThemeId()).isNull(); + assertThat(app.isEditable()).isTrue(); + assertThat(app.isLink()).isTrue(); + } + + private SProfile getProfile(Long profileId) throws Exception { + return getTransactionService().executeInTransaction(() -> profileService.getProfile(profileId)); + } + + private void assertAppLink2() throws Exception { + SApplication app = getTransactionService() + .executeInTransaction(() -> applicationService.getApplicationByToken(APP_2_TOKEN)); + assertThat(app).isNotNull(); + assertThat(app.getDisplayName()).isEqualTo("Application 2"); + assertThat(app.getDescription()).isNull(); + assertThat(app.getVersion()).isEqualTo("1.1"); + assertThat(app.getIconPath()).isNull(); + assertThat(app.getCreatedBy()).isEqualTo(-1L); + assertThat(app.getState()).isEqualTo(SApplicationState.DEACTIVATED.name()); + assertThat(app.getProfileId()).isNull(); + assertThat(app.getInternalProfile()).isNull(); + assertThat(app.getHomePageId()).isNull(); + assertThat(app.getLayoutId()).isNull(); + assertThat(app.getThemeId()).isNull(); + assertThat(app.isEditable()).isTrue(); + assertThat(app.isLink()).isTrue(); + } + + private void assertAppLink3() throws Exception { + SApplication app = getTransactionService() + .executeInTransaction(() -> applicationService.getApplicationByToken(APP_3_TOKEN)); + assertThat(app).isNotNull(); + assertThat(app.getDisplayName()).isEqualTo("Application 3"); + assertThat(app.getDescription()).isEqualTo("Description of Application 3"); + assertThat(app.getVersion()).isEqualTo("2.0"); + assertThat(app.getIconPath()).isEqualTo("/app3.jpg"); + assertThat(app.getCreatedBy()).isEqualTo(-1L); + assertThat(app.getState()).isEqualTo(SApplicationState.ACTIVATED.name()); + assertThat(app.getHomePageId()).isNotNull(); + assertThat(getProfile(app.getProfileId()).getName()).isEqualTo("User"); + assertThat(app.getInternalProfile()).isNull(); + assertThat(app.getLayoutId()).isNotNull(); + assertThat(app.getThemeId()).isNotNull(); + assertThat(app.isEditable()).isTrue(); + assertThat(app.isLink()).isFalse(); + } + + private void assertAppLink4() throws Exception { + SApplication app = getTransactionService() + .executeInTransaction(() -> applicationService.getApplicationByToken(APP_4_TOKEN)); + assertThat(app).isNotNull(); + assertThat(app.getDisplayName()).isEqualTo("Application 4"); + assertThat(app.getDescription()).isNull(); + assertThat(app.getVersion()).isEqualTo("2.0"); + assertThat(app.getIconPath()).isNull(); + assertThat(app.getCreatedBy()).isEqualTo(-1L); + assertThat(app.getState()).isEqualTo(SApplicationState.DEACTIVATED.name()); + assertThat(app.getProfileId()).isNull(); + assertThat(app.getInternalProfile()).isNull(); + assertThat(app.getHomePageId()).isNull(); + assertThat(app.getLayoutId()).isNotNull(); + assertThat(app.getThemeId()).isNotNull(); + assertThat(app.isEditable()).isTrue(); + assertThat(app.isLink()).isFalse(); + } + + private void createDummyPage() throws Exception { + try (var contentStream = this.getClass().getResourceAsStream("/applications-importer/dummy-bizapp-page.zip")) { + assertThat(contentStream).isNotNull(); + getTransactionService().executeInTransaction(() -> pageService.addPage(contentStream.readAllBytes(), + "custompage_mynewcustompage", SessionInfos.getUserIdFromSession())); + } + } +} diff --git a/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/business/data/BDRepositoryLocalIT.java b/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/business/data/BDRepositoryLocalIT.java index 32edff41d5d..f8a696a9ea5 100644 --- a/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/business/data/BDRepositoryLocalIT.java +++ b/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/business/data/BDRepositoryLocalIT.java @@ -43,6 +43,7 @@ import org.bonitasoft.engine.operation.OperatorType; import org.bonitasoft.engine.service.ServiceAccessor; import org.bonitasoft.engine.service.ServiceAccessorSingleton; +import org.bonitasoft.platform.setup.PlatformSetup; import org.junit.*; import org.junit.rules.TemporaryFolder; @@ -485,7 +486,7 @@ private BusinessObjectModel buildCustomBOM() { @Test public void deploy_a_BDR_and_verify_sequence_behaviour_by_DBVendor() throws Exception { - String dbVendor = System.getProperty("sysprop.bonita.bdm.db.vendor"); + String dbVendor = PlatformSetup.getPropertyBonitaBdmDbVendor(); Assume.assumeTrue("We don't test sequence behaviour on h2", !dbVendor.equals("h2")); switch (dbVendor) { case "postgres": diff --git a/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/classloader/ClassLoaderServiceIT.java b/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/classloader/ClassLoaderServiceIT.java index 8c4259a9079..c5f6e39cc3f 100644 --- a/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/classloader/ClassLoaderServiceIT.java +++ b/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/classloader/ClassLoaderServiceIT.java @@ -33,6 +33,7 @@ import org.bonitasoft.engine.CallableWithException; import org.bonitasoft.engine.RunnableWithException; import org.bonitasoft.engine.bpm.CommonBPMServicesTest; +import org.bonitasoft.engine.commons.exceptions.SBonitaException; import org.bonitasoft.engine.commons.io.IOUtil; import org.bonitasoft.engine.dependency.DependencyService; import org.bonitasoft.engine.dependency.SDependencyException; @@ -79,10 +80,11 @@ public void tearDown() throws Exception { } @Before - public void setUp() { + public void setUp() throws SBonitaException { classLoaderService = getServiceAccessor().getClassLoaderService(); dependencyService = getServiceAccessor().getDependencyService(); platformDependencyService = getServiceAccessor().getPlatformDependencyService(); + classLoaderService.start(); } private T inTx(CallableWithException runnable) throws Exception { diff --git a/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/job/JobExecutionIT.java b/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/job/JobExecutionIT.java index a8c8a70d92e..34b27072fc7 100644 --- a/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/job/JobExecutionIT.java +++ b/bonita-integration-tests/bonita-integration-tests-local/src/test/java/org/bonitasoft/engine/job/JobExecutionIT.java @@ -20,8 +20,6 @@ import static org.awaitility.Durations.ONE_SECOND; import static org.hamcrest.collection.IsCollectionWithSize.hasSize; -import java.io.Serializable; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; @@ -133,15 +131,14 @@ private List waitForJobDescriptorsToHaveSize(final int nbOfExpec public void retryAJob_should_update_job_log_when_execution_fails_again() throws Exception { //given getCommandAPI().register("except", "Throws Exception when scheduling a job", AddJobCommand.class.getName()); - final Map parameters = new HashMap<>(); try { - getCommandAPI().execute("except", parameters); + getCommandAPI().execute("except", Map.of()); // Job can trigger in up to 'org.quartz.scheduler.idleWaitTime' milliseconds, so better wait long enough: FailedJob failedJob = await().atMost(ONE_MINUTE).pollInterval(ONE_SECOND).until( () -> getProcessAPI().getFailedJobs(0, 100), hasSize(1)).get(0); //when - getProcessAPI().replayFailedJob(failedJob.getJobDescriptorId(), emptyMap()); + getProcessAPI().replayFailedJob(failedJob.getJobDescriptorId()); //then // Job can trigger in up to 'org.quartz.scheduler.idleWaitTime' milliseconds, so better wait long enough: diff --git a/bonita-integration-tests/bonita-integration-tests-local/src/test/resources/applications-importer/dummy-bizapp-page.zip b/bonita-integration-tests/bonita-integration-tests-local/src/test/resources/applications-importer/dummy-bizapp-page.zip new file mode 100644 index 00000000000..d069fa1bfb3 Binary files /dev/null and b/bonita-integration-tests/bonita-integration-tests-local/src/test/resources/applications-importer/dummy-bizapp-page.zip differ diff --git a/bonita-integration-tests/bonita-integration-tests-local/src/test/resources/applications-importer/mixedLegacyAndApplicationLinks.xml b/bonita-integration-tests/bonita-integration-tests-local/src/test/resources/applications-importer/mixedLegacyAndApplicationLinks.xml new file mode 100644 index 00000000000..e1a2004610d --- /dev/null +++ b/bonita-integration-tests/bonita-integration-tests-local/src/test/resources/applications-importer/mixedLegacyAndApplicationLinks.xml @@ -0,0 +1,39 @@ + + + + Application 1 + Description of Application 1 + /app1.jpg + + + Application 2 + + + Application 3 + Description of Application 3 + /app3.jpg + + + + + + Menu level 1 + + + Menu level 1.1 + + + + + Empty menu + + + + + Application 4 + + + + diff --git a/bonita-integration-tests/bonita-integration-tests-local/src/test/resources/applications-importer/multipleApplicationLinks.xml b/bonita-integration-tests/bonita-integration-tests-local/src/test/resources/applications-importer/multipleApplicationLinks.xml new file mode 100644 index 00000000000..a2d4ab49b74 --- /dev/null +++ b/bonita-integration-tests/bonita-integration-tests-local/src/test/resources/applications-importer/multipleApplicationLinks.xml @@ -0,0 +1,11 @@ + + + + Application 1 + Description of Application 1 + /app1.jpg + + + Application 2 + + diff --git a/bonita-integration-tests/bonita-integration-tests-local/src/test/resources/applications-importer/oneApplicationLink.xml b/bonita-integration-tests/bonita-integration-tests-local/src/test/resources/applications-importer/oneApplicationLink.xml new file mode 100644 index 00000000000..39bcec34f7c --- /dev/null +++ b/bonita-integration-tests/bonita-integration-tests-local/src/test/resources/applications-importer/oneApplicationLink.xml @@ -0,0 +1,8 @@ + + + + Application 1 + Description of Application 1 + /app1.jpg + + diff --git a/bonita-integration-tests/bonita-integration-tests-local/src/test/resources/customer-application-v2.zip b/bonita-integration-tests/bonita-integration-tests-local/src/test/resources/customer-application-v2.zip index 8ff42af60d6..44d76de3d24 100644 Binary files a/bonita-integration-tests/bonita-integration-tests-local/src/test/resources/customer-application-v2.zip and b/bonita-integration-tests/bonita-integration-tests-local/src/test/resources/customer-application-v2.zip differ diff --git a/bonita-integration-tests/bonita-integration-tests-local/src/test/resources/customer-application.zip b/bonita-integration-tests/bonita-integration-tests-local/src/test/resources/customer-application.zip index e9bd5c0d1a9..75dffe47b7f 100644 Binary files a/bonita-integration-tests/bonita-integration-tests-local/src/test/resources/customer-application.zip and b/bonita-integration-tests/bonita-integration-tests-local/src/test/resources/customer-application.zip differ diff --git a/bonita-integration-tests/bonita-integration-tests-web/build.gradle b/bonita-integration-tests/bonita-integration-tests-web/build.gradle index 30109d74bbd..ced9b8593b3 100644 --- a/bonita-integration-tests/bonita-integration-tests-web/build.gradle +++ b/bonita-integration-tests/bonita-integration-tests-web/build.gradle @@ -12,6 +12,7 @@ dependencies { implementation libs.slf4jApi implementation libs.commonsIO implementation libs.jakartaServletApi + implementation libs.junit4 implementation libs.springTest testImplementation libs.hamcrest testImplementation libs.mockitoCore diff --git a/bonita-integration-tests/bonita-integration-tests-web/src/test/java/org/bonitasoft/web/rest/server/api/page/builder/PageItemBuilder.java b/bonita-integration-tests/bonita-integration-tests-web/src/main/java/org/bonitasoft/web/rest/server/api/page/builder/PageItemBuilder.java similarity index 100% rename from bonita-integration-tests/bonita-integration-tests-web/src/test/java/org/bonitasoft/web/rest/server/api/page/builder/PageItemBuilder.java rename to bonita-integration-tests/bonita-integration-tests-web/src/main/java/org/bonitasoft/web/rest/server/api/page/builder/PageItemBuilder.java diff --git a/bonita-integration-tests/bonita-integration-tests-web/src/test/java/org/bonitasoft/web/rest/server/api/application/APIApplicationIT.java b/bonita-integration-tests/bonita-integration-tests-web/src/test/java/org/bonitasoft/web/rest/server/api/application/APIApplicationIT.java new file mode 100644 index 00000000000..4c61f6541af --- /dev/null +++ b/bonita-integration-tests/bonita-integration-tests-web/src/test/java/org/bonitasoft/web/rest/server/api/application/APIApplicationIT.java @@ -0,0 +1,213 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.web.rest.server.api.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.bonitasoft.web.rest.server.api.page.builder.PageItemBuilder.aPageItem; +import static org.junit.Assert.*; +import static org.mockito.Mockito.spy; + +import java.io.InputStream; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.io.IOUtils; +import org.bonitasoft.engine.api.ApplicationAPI; +import org.bonitasoft.engine.api.PageAPI; +import org.bonitasoft.engine.api.TenantAPIAccessor; +import org.bonitasoft.engine.business.application.Application; +import org.bonitasoft.engine.business.application.ApplicationImportPolicy; +import org.bonitasoft.engine.exception.BonitaRuntimeException; +import org.bonitasoft.engine.page.Page; +import org.bonitasoft.engine.search.SearchOptions; +import org.bonitasoft.engine.search.SearchOptionsBuilder; +import org.bonitasoft.engine.session.APISession; +import org.bonitasoft.web.rest.model.application.*; +import org.bonitasoft.web.rest.model.portal.page.PageItem; +import org.bonitasoft.web.rest.server.api.applicationpage.APIApplicationDataStoreFactory; +import org.bonitasoft.web.rest.server.datastore.application.ApplicationDataStoreCreator; +import org.bonitasoft.web.test.AbstractConsoleTest; +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; + +public class APIApplicationIT extends AbstractConsoleTest { + + public static final String HOME_PAGE_ZIP = "/homePage.zip"; + public static final String LAYOUT_ZIP = "/layout.zip"; + public static final String THEME_ZIP = "/theme.zip"; + public static final String APP_LINK_DESCRIPTOR = "/appLinkDescriptor.xml"; + private APIApplication apiApplication; + private APISession session; + + @Override + public void consoleTestSetUp() throws Exception { + session = getInitiator().getSession(); + apiApplication = spy( + new APIApplication(new ApplicationDataStoreCreator(), new APIApplicationDataStoreFactory())); + apiApplication.setCaller(getAPICaller(session, "API/living/application")); + } + + private PageAPI getPageAPI() throws Exception { + return TenantAPIAccessor.getCustomPageAPI(session); + } + + private ApplicationAPI getApplicationAPI() throws Exception { + return TenantAPIAccessor.getApplicationAPI(session); + } + + @After + public void cleanPagesAndApplications() throws Exception { + final SearchOptions searchOptions = new SearchOptionsBuilder(0, 100000).done(); + + List apps = getApplicationAPI().searchApplications(searchOptions).getResult(); + apps.stream().map(Application::getId).forEach(t -> { + try { + getApplicationAPI().deleteApplication(t); + } catch (Exception e) { + e.printStackTrace(); + } + }); + + List pages = getPageAPI().searchPages(searchOptions).getResult(); + var ids = pages.stream().map(Page::getId).toList(); + getPageAPI().deletePages(ids); + } + + private PageItem addPage(String pageFileName) throws Exception { + final PageItem pageItem = aPageItem().build(); + final InputStream pageInputStream = getClass().getResourceAsStream(pageFileName); + final byte[] pageContent = IOUtils.toByteArray(pageInputStream); + return addPageItemToRepository(pageItem.getContentName(), pageContent); + } + + private PageItem addPageItemToRepository(final String pageContentName, final byte[] pageContent) throws Exception { + return aPageItem().fromEngineItem(getPageAPI().createPage(pageContentName, pageContent)).build(); + } + + @Test + public void should_add_ApplicationLink() { + // Given + final ApplicationLinkItem linkItem = ApplicationLinkDefinition.get().createItem(); + linkItem.setToken("tokenLink"); + linkItem.setDisplayName("Link"); + linkItem.setVersion("1.0"); + linkItem.setProfileId(2L); + linkItem.setState("ACTIVATED"); + + // When + var createdLink = apiApplication.add(linkItem); + + // Then + Map attributes = new HashMap<>(linkItem.getAttributes().size()); + linkItem.getAttributes().keySet().forEach(k -> attributes.put(k, createdLink.getAttributes().get(k))); + Assert.assertEquals(new HashMap<>(linkItem.getAttributes()), attributes); + assertThat(createdLink.isLink()).isTrue(); + } + + @Test + public void should_add_LegacyApplication() throws Exception { + // Given + var pair = createLegacyApplicationWithOriginal(); + var original = pair.getKey(); + var legacyApp = pair.getValue(); + + // Then + Map attributes = new HashMap<>(original.getAttributes().size()); + original.getAttributes().keySet().forEach(k -> attributes.put(k, legacyApp.getAttributes().get(k))); + Assert.assertEquals(new HashMap<>(original.getAttributes()), attributes); + assertThat(legacyApp.isLink()).isFalse(); + } + + @Test + public void should_update_ApplicationLink() throws Exception { + // Given + getApplicationAPI().importApplications( + IOUtils.toByteArray(getClass().getResourceAsStream(APP_LINK_DESCRIPTOR)), + ApplicationImportPolicy.REPLACE_DUPLICATES); + ApplicationLinkItem linkItem = (ApplicationLinkItem) apiApplication + .search(0, 1, null, null, Collections.singletonMap("token", "app1")).getResults().get(0); + Map attributes = Map.of(AbstractApplicationItem.ATTRIBUTE_DISPLAY_NAME, "Link Updated"); + + // When + var updatedLink = apiApplication.update(linkItem.getId(), attributes); + + // Then updated + assertEquals("Link Updated", updatedLink.getDisplayName()); + assertEquals("Link Updated", apiApplication.get(linkItem.getId()).getDisplayName()); + assertThat(linkItem.isLink()).isTrue(); + } + + @Test + public void should_update_LegacyApplication() throws Exception { + // Given + var legacyApp = createLegacyApplication(); + + // When + Map attributes = Map.of(AbstractApplicationItem.ATTRIBUTE_DISPLAY_NAME, "Legacy Updated"); + var updatedItem = apiApplication.update(legacyApp.getId(), attributes); + + // Then + assertEquals("Legacy Updated", updatedItem.getDisplayName()); + assertThat(updatedItem.isLink()).isFalse(); + } + + @Test + public void should_search_not_support_filtering_on_ApplicationLinks() throws Exception { + // Given + var legacyApp = createLegacyApplication(); + + // When + final String search = legacyApp.getDisplayName(); + final String orders = ApplicationItem.ATTRIBUTE_TOKEN + " DESC"; + final HashMap filters = new HashMap<>(); + filters.put(ApplicationItem.ATTRIBUTE_LINK, "true"); + + // Then + assertThrows( + "Expected exception: The search does not support filtering on application links in this edition.", + BonitaRuntimeException.class, () -> apiApplication.search(0, 1, search, orders, filters)); + } + + private ApplicationItem createLegacyApplication() throws Exception { + return createLegacyApplicationWithOriginal().getValue(); + } + + /** + * Create a legacy application. + * + * @return a pair with the constructed item as key and the api call result as value. + * @throws Exception exception during creation + */ + private Entry createLegacyApplicationWithOriginal() throws Exception { + addPage(HOME_PAGE_ZIP); + final PageItem layout = addPage(LAYOUT_ZIP); + final PageItem theme = addPage(THEME_ZIP); + final ApplicationItem legacyItem = ApplicationDefinition.get().createItem(); + legacyItem.setToken("tokenLegacy"); + legacyItem.setDisplayName("Legacy"); + legacyItem.setVersion("1.0"); + legacyItem.setProfileId(2L); + legacyItem.setState("ACTIVATED"); + legacyItem.setLayoutId(layout.getId().toLong()); + legacyItem.setThemeId(theme.getId().toLong()); + + return Collections.singletonMap(legacyItem, (ApplicationItem) apiApplication.add(legacyItem)).entrySet() + .iterator().next(); + } + +} diff --git a/bonita-integration-tests/bonita-integration-tests-web/src/test/resources/appLinkDescriptor.xml b/bonita-integration-tests/bonita-integration-tests-web/src/test/resources/appLinkDescriptor.xml new file mode 100644 index 00000000000..39bcec34f7c --- /dev/null +++ b/bonita-integration-tests/bonita-integration-tests-web/src/test/resources/appLinkDescriptor.xml @@ -0,0 +1,8 @@ + + + + Application 1 + Description of Application 1 + /app1.jpg + + diff --git a/bonita-integration-tests/bonita-integration-tests-web/src/test/resources/homePage.zip b/bonita-integration-tests/bonita-integration-tests-web/src/test/resources/homePage.zip new file mode 100644 index 00000000000..5bfc615661e Binary files /dev/null and b/bonita-integration-tests/bonita-integration-tests-web/src/test/resources/homePage.zip differ diff --git a/bonita-integration-tests/bonita-integration-tests-web/src/test/resources/layout.zip b/bonita-integration-tests/bonita-integration-tests-web/src/test/resources/layout.zip new file mode 100644 index 00000000000..68ab047e014 Binary files /dev/null and b/bonita-integration-tests/bonita-integration-tests-web/src/test/resources/layout.zip differ diff --git a/bonita-integration-tests/bonita-integration-tests-web/src/test/resources/theme.zip b/bonita-integration-tests/bonita-integration-tests-web/src/test/resources/theme.zip new file mode 100644 index 00000000000..dbef7c74613 Binary files /dev/null and b/bonita-integration-tests/bonita-integration-tests-web/src/test/resources/theme.zip differ diff --git a/bonita-integration-tests/bonita-query-tests/build.gradle b/bonita-integration-tests/bonita-query-tests/build.gradle index d69d043ac3f..5605f3c5c4b 100644 --- a/bonita-integration-tests/bonita-query-tests/build.gradle +++ b/bonita-integration-tests/bonita-query-tests/build.gradle @@ -1,7 +1,8 @@ - +plugins { id 'bonita-docker-database' } dependencies { - testImplementation libs.junit4 + testAnnotationProcessor libs.lombok + testImplementation libs.lombok testImplementation libs.assertj testImplementation libs.h2 testImplementation libs.springBeans @@ -11,4 +12,8 @@ dependencies { testImplementation libs.springOrm testImplementation project(":bpm:bonita-server") testImplementation project(":bpm:bonita-common") + + testRuntimeOnly libs.tomcatDbcp } + +databaseIntegrationTest { include "**/*Test.class" } diff --git a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/contract/data/ContractDataTest.java b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/contract/data/ContractDataTest.java index 21ad6563f90..dc1774f6754 100644 --- a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/contract/data/ContractDataTest.java +++ b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/contract/data/ContractDataTest.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.Map; +import org.bonitasoft.engine.test.persistence.jdbc.JdbcRowMapper; import org.bonitasoft.engine.test.persistence.repository.ContractDataRepository; import org.junit.Test; import org.junit.runner.RunWith; @@ -51,20 +52,20 @@ public void should_be_able_to_add_contract_data() { repository.flush(); List> contractData = jdbcTemplate - .queryForList("SELECT kind, name, scopeId, val from contract_data"); + .query("SELECT KIND, NAME, SCOPEID, VAL from contract_data", new JdbcRowMapper("SCOPEID")); assertThat(contractData).hasSize(2); assertThat(contractData).anySatisfy(c -> { - assertThat(c.get("kind")).isEqualTo("PROCESS"); - assertThat(c.get("name")).isEqualTo("myProcessContractData"); - assertThat(c.get("scopeId")).isEqualTo(123L); - assertThat(c.get("val")).isEqualTo("SerializedValue"); + assertThat(c.get("KIND")).isEqualTo("PROCESS"); + assertThat(c.get("NAME")).isEqualTo("myProcessContractData"); + assertThat(c.get("SCOPEID")).isEqualTo(123L); + assertThat(c.get("VAL")).isEqualTo("SerializedValue"); }); assertThat(contractData).anySatisfy(c -> { - assertThat(c.get("kind")).isEqualTo("TASK"); - assertThat(c.get("name")).isEqualTo("myTaskContractData"); - assertThat(c.get("scopeId")).isEqualTo(124L); - assertThat(c.get("val")).isEqualTo("SerializedValue"); + assertThat(c.get("KIND")).isEqualTo("TASK"); + assertThat(c.get("NAME")).isEqualTo("myTaskContractData"); + assertThat(c.get("SCOPEID")).isEqualTo(124L); + assertThat(c.get("VAL")).isEqualTo("SerializedValue"); }); } diff --git a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/form/FormMappingTest.java b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/form/FormMappingTest.java index cfba4b95700..14e73deae72 100644 --- a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/form/FormMappingTest.java +++ b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/form/FormMappingTest.java @@ -20,6 +20,7 @@ import java.util.Map; import org.bonitasoft.engine.page.SPageMapping; +import org.bonitasoft.engine.test.persistence.jdbc.JdbcRowMapper; import org.bonitasoft.engine.test.persistence.repository.TestRepository; import org.junit.Test; import org.junit.runner.RunWith; @@ -51,24 +52,26 @@ public void should_be_able_to_add_form_mapping() { testRepository.flush(); - List> formMapping = jdbcTemplate.queryForList("SELECT * from form_mapping"); + List> formMapping = jdbcTemplate.query("SELECT * from form_mapping", + new JdbcRowMapper("PAGE_MAPPING_ID", "LASTUPDATEDATE", "LASTUPDATEDBY", "PROCESS")); + assertThat(formMapping).hasSize(2); assertThat(formMapping).anySatisfy(c -> { - assertThat(c.get("task")).isEqualTo("task1"); - assertThat(c.get("type")).isEqualTo(3); - assertThat(c.get("page_mapping_id")).isEqualTo(1L); - assertThat(c.get("lastupdatedate")).isEqualTo(200L); - assertThat(c.get("lastupdatedby")).isEqualTo(100L); - assertThat(c.get("process")).isEqualTo(2L); - assertThat(c.get("target")).isEqualTo("target1"); + assertThat(c.get("TASK")).isEqualTo("task1"); + assertThat(c.get("TYPE")).isEqualTo(3); + assertThat(c.get("PAGE_MAPPING_ID")).isEqualTo(1L); + assertThat(c.get("LASTUPDATEDATE")).isEqualTo(200L); + assertThat(c.get("LASTUPDATEDBY")).isEqualTo(100L); + assertThat(c.get("PROCESS")).isEqualTo(2L); + assertThat(c.get("TARGET")).isEqualTo("target1"); }); assertThat(formMapping).anySatisfy(c -> { - assertThat(c.get("task")).isEqualTo("task2"); - assertThat(c.get("page_mapping_id")).isEqualTo(1L); - assertThat(c.get("type")).isEqualTo(4); - assertThat(c.get("process")).isEqualTo(3L); - assertThat(c.get("target")).isEqualTo("target2"); + assertThat(c.get("TASK")).isEqualTo("task2"); + assertThat(c.get("PAGE_MAPPING_ID")).isEqualTo(1L); + assertThat(c.get("TYPE")).isEqualTo(4); + assertThat(c.get("PROCESS")).isEqualTo(3L); + assertThat(c.get("TARGET")).isEqualTo("target2"); }); } diff --git a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/ArchiveFlowNodeInstanceTest.java b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/ArchiveFlowNodeInstanceTest.java index 6eb6d117fe8..63c3993ab79 100755 --- a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/ArchiveFlowNodeInstanceTest.java +++ b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/ArchiveFlowNodeInstanceTest.java @@ -78,7 +78,7 @@ public void should_save_and_get_SAUserTaskInstance_with_task_priority() { .queryForMap("SELECT * FROM arch_flownode_instance where id = " + flowNode.getId()); assertThat(flowNodeFromQuery).isEqualTo(flowNode); - assertThat(flowNodeAsMap.get("PRIORITY")).isEqualTo(3); + assertThat(((Number) flowNodeAsMap.get("PRIORITY")).intValue()).isEqualTo(3); } @Test diff --git a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/ArchiveProcessInstanceQueriesTest.java b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/ArchiveProcessInstanceQueriesTest.java index 861cb139090..cc96d272346 100644 --- a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/ArchiveProcessInstanceQueriesTest.java +++ b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/ArchiveProcessInstanceQueriesTest.java @@ -29,6 +29,7 @@ import org.bonitasoft.engine.core.process.instance.model.archive.business.data.SAProcessMultiRefBusinessDataInstance; import org.bonitasoft.engine.core.process.instance.model.archive.business.data.SAProcessSimpleRefBusinessDataInstance; import org.bonitasoft.engine.persistence.PersistentObject; +import org.bonitasoft.engine.test.persistence.jdbc.JdbcRowMapper; import org.bonitasoft.engine.test.persistence.repository.ProcessInstanceRepository; import org.junit.Test; import org.junit.runner.RunWith; @@ -83,7 +84,7 @@ public void getArchivedProcessInstancesInAllStates_should_return_empty_list_when } @Test - public void should_save_and_get_multi_business_data_reference_for_process() { + public void should_save_and_get_multi_business_data_reference_for_archived_process() { SAProcessMultiRefBusinessDataInstance multiRefBusinessDataInstance = new SAProcessMultiRefBusinessDataInstance(); multiRefBusinessDataInstance.setDataIds(Arrays.asList(23L, 25L, 27L)); multiRefBusinessDataInstance.setProcessInstanceId(PROCESS_INSTANCE_ID); @@ -95,12 +96,14 @@ public void should_save_and_get_multi_business_data_reference_for_process() { PersistentObject multiRefBusinessData = repository.selectOne("getSARefBusinessDataInstance", pair("processInstanceId", PROCESS_INSTANCE_ID), pair("name", "myMultiProcData")); Map multiRefBusinessDataAsMap = jdbcTemplate - .queryForMap( + .queryForObject( "SELECT ID, KIND, NAME, DATA_CLASSNAME, DATA_ID, ORIG_PROC_INST_ID, ORIG_FN_INST_ID FROM arch_ref_biz_data_inst WHERE orig_proc_inst_id=" - + PROCESS_INSTANCE_ID + " AND name='myMultiProcData'"); + + PROCESS_INSTANCE_ID + " AND name='myMultiProcData'", + new JdbcRowMapper("ID", "DATA_ID", "ORIG_PROC_INST_ID", "ORIG_FN_INST_ID")); List> dataIds = jdbcTemplate - .queryForList("SELECT ID, IDX, DATA_ID FROM arch_multi_biz_data WHERE id=" - + multiRefBusinessDataInstance.getId()); + .query("SELECT ID, IDX, DATA_ID FROM arch_multi_biz_data WHERE id=" + + multiRefBusinessDataInstance.getId(), + new JdbcRowMapper("ID", "IDX", "DATA_ID")); assertThat(((SAProcessMultiRefBusinessDataInstance) multiRefBusinessData).getDataIds()) .isEqualTo(Arrays.asList(23L, 25L, 27L)); @@ -114,13 +117,13 @@ public void should_save_and_get_multi_business_data_reference_for_process() { entry("ORIG_PROC_INST_ID", PROCESS_INSTANCE_ID), entry("ORIG_FN_INST_ID", null)); assertThat(dataIds).containsExactly( - mapOf(pair("ID", multiRefBusinessDataInstance.getId()), pair("IDX", 0), pair("DATA_ID", 23L)), - mapOf(pair("ID", multiRefBusinessDataInstance.getId()), pair("IDX", 1), pair("DATA_ID", 25L)), - mapOf(pair("ID", multiRefBusinessDataInstance.getId()), pair("IDX", 2), pair("DATA_ID", 27L))); + mapOf(pair("ID", multiRefBusinessDataInstance.getId()), pair("IDX", 0L), pair("DATA_ID", 23L)), + mapOf(pair("ID", multiRefBusinessDataInstance.getId()), pair("IDX", 1L), pair("DATA_ID", 25L)), + mapOf(pair("ID", multiRefBusinessDataInstance.getId()), pair("IDX", 2L), pair("DATA_ID", 27L))); } @Test - public void should_save_and_get_single_business_data_reference_for_process() { + public void should_save_and_get_single_business_data_reference_for_archived_process() { SAProcessSimpleRefBusinessDataInstance singleRef = new SAProcessSimpleRefBusinessDataInstance(); singleRef.setDataId(43L); singleRef.setProcessInstanceId(PROCESS_INSTANCE_ID); @@ -132,10 +135,11 @@ public void should_save_and_get_single_business_data_reference_for_process() { PersistentObject singleRefFromQuery = repository.selectOne("getSARefBusinessDataInstance", pair("processInstanceId", PROCESS_INSTANCE_ID), pair("name", "mySingleData")); Map multiRefBusinessDataAsMap = jdbcTemplate - .queryForMap( + .queryForObject( "SELECT ID, KIND, NAME, DATA_CLASSNAME, DATA_ID, ORIG_PROC_INST_ID, ORIG_FN_INST_ID FROM arch_ref_biz_data_inst WHERE orig_proc_inst_id=" + PROCESS_INSTANCE_ID - + " AND name='mySingleData'"); + + " AND name='mySingleData'", + new JdbcRowMapper("ID", "DATA_ID", "ORIG_PROC_INST_ID", "ORIG_FN_INST_ID")); assertThat(singleRefFromQuery).isEqualTo(singleRef); assertThat(multiRefBusinessDataAsMap).containsOnly( entry("ID", singleRef.getId()), @@ -148,7 +152,7 @@ public void should_save_and_get_single_business_data_reference_for_process() { } @Test - public void should_save_and_get_single_business_data_reference_for_flow_node() { + public void should_save_and_get_single_business_data_reference_for_flow_node_of_archived_process() { SAFlowNodeSimpleRefBusinessDataInstance singleRef = new SAFlowNodeSimpleRefBusinessDataInstance(); singleRef.setDataId(43L); singleRef.setFlowNodeInstanceId(FLOW_NODE_INSTANCE_ID); @@ -160,10 +164,11 @@ public void should_save_and_get_single_business_data_reference_for_flow_node() { PersistentObject singleRefFromQuery = repository.selectOne("getSAFlowNodeRefBusinessDataInstance", pair("flowNodeInstanceId", FLOW_NODE_INSTANCE_ID), pair("name", "mySingleData")); Map multiRefBusinessDataAsMap = jdbcTemplate - .queryForMap( + .queryForObject( "SELECT ID, KIND, NAME, DATA_CLASSNAME, DATA_ID, ORIG_PROC_INST_ID, ORIG_FN_INST_ID FROM arch_ref_biz_data_inst WHERE orig_fn_inst_id=" + FLOW_NODE_INSTANCE_ID - + " AND name='mySingleData'"); + + " AND name='mySingleData'", + new JdbcRowMapper("ID", "DATA_ID", "ORIG_PROC_INST_ID", "ORIG_FN_INST_ID")); assertThat(singleRefFromQuery).isEqualTo(singleRef); assertThat(multiRefBusinessDataAsMap).containsOnly( entry("ID", singleRef.getId()), diff --git a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/CommentsTest.java b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/CommentsTest.java index 24438148e5f..b9fed49acad 100644 --- a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/CommentsTest.java +++ b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/CommentsTest.java @@ -24,6 +24,7 @@ import org.bonitasoft.engine.core.process.comment.model.SSystemComment; import org.bonitasoft.engine.core.process.comment.model.archive.SAComment; import org.bonitasoft.engine.persistence.PersistentObject; +import org.bonitasoft.engine.test.persistence.jdbc.JdbcRowMapper; import org.bonitasoft.engine.test.persistence.repository.CommentRepository; import org.junit.Test; import org.junit.runner.RunWith; @@ -61,7 +62,7 @@ public void should_getComments_of_process_instance() { repository.add(new SHumanComment(PROCESS2_ID, "comment5", JACK_ID)); assertThat(repository.getCommentsOfProcessInstance(PROCESS1_ID)).extracting("content", "userId", "class") - .containsExactly( + .containsExactlyInAnyOrder( tuple("comment1", JACK_ID, SHumanComment.class), tuple("comment2", JOHN_ID, SHumanComment.class), tuple("comment3", JACK_ID, SHumanComment.class), @@ -76,13 +77,15 @@ public void should_save_and_get_SComment() { repository.flush(); Map comment1AsMap = jdbcTemplate - .queryForMap( + .queryForObject( "SELECT ID, KIND, CONTENT, POSTDATE, PROCESSINSTANCEID, USERID FROM process_comment WHERE processInstanceId = " - + PROCESS1_ID); + + PROCESS1_ID, + new JdbcRowMapper("ID", "POSTDATE", "PROCESSINSTANCEID", "USERID")); Map comment2AsMap = jdbcTemplate - .queryForMap( + .queryForObject( "SELECT ID, KIND, CONTENT, POSTDATE, PROCESSINSTANCEID, USERID FROM process_comment WHERE processInstanceId = " - + PROCESS2_ID); + + PROCESS2_ID, + new JdbcRowMapper("ID", "POSTDATE", "PROCESSINSTANCEID", "USERID")); assertThat(comment1AsMap).containsOnly( entry("ID", comment1.getId()), @@ -111,13 +114,17 @@ public void should_save_and_get_SAComment() { PersistentObject comment2FromQuery = repository.selectOne("getArchivedCommentById", pair("id", comment2.getId())); Map comment1AsMap = jdbcTemplate - .queryForMap( + .queryForObject( "SELECT ID, SOURCEOBJECTID, ARCHIVEDATE, CONTENT, POSTDATE, PROCESSINSTANCEID, USERID FROM arch_process_comment WHERE processInstanceId = " - + PROCESS1_ID); + + PROCESS1_ID, + new JdbcRowMapper("ID", "SOURCEOBJECTID", "ARCHIVEDATE", "POSTDATE", "PROCESSINSTANCEID", + "USERID")); Map comment2AsMap = jdbcTemplate - .queryForMap( + .queryForObject( "SELECT ID, SOURCEOBJECTID, ARCHIVEDATE, CONTENT, POSTDATE, PROCESSINSTANCEID, USERID FROM arch_process_comment WHERE processInstanceId = " - + PROCESS2_ID); + + PROCESS2_ID, + new JdbcRowMapper("ID", "SOURCEOBJECTID", "ARCHIVEDATE", "POSTDATE", "PROCESSINSTANCEID", + "USERID")); assertThat(comment1FromQuery).isEqualTo(comment1); assertThat(comment2FromQuery).isEqualTo(comment2); diff --git a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/ConnectorInstanceQueriesTest.java b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/ConnectorInstanceQueriesTest.java index 87d92fed982..08261d15982 100644 --- a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/ConnectorInstanceQueriesTest.java +++ b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/ConnectorInstanceQueriesTest.java @@ -71,13 +71,12 @@ public void setUp() { containerType = "Pouet"; containerId = 1L; long differentContainerId = 5L; - long tenantId = 100L; expectedConnector1 = aConnectorInstance().setContainerId(containerId).setContainerType(containerType) .setActivationEvent(ON_FINISH) .withFailureInfo(false).setState(ConnectorState.EXECUTING.toString()).build(); expectedConnector2 = aConnectorInstance().setContainerId(containerId).setContainerType(containerType) .setActivationEvent(ON_ENTER) - .setState(ConnectorState.EXECUTING.toString()).withFailureInfo(false) + .setState(ConnectorState.EXECUTING.toString()).withFailureInfo(false).setExecutionOrder(1) .build(); expectedConnector3 = aConnectorInstance().setContainerId(containerId).setContainerType(containerType) .setActivationEvent(ON_ENTER) @@ -85,7 +84,7 @@ public void setUp() { .build(); expectedConnector4 = aConnectorInstance().setContainerId(containerId).setContainerType(containerType) .setActivationEvent(ON_ENTER) - .setState(ConnectorState.TO_BE_EXECUTED.toString()).withFailureInfo(false) + .setState(ConnectorState.TO_BE_EXECUTED.toString()).withFailureInfo(false).setExecutionOrder(2) .build(); expectedConnector5 = aConnectorInstance().setContainerId(containerId).setContainerType(containerType) .setActivationEvent(ON_ENTER) @@ -142,10 +141,10 @@ public void getNumberOfConnectorInstances() { @Test public void getNextExecutableConnectorInstance() { - SConnectorInstance connectors = repository + SConnectorInstance connector = repository .getNextExecutableConnectorInstance(containerId, containerType, ON_ENTER); - assertThat(connectors).isSameAs(expectedConnector2); + assertThat(connector).isSameAs(expectedConnector2); } @Test diff --git a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/ProcessDeploymentInfoQueriesTest.java b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/ProcessDeploymentInfoQueriesTest.java index b973a8385d7..fa0b99d6681 100644 --- a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/ProcessDeploymentInfoQueriesTest.java +++ b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/ProcessDeploymentInfoQueriesTest.java @@ -31,6 +31,7 @@ import org.bonitasoft.engine.core.process.definition.model.SProcessDefinitionDesignContent; import org.bonitasoft.engine.persistence.PersistentObject; import org.bonitasoft.engine.supervisor.mapping.model.SProcessSupervisor; +import org.bonitasoft.engine.test.persistence.jdbc.JdbcRowMapper; import org.bonitasoft.engine.test.persistence.repository.ProcessDeploymentInfoRepository; import org.junit.Before; import org.junit.Test; @@ -883,12 +884,15 @@ public void should_reference_design_content_using_id() { .designContent(content).build()); repository.flush(); - Map processDefinitionMap = jdbcTemplate.queryForMap( - "SELECT name, CONTENT_ID FROM process_definition WHERE processId=123456"); - Map processContentMap = jdbcTemplate.queryForMap("SELECT ID FROM process_content "); + Map processDefinitionMap = jdbcTemplate.queryForObject( + "SELECT name, CONTENT_ID FROM process_definition WHERE processId=123456", + new JdbcRowMapper("CONTENT_ID")); + Map processContentMap = jdbcTemplate.queryForObject("SELECT ID FROM process_content", + new JdbcRowMapper("ID")); - assertThat(processDefinitionMap.get("name")).isEqualTo("MyProcessWithContent"); + assertThat(processDefinitionMap.get("NAME")).isEqualTo("MyProcessWithContent"); assertThat(processDefinitionMap.get("CONTENT_ID")).isEqualTo(content.getId()); assertThat(processContentMap.get("ID")).isEqualTo(content.getId()); } + } diff --git a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/ProcessInstanceQueriesTest.java b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/ProcessInstanceQueriesTest.java index 37ca48ba992..62e0a7a6223 100644 --- a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/ProcessInstanceQueriesTest.java +++ b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/ProcessInstanceQueriesTest.java @@ -44,6 +44,7 @@ import org.bonitasoft.engine.core.process.instance.model.business.data.SProcessSimpleRefBusinessDataInstance; import org.bonitasoft.engine.identity.model.SUser; import org.bonitasoft.engine.persistence.PersistentObject; +import org.bonitasoft.engine.test.persistence.jdbc.JdbcRowMapper; import org.bonitasoft.engine.test.persistence.repository.ProcessInstanceRepository; import org.junit.Test; import org.junit.runner.RunWith; @@ -875,10 +876,14 @@ public void should_save_and_get_multi_business_data_reference_for_process() { PersistentObject multiRefBusinessData = repository.selectOne("getSRefBusinessDataInstance", pair("processInstanceId", PROCESS_INSTANCE_ID), pair("name", "myMultiProcData")); Map multiRefBusinessDataAsMap = jdbcTemplate - .queryForMap("SELECT * FROM ref_biz_data_inst WHERE proc_inst_id=" + PROCESS_INSTANCE_ID - + " AND name='myMultiProcData'"); - List> dataIds = jdbcTemplate.queryForList( - "SELECT ID, IDX, DATA_ID FROM multi_biz_data WHERE id=" + multiRefBusinessDataInstance.getId()); + .queryForObject( + "SELECT TENANTID, ID, KIND, NAME, DATA_CLASSNAME, DATA_ID, PROC_INST_ID, FN_INST_ID FROM ref_biz_data_inst WHERE proc_inst_id=" + + PROCESS_INSTANCE_ID + + " AND name='myMultiProcData'", + new JdbcRowMapper("TENANTID", "ID", "DATA_ID", "PROC_INST_ID", "FN_INST_ID")); + List> dataIds = jdbcTemplate.query( + "SELECT ID, IDX, DATA_ID FROM multi_biz_data WHERE id=" + multiRefBusinessDataInstance.getId(), + new JdbcRowMapper("ID", "IDX", "DATA_ID")); assertThat(((SProcessMultiRefBusinessDataInstance) multiRefBusinessData).getDataIds()) .isEqualTo(Arrays.asList(23L, 25L, 27L)); @@ -893,9 +898,9 @@ public void should_save_and_get_multi_business_data_reference_for_process() { entry("PROC_INST_ID", PROCESS_INSTANCE_ID), entry("FN_INST_ID", null)); assertThat(dataIds).containsExactly( - mapOf(pair("ID", multiRefBusinessDataInstance.getId()), pair("IDX", 0), pair("DATA_ID", 23L)), - mapOf(pair("ID", multiRefBusinessDataInstance.getId()), pair("IDX", 1), pair("DATA_ID", 25L)), - mapOf(pair("ID", multiRefBusinessDataInstance.getId()), pair("IDX", 2), pair("DATA_ID", 27L))); + mapOf(pair("ID", multiRefBusinessDataInstance.getId()), pair("IDX", 0L), pair("DATA_ID", 23L)), + mapOf(pair("ID", multiRefBusinessDataInstance.getId()), pair("IDX", 1L), pair("DATA_ID", 25L)), + mapOf(pair("ID", multiRefBusinessDataInstance.getId()), pair("IDX", 2L), pair("DATA_ID", 27L))); } @Test @@ -911,9 +916,10 @@ public void should_save_and_get_single_business_data_reference_for_process() { PersistentObject singleRefFromQuery = repository.selectOne("getSRefBusinessDataInstance", pair("processInstanceId", PROCESS_INSTANCE_ID), pair("name", "mySingleData")); Map multiRefBusinessDataAsMap = jdbcTemplate - .queryForMap( + .queryForObject( "SELECT ID, KIND, NAME, DATA_CLASSNAME, DATA_ID, PROC_INST_ID, FN_INST_ID FROM ref_biz_data_inst WHERE proc_inst_id=" - + PROCESS_INSTANCE_ID + " AND name='mySingleData'"); + + PROCESS_INSTANCE_ID + " AND name='mySingleData'", + new JdbcRowMapper("ID", "DATA_ID", "PROC_INST_ID", "FN_INST_ID")); assertThat(singleRefFromQuery).isEqualTo(singleRef); assertThat(multiRefBusinessDataAsMap).containsOnly( entry("ID", singleRef.getId()), @@ -939,10 +945,11 @@ public void should_save_and_get_single_business_data_reference_for_flow_node() { PersistentObject singleRefFromQuery = repository.selectOne("getSFlowNodeRefBusinessDataInstance", pair("flowNodeInstanceId", FLOW_NODE_INSTANCE_ID), pair("name", "mySingleData")); Map multiRefBusinessDataAsMap = jdbcTemplate - .queryForMap( + .queryForObject( "SELECT ID, KIND, NAME, DATA_CLASSNAME, DATA_ID, PROC_INST_ID, FN_INST_ID FROM ref_biz_data_inst WHERE fn_inst_id=" + FLOW_NODE_INSTANCE_ID - + " AND name='mySingleData'"); + + " AND name='mySingleData'", + new JdbcRowMapper("ID", "DATA_ID", "PROC_INST_ID", "FN_INST_ID")); assertThat(singleRefFromQuery).isEqualTo(singleRef); assertThat(multiRefBusinessDataAsMap).containsOnly( entry("ID", singleRef.getId()), diff --git a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/SADataInstanceQueriesTest.java b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/SADataInstanceQueriesTest.java index 8e5bddc4220..80ad91c5972 100644 --- a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/SADataInstanceQueriesTest.java +++ b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/core/process/instance/model/SADataInstanceQueriesTest.java @@ -45,6 +45,7 @@ import org.bonitasoft.engine.data.instance.model.archive.SAShortTextDataInstance; import org.bonitasoft.engine.data.instance.model.archive.SAXMLObjectDataInstance; import org.bonitasoft.engine.persistence.PersistentObject; +import org.bonitasoft.engine.test.persistence.jdbc.JdbcRowMapper; import org.bonitasoft.engine.test.persistence.repository.SADataInstanceRepository; import org.junit.Test; import org.junit.runner.RunWith; @@ -95,11 +96,17 @@ private void addSADataInstance(final int id, final String name, final int contai } protected Map getDataUsingJDBC(SDataInstance dataInstance) { - return jdbcTemplate.queryForMap("SELECT * FROM data_instance where id = " + dataInstance.getId()); + return jdbcTemplate.queryForObject("SELECT * FROM data_instance where id = " + dataInstance.getId(), + new JdbcRowMapper(List.of("LONGVALUE"), + List.of("BOOLEANVALUE"), + List.of("DOUBLEVALUE"))); } protected Map getDataUsingJDBC(SADataInstance dataInstance) { - return jdbcTemplate.queryForMap("SELECT * FROM arch_data_instance where id = " + dataInstance.getId()); + return jdbcTemplate.queryForObject("SELECT * FROM arch_data_instance where id = " + dataInstance.getId(), + new JdbcRowMapper(List.of("LONGVALUE"), + List.of("BOOLEANVALUE"), + List.of("DOUBLEVALUE"))); } protected PersistentObject getDataInstance(String dataName) { @@ -185,7 +192,7 @@ public void should_save_and_get_SDoubleDataInstance() { assertThat(persistentObject).isEqualTo(dataInstance); assertThat(persistentObject).isInstanceOf(SDoubleDataInstance.class); - assertThat(dataAsMap).containsEntry("DOUBLEVALUE", 1234567890.0); + assertThat(dataAsMap).containsEntry("DOUBLEVALUE", 1234567890.0d); assertThat(dataAsMap).containsEntry("DISCRIMINANT", "SDoubleDataInstanceImpl"); } @@ -232,7 +239,7 @@ public void should_save_and_get_SDateDataInstance() { assertThat(persistentObject).isEqualTo(dataInstance); assertThat(persistentObject).isInstanceOf(SDateDataInstance.class); - assertThat(dataAsMap).containsEntry("LongValue", date.getTime()); + assertThat(dataAsMap).containsEntry("LONGVALUE", date.getTime()); assertThat(dataAsMap).containsEntry("DISCRIMINANT", "SDateDataInstanceImpl"); } @@ -263,7 +270,7 @@ public void should_save_and_get_SFloatDataInstance() { assertThat(persistentObject).isEqualTo(dataInstance); assertThat(persistentObject).isInstanceOf(SFloatDataInstance.class); - assertThat(dataAsMap.get("FLOATVALUE")).isEqualTo(1.0); + assertThat(((Number) dataAsMap.get("FLOATVALUE")).floatValue()).isEqualTo(1.0f); assertThat(dataAsMap).containsEntry("DISCRIMINANT", "SFloatDataInstanceImpl"); } @@ -323,7 +330,7 @@ public void should_save_and_get_SADoubleDataInstance() { assertThat(persistentObject).isEqualTo(dataInstance); assertThat(persistentObject).isInstanceOf(SADoubleDataInstance.class); - assertThat(dataAsMap).containsEntry("DOUBLEVALUE", 1234567890.0); + assertThat(dataAsMap).containsEntry("DOUBLEVALUE", 1234567890.0d); assertThat(dataAsMap).containsEntry("DISCRIMINANT", "SADoubleDataInstanceImpl"); } @@ -370,7 +377,7 @@ public void should_save_and_get_SADateDataInstance() { assertThat(persistentObject).isEqualTo(dataInstance); assertThat(persistentObject).isInstanceOf(SADateDataInstance.class); - assertThat(dataAsMap).containsEntry("LongValue", date.getTime()); + assertThat(dataAsMap).containsEntry("LONGVALUE", date.getTime()); assertThat(dataAsMap).containsEntry("DISCRIMINANT", "SADateDataInstanceImpl"); } @@ -400,7 +407,7 @@ public void should_save_and_get_SAFloatDataInstance() { assertThat(persistentObject).isEqualTo(dataInstance); assertThat(persistentObject).isInstanceOf(SAFloatDataInstance.class); - assertThat(dataAsMap.get("FLOATVALUE")).isEqualTo(1.0); + assertThat(((Number) dataAsMap.get("FLOATVALUE")).floatValue()).isEqualTo(1.0f); assertThat(dataAsMap).containsEntry("DISCRIMINANT", "SAFloatDataInstanceImpl"); } diff --git a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/parameter/ParameterTest.java b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/parameter/ParameterTest.java index 2f666aa26e8..a1e9db3d995 100644 --- a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/parameter/ParameterTest.java +++ b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/parameter/ParameterTest.java @@ -20,6 +20,7 @@ import java.util.Map; import org.bonitasoft.engine.persistence.PersistentObject; +import org.bonitasoft.engine.test.persistence.jdbc.JdbcRowMapper; import org.bonitasoft.engine.test.persistence.repository.TestRepository; import org.junit.Test; import org.junit.runner.RunWith; @@ -47,7 +48,8 @@ public void should_save_and_get_parameter() { pair("name", "parameterName"), pair("processDefinitionId", 12345L)); testRepository.flush(); Map parameterAsMap = jdbcTemplate - .queryForMap("SELECT * FROM proc_parameter WHERE name = 'parameterName'"); + .queryForObject("SELECT * FROM proc_parameter WHERE name = 'parameterName'", + new JdbcRowMapper("TENANTID", "ID", "PROCESS_ID")); assertThat(parameterFromQuery).isEqualTo(sParameter); assertThat(parameterAsMap).containsOnly( diff --git a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/platform/command/model/PlatformCommandTest.java b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/platform/command/model/PlatformCommandTest.java index 6a98299d401..77bbfe1796d 100644 --- a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/platform/command/model/PlatformCommandTest.java +++ b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/platform/command/model/PlatformCommandTest.java @@ -20,6 +20,7 @@ import java.util.Map; import org.bonitasoft.engine.persistence.PersistentObject; +import org.bonitasoft.engine.test.persistence.jdbc.JdbcRowMapper; import org.bonitasoft.engine.test.persistence.repository.PlatformRepository; import org.junit.Test; import org.junit.runner.RunWith; @@ -50,7 +51,8 @@ public void should_save_and_get_SPlatformCommand() { PersistentObject platformCommandFromQuery = repository.selectOneOnPlatform("getPlatformCommandByName", pair("name", "myPlatformCommand")); - Map platformCommandAsMap = jdbcTemplate.queryForMap("SELECT * FROM platformCommand"); + Map platformCommandAsMap = jdbcTemplate.queryForObject("SELECT * FROM platformCommand", + new JdbcRowMapper("ID")); assertThat(platformCommandFromQuery).isEqualTo(platformCommand); assertThat(platformCommandAsMap).containsOnly( diff --git a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/platform/model/impl/PlatformTest.java b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/platform/model/impl/PlatformTest.java index 49711c0358a..79619c74c2e 100644 --- a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/platform/model/impl/PlatformTest.java +++ b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/platform/model/impl/PlatformTest.java @@ -16,10 +16,12 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; +import java.util.List; import java.util.Map; import org.bonitasoft.engine.persistence.PersistentObject; import org.bonitasoft.engine.platform.model.SPlatform; +import org.bonitasoft.engine.test.persistence.jdbc.JdbcRowMapper; import org.bonitasoft.engine.test.persistence.repository.PlatformRepository; import org.junit.Test; import org.junit.runner.RunWith; @@ -52,7 +54,8 @@ public void should_save_and_get_SPlatform() { repository.flush(); PersistentObject platformFromQuery = repository.selectOneOnPlatform("getPlatform"); - Map platformAsMap = jdbcTemplate.queryForMap("SELECT * FROM platform"); + Map platformAsMap = jdbcTemplate.queryForObject("SELECT * FROM platform", + new JdbcRowMapper(List.of("ID", "CREATED"), List.of("MAINTENANCE_MESSAGE_ACTIVE"))); assertThat(platformFromQuery).isEqualTo(platform); assertThat(platformAsMap).containsOnly( diff --git a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/queriablelogger/model/QueriableLogParameterTest.java b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/queriablelogger/model/QueriableLogParameterTest.java index 18014016001..ad8106896a9 100644 --- a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/queriablelogger/model/QueriableLogParameterTest.java +++ b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/queriablelogger/model/QueriableLogParameterTest.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.Map; +import org.bonitasoft.engine.test.persistence.jdbc.JdbcRowMapper; import org.bonitasoft.engine.test.persistence.repository.TestRepository; import org.junit.Test; import org.junit.runner.RunWith; @@ -64,7 +65,8 @@ public void should_be_able_to_add_querriable_log() { testRepository.flush(); - List> queriableLogs = jdbcTemplate.queryForList("SELECT * from queriableLog_p"); + List> queriableLogs = jdbcTemplate.query("SELECT * from queriableLog_p", + new JdbcRowMapper("ID", "TENANTID", "B_LOG_ID")); assertThat(queriableLogs).hasSize(2); assertThat(queriableLogs.stream().filter(m -> m.get("ID").equals(1L)).findFirst().get()).containsOnly( diff --git a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/queriablelogger/model/QueriableLogTest.java b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/queriablelogger/model/QueriableLogTest.java index 15cb018d913..9c043a401b3 100644 --- a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/queriablelogger/model/QueriableLogTest.java +++ b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/queriablelogger/model/QueriableLogTest.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.Map; +import org.bonitasoft.engine.test.persistence.jdbc.JdbcRowMapper; import org.bonitasoft.engine.test.persistence.repository.TestRepository; import org.junit.Test; import org.junit.runner.RunWith; @@ -39,7 +40,7 @@ public class QueriableLogTest { private JdbcTemplate jdbcTemplate; @Test - public void should_be_able_to_add_querriable_log() { + public void should_be_able_to_add_queriable_log() { SQueriableLog queriableLog = SQueriableLog.builder() .initializeNow()// @@ -74,7 +75,9 @@ public void should_be_able_to_add_querriable_log() { testRepository.flush(); - List> queriableLogs = jdbcTemplate.queryForList("SELECT * from queriable_log"); + List> queriableLogs = jdbcTemplate.query("SELECT * from queriable_log", + new JdbcRowMapper("ID", "TENANTID", "NUMERICINDEX1", "NUMERICINDEX2", "NUMERICINDEX3", + "NUMERICINDEX4", "NUMERICINDEX5", "THREADNUMBER", "LOG_TIMESTAMP")); assertThat(queriableLogs).hasSize(2); assertThat(queriableLogs.stream().filter(m -> m.get("ID").equals(1L)).findFirst().get()).containsOnly( diff --git a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/resources/DependencyServiceQueriesTest.java b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/resources/DependencyServiceQueriesTest.java index 2d3993acabd..234b5f1be60 100644 --- a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/resources/DependencyServiceQueriesTest.java +++ b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/resources/DependencyServiceQueriesTest.java @@ -23,8 +23,13 @@ import java.util.Map; import java.util.Random; -import org.bonitasoft.engine.dependency.model.*; +import org.bonitasoft.engine.dependency.model.DependencyContent; +import org.bonitasoft.engine.dependency.model.SDependency; +import org.bonitasoft.engine.dependency.model.SDependencyMapping; +import org.bonitasoft.engine.dependency.model.SPlatformDependency; +import org.bonitasoft.engine.dependency.model.SPlatformDependencyMapping; import org.bonitasoft.engine.persistence.PersistentObject; +import org.bonitasoft.engine.test.persistence.jdbc.JdbcRowMapper; import org.bonitasoft.engine.test.persistence.repository.DependencyRepository; import org.bonitasoft.engine.test.persistence.repository.PlatformRepository; import org.junit.Test; @@ -134,7 +139,8 @@ public void should_save_and_get_dependency() { PersistentObject dependencyFromQuery = repository.selectOne("getDependencyByName", pair("name", "dependencyName")); - Map dependencyAsMap = jdbcTemplate.queryForMap("SELECT * FROM dependency"); + Map dependencyAsMap = jdbcTemplate.queryForObject("SELECT * FROM dependency", + new JdbcRowMapper("TENANTID", "ID")); assertThat(dependencyFromQuery).isEqualTo(aDependency); assertThat(dependencyAsMap).containsOnly( @@ -161,7 +167,8 @@ public void should_save_and_get_dependency_mapping() { PersistentObject dependencyMappingFromQuery = repository.selectOne("getDependencyMappingsByDependency", pair("dependencyId", aDependency.getId())); Map dependencyMappingAsMap = jdbcTemplate - .queryForMap("SELECT * FROM dependencymapping WHERE dependencyId=" + aDependency.getId()); + .queryForObject("SELECT * FROM dependencymapping WHERE dependencyId=" + aDependency.getId(), + new JdbcRowMapper("TENANTID", "ID", "ARTIFACTID", "DEPENDENCYID")); assertThat(dependencyMappingFromQuery).isEqualTo(dependencyMapping); assertThat(dependencyMappingAsMap).containsOnly( @@ -182,9 +189,11 @@ public void should_save_and_get_platform_dependency() { PersistentObject dependencyFromQuery = platformRepository.selectOneOnPlatform("getPlatformDependencyByName", pair("name", "dependencyName")); - Map dependencyAsMap = jdbcTemplate.queryForMap("SELECT * FROM pdependency"); + Map dependencyAsMap = jdbcTemplate.queryForObject("SELECT * FROM pdependency", + new JdbcRowMapper("ID")); assertThat(dependencyFromQuery).isEqualTo(aDependency); + assertThat(dependencyAsMap).containsOnly( entry("ID", aDependency.getId()), entry("NAME", "dependencyName"), @@ -208,7 +217,8 @@ public void should_save_and_get_platform_dependency_mapping() { PersistentObject dependencyMappingFromQuery = platformRepository.selectOneOnPlatform( "getPlatformDependencyMappingsByDependency", pair("dependencyId", aDependency.getId())); Map dependencyMappingAsMap = jdbcTemplate - .queryForMap("SELECT * FROM pdependencymapping WHERE dependencyId=" + aDependency.getId()); + .queryForObject("SELECT * FROM pdependencymapping WHERE dependencyId=" + aDependency.getId(), + new JdbcRowMapper("ID", "ARTIFACTID", "DEPENDENCYID")); assertThat(dependencyMappingFromQuery).isEqualTo(dependencyMapping); assertThat(dependencyMappingAsMap).containsOnly( diff --git a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/scheduler/SchedulerQueryTest.java b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/scheduler/SchedulerQueryTest.java index 59a72922e48..1176a394d86 100644 --- a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/scheduler/SchedulerQueryTest.java +++ b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/scheduler/SchedulerQueryTest.java @@ -28,6 +28,7 @@ import org.bonitasoft.engine.scheduler.model.SJobDescriptor; import org.bonitasoft.engine.scheduler.model.SJobLog; import org.bonitasoft.engine.scheduler.model.SJobParameter; +import org.bonitasoft.engine.test.persistence.jdbc.JdbcRowMapper; import org.bonitasoft.engine.test.persistence.repository.JobRepository; import org.hibernate.internal.util.SerializationHelper; import org.junit.Test; @@ -96,7 +97,8 @@ public void should_save_and_get_SJobDescriptor() { Long numberOfSJobDescriptor = jobRepository.selectCount("getNumberOfSJobDescriptor"); PersistentObject searchSJobDescriptor = jobRepository.selectOne("searchSJobDescriptor"); - Map jobDescriptorAsMap = jdbcTemplate.queryForMap("SELECT * FROM job_desc"); + Map jobDescriptorAsMap = jdbcTemplate.queryForObject("SELECT * FROM job_desc", + new JdbcRowMapper("TENANTID", "ID")); assertThat(numberOfSJobDescriptor).isEqualTo(1); assertThat(searchSJobDescriptor).isEqualTo(jobDescriptor); @@ -119,7 +121,8 @@ public void should_save_and_get_SJobParameter() { Long numberOfSJobParameters = jobRepository.selectCount("getNumberOfSJobParameter"); PersistentObject jobParameterFromQuery = jobRepository.selectOne("getJobParameters", pair("jobDescriptorId", 1234L)); - Map jobParameterAsMap = jdbcTemplate.queryForMap("SELECT * FROM job_param"); + Map jobParameterAsMap = jdbcTemplate.queryForObject("SELECT * FROM job_param", + new JdbcRowMapper("TENANTID", "ID", "JOBDESCRIPTORID")); assertThat(numberOfSJobParameters).isEqualTo(1); assertThat(jobParameterFromQuery).isEqualTo(jobParameter); @@ -143,7 +146,8 @@ public void should_save_and_get_SJobLog() { Long numberOfSJobLog = jobRepository.selectCount("getNumberOfSJobLog"); PersistentObject jobLogFromQuery = jobRepository.selectOne("searchSJobLog"); - Map jobLogAsMap = jdbcTemplate.queryForMap("SELECT * FROM job_log"); + Map jobLogAsMap = jdbcTemplate.queryForObject("SELECT * FROM job_log", + new JdbcRowMapper("TENANTID", "ID", "JOBDESCRIPTORID", "RETRYNUMBER", "LASTUPDATEDATE")); assertThat(numberOfSJobLog).isEqualTo(1); assertThat(jobLogFromQuery).isEqualTo(jobLog); diff --git a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/temporary/content/TemporaryContentQueryTest.java b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/temporary/content/TemporaryContentQueryTest.java index 240b74abfd2..5bcd21fbb91 100644 --- a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/temporary/content/TemporaryContentQueryTest.java +++ b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/temporary/content/TemporaryContentQueryTest.java @@ -24,7 +24,6 @@ import java.sql.Blob; import java.sql.SQLException; -import org.apache.commons.io.IOUtils; import org.bonitasoft.engine.test.persistence.repository.TemporaryContentRepository; import org.junit.Test; import org.junit.runner.RunWith; @@ -64,8 +63,9 @@ public void shouldStoreStream() throws IOException, SQLException { InputStream uploadedFileStream = savedTemporaryContent.getContent().getBinaryStream(); assertThat(savedTemporaryContent.getFileName()).isEqualTo(temporaryContent.getFileName()); assertThat(savedTemporaryContent.getMimeType()).isEqualTo(temporaryContent.getMimeType()); - assertThat(tempFilePath.toFile().length()).isEqualTo(uploadedFileStream.available()); - assertArrayEquals(IOUtils.toByteArray(uploadedFileStream), "test".getBytes()); + final byte[] contentByteArray = uploadedFileStream.readAllBytes(); + assertThat(tempFilePath.toFile().length()).isEqualTo(contentByteArray.length); + assertArrayEquals(contentByteArray, "test".getBytes()); } @Test diff --git a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/test/persistence/TestLocalSessionFactoryBuilder.java b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/test/persistence/TestLocalSessionFactoryBuilder.java index 8162abeef96..2126bbc4703 100644 --- a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/test/persistence/TestLocalSessionFactoryBuilder.java +++ b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/test/persistence/TestLocalSessionFactoryBuilder.java @@ -13,37 +13,46 @@ **/ package org.bonitasoft.engine.test.persistence; -import org.bonitasoft.engine.persistence.*; +import org.bonitasoft.engine.persistence.PostgresMaterializedBlobType; +import org.bonitasoft.engine.persistence.PostgresMaterializedClobType; +import org.bonitasoft.engine.persistence.PostgresXMLType; +import org.bonitasoft.engine.persistence.XMLType; import org.bonitasoft.engine.services.Vendor; +import org.hibernate.Interceptor; import org.hibernate.SessionFactory; import org.springframework.orm.hibernate5.LocalSessionFactoryBean; import org.springframework.orm.hibernate5.LocalSessionFactoryBuilder; public class TestLocalSessionFactoryBuilder extends LocalSessionFactoryBean { + private Interceptor interceptor; + @Override protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) { Vendor vendor = Vendor.fromHibernateConfiguration(sfb); //register type before loading mappings/entities, type should be present before loading JPA entities switch (vendor) { - case ORACLE: - sfb.setInterceptor(new OracleInterceptor()); - break; - case MYSQL: - case OTHER: + case ORACLE, OTHER, SQLSERVER: sfb.registerTypeOverride(XMLType.INSTANCE); break; - case SQLSERVER: - sfb.setInterceptor(new SQLServerInterceptor()); + case MYSQL: + System.setProperty("hibernate.dialect.storage_engine", "innodb"); sfb.registerTypeOverride(XMLType.INSTANCE); break; case POSTGRES: - sfb.setInterceptor(new PostgresInterceptor()); sfb.registerTypeOverride(new PostgresMaterializedBlobType()); sfb.registerTypeOverride(new PostgresMaterializedClobType()); sfb.registerTypeOverride(PostgresXMLType.INSTANCE); break; - }; + } + if (interceptor != null) { + sfb.setInterceptor(interceptor); + } return super.buildSessionFactory(sfb); } + + public void setInterceptor(Interceptor interceptor) { + this.interceptor = interceptor; + } + } diff --git a/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/test/persistence/jdbc/JdbcRowMapper.java b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/test/persistence/jdbc/JdbcRowMapper.java new file mode 100644 index 00000000000..fc86a561f15 --- /dev/null +++ b/bonita-integration-tests/bonita-query-tests/src/test/java/org/bonitasoft/engine/test/persistence/jdbc/JdbcRowMapper.java @@ -0,0 +1,150 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.engine.test.persistence.jdbc; + +import java.sql.Blob; +import java.sql.Clob; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.jdbc.core.RowMapper; + +/** + * Spring JDBC RowMapper that converts column names and values as Hibernate woulds: + *
    + *
  • converts column names to upper case so that tests can assert on column name whatever the DB vendor
  • + *
  • converts some column values to long, double, int or boolean if needed, notably on Oracle where types seem to be + * harder to detect
  • + *
  • converts Clob and Blob to String and byte[] respectively
  • + *
+ * + * @author Emmanuel Duchastenier + */ +@Slf4j +public class JdbcRowMapper implements RowMapper> { + + private final String dbVendor = System.getProperty("sysprop.bonita.db.vendor", "h2"); + + private List columnsToConvertToLong = new ArrayList<>(); // column names must be upper case + private List columnsToConvertToBoolean = new ArrayList<>(); // column names must be upper case + private List columnsToConvertToDouble = new ArrayList<>(); // column names must be upper case + + private final Map converters = Map.of( + "h2", new DefaultValueConverter(), + "postgres", new DefaultValueConverter(), + "mysql", new DefaultValueConverter(), + "sqlserver", new DefaultValueConverter(), + "oracle", new OracleValueConverter()); + + public JdbcRowMapper() { + log.info("Detected DB vendor: {}", dbVendor); + } + + /** + * @param columnsToConvertToLong column names must be upper case + */ + public JdbcRowMapper(String... columnsToConvertToLong) { + this(); + this.columnsToConvertToLong.addAll(List.of(columnsToConvertToLong)); + } + + /** + * @param columnsToConvertToLong column names must be upper case + * @param columnsToConvertToBoolean column names must be upper case + */ + public JdbcRowMapper(List columnsToConvertToLong, List columnsToConvertToBoolean) { + this(); + this.columnsToConvertToLong = columnsToConvertToLong; + this.columnsToConvertToBoolean = columnsToConvertToBoolean; + } + + public JdbcRowMapper(List columnsToConvertToLong, List columnsToConvertToBoolean, + List columnsToConvertToDouble) { + this(columnsToConvertToLong, columnsToConvertToBoolean); + this.columnsToConvertToDouble = columnsToConvertToDouble; + } + + @Override + public Map mapRow(ResultSet rs, int rowNum) throws SQLException { + Map result = new HashMap<>(); + int columnCount = rs.getMetaData().getColumnCount(); + for (int i = 1; i <= columnCount; i++) { + final Object object = rs.getObject(i); + Object value = converters.get(dbVendor).getValue(rs, object, i); + result.put(rs.getMetaData().getColumnName(i).toUpperCase(), value); + } + return result; + } + + @FunctionalInterface + public interface JdbcValueConverter { + + Object getValue(ResultSet resultSet, Object object, int rowNum) throws SQLException; + } + + class DefaultValueConverter implements JdbcValueConverter { + + @Override + public Object getValue(ResultSet rs, Object object, int columnNumber) throws SQLException { + if (object == null) { + return null; + } + + if (object instanceof Clob) { + final Clob clob = rs.getClob(columnNumber); + return clob.getSubString(1, (int) clob.length()); + } + if (object instanceof Blob) { + final Blob blob = rs.getBlob(columnNumber); + return blob.getBytes(1, (int) blob.length()); + } + + // if value must be converted to double, let's do it: + final String upperCaseColumnName = rs.getMetaData().getColumnName(columnNumber).toUpperCase(); + if (columnsToConvertToDouble.contains(upperCaseColumnName)) { + return ((Number) object).doubleValue(); + } + // if value must be converted to long, let's do it: + if (columnsToConvertToLong.contains(upperCaseColumnName)) { + return ((Number) object).longValue(); + } else if (object instanceof Number) { + // if value can be converted to int, let's do it: + try { + return ((Number) object).intValue(); + } catch (Exception ignored) { + } + } + return object; + } + } + + class OracleValueConverter extends DefaultValueConverter { + + @Override + public Object getValue(ResultSet rs, Object object, int columnNumber) throws SQLException { + if (object != null + && columnsToConvertToBoolean.contains(rs.getMetaData().getColumnName(columnNumber).toUpperCase())) { + return "1".equals(rs.getString(columnNumber)); + } else { + return super.getValue(rs, object, columnNumber); + } + } + } + +} diff --git a/bonita-integration-tests/bonita-query-tests/src/test/resources/datasource/datasource-dependency-h2.xml b/bonita-integration-tests/bonita-query-tests/src/test/resources/datasource/datasource-dependency-h2.xml new file mode 100644 index 00000000000..0b4f6a71019 --- /dev/null +++ b/bonita-integration-tests/bonita-query-tests/src/test/resources/datasource/datasource-dependency-h2.xml @@ -0,0 +1,20 @@ + + + + + + org.hibernate.dialect.H2Dialect + org.h2.jdbcx.JdbcDataSource + jdbc:h2:mem:bonita;DB_CLOSE_ON_EXIT=FALSE;AUTOCOMMIT=OFF;IGNORECASE=TRUE;DATABASE_TO_LOWER=TRUE; + sa + + + + + + + + diff --git a/bonita-integration-tests/bonita-query-tests/src/test/resources/datasource/datasource-dependency-postgres.xml b/bonita-integration-tests/bonita-query-tests/src/test/resources/datasource/datasource-dependency-postgres.xml new file mode 100644 index 00000000000..2cccb4d6acc --- /dev/null +++ b/bonita-integration-tests/bonita-query-tests/src/test/resources/datasource/datasource-dependency-postgres.xml @@ -0,0 +1,24 @@ + + + + + + + org.hibernate.dialect.PostgreSQL10Dialect + org.postgresql.xa.PGXADataSource + localhost + 5432 + bonita + bonita + bonita + jdbc:postgresql://${db.server.name}:${db.server.port}/${db.database.name} + + + + + + + diff --git a/bonita-integration-tests/bonita-query-tests/src/test/resources/testContext.xml b/bonita-integration-tests/bonita-query-tests/src/test/resources/testContext.xml index 9d1b4b34326..80ccbf83c56 100644 --- a/bonita-integration-tests/bonita-query-tests/src/test/resources/testContext.xml +++ b/bonita-integration-tests/bonita-query-tests/src/test/resources/testContext.xml @@ -1,24 +1,31 @@ - + + + + + + + + + + + @@ -210,7 +217,6 @@ /org/bonitasoft/engine/platform/model/impl/hibernate/platform.queries.hbm.xml org/bonitasoft/engine/platform/command/model/impl/hibernate/platformCommand.queries.hbm.xml - /org/bonitasoft/engine/core/process/instance/model/impl/hibernate/archived.process.instance.queries.hbm.xml /org/bonitasoft/engine/page/impl/hibernate/page.queries.hbm.xml @@ -235,7 +241,7 @@ create-drop - org.hibernate.dialect.H2Dialect + ${db.hibernate.dialect} false false false diff --git a/bonita-integration-tests/bonita-test-utils/build.gradle b/bonita-integration-tests/bonita-test-utils/build.gradle index def2e8f8d5a..b1c1211e1a5 100644 --- a/bonita-integration-tests/bonita-test-utils/build.gradle +++ b/bonita-integration-tests/bonita-test-utils/build.gradle @@ -2,10 +2,13 @@ dependencies { api project(':bpm:bonita-client') api project(':bpm:bonita-common') api project(':bonita-test-api') - api libs.junit4 api libs.commonsIO api libs.xmlunit api libs.assertj + + implementation project(':bpm:bonita-core:bonita-process-engine') + implementation libs.junit4 + implementation libs.springTest } publishing { diff --git a/bonita-integration-tests/bonita-test-utils/src/main/java/org/bonitasoft/engine/test/APITestUtil.java b/bonita-integration-tests/bonita-test-utils/src/main/java/org/bonitasoft/engine/test/APITestUtil.java index 77e7167dbf8..dcdde98dfa5 100644 --- a/bonita-integration-tests/bonita-test-utils/src/main/java/org/bonitasoft/engine/test/APITestUtil.java +++ b/bonita-integration-tests/bonita-test-utils/src/main/java/org/bonitasoft/engine/test/APITestUtil.java @@ -47,6 +47,7 @@ import org.bonitasoft.engine.api.ProcessAPI; import org.bonitasoft.engine.api.ProfileAPI; import org.bonitasoft.engine.api.TenantAdministrationAPI; +import org.bonitasoft.engine.api.platform.PlatformInformationAPI; import org.bonitasoft.engine.bdm.model.BusinessObject; import org.bonitasoft.engine.bdm.model.BusinessObjectModel; import org.bonitasoft.engine.bdm.model.Query; @@ -94,7 +95,7 @@ import org.bonitasoft.engine.bpm.process.impl.ProcessDefinitionBuilder; import org.bonitasoft.engine.bpm.supervisor.ProcessSupervisor; import org.bonitasoft.engine.bpm.supervisor.ProcessSupervisorSearchDescriptor; -import org.bonitasoft.engine.business.application.Application; +import org.bonitasoft.engine.business.application.IApplication; import org.bonitasoft.engine.command.CommandDescriptor; import org.bonitasoft.engine.command.CommandExecutionException; import org.bonitasoft.engine.command.CommandNotFoundException; @@ -1033,9 +1034,15 @@ public void waitForProcessToBeInState(final ProcessInstance processInstance, fin public void waitForProcessToBeInState(final long processInstanceId, final ProcessInstanceState state) throws Exception { + waitForProcessToBeInState(processInstanceId, state, DEFAULT_TIMEOUT); + } + + public void waitForProcessToBeInState(final long processInstanceId, final ProcessInstanceState state, + final int timeoutInMillis) + throws Exception { ClientEventUtil.executeWaitServerCommand(getCommandAPI(), ClientEventUtil.getProcessInstanceInState(processInstanceId, state.getId()), - DEFAULT_TIMEOUT); + timeoutInMillis); } public void waitForInitializingProcess() throws Exception { @@ -1046,7 +1053,7 @@ public void waitForInitializingProcess() throws Exception { private Long waitForFlowNode(final long processInstanceId, final TestStates state, final String flowNodeName, final boolean useRootProcessInstance, - final int timeout) throws Exception { + final int timeoutInMillis) throws Exception { Map params; if (useRootProcessInstance) { params = ClientEventUtil.getFlowNodeInState(processInstanceId, state.getStateName(), flowNodeName); @@ -1054,7 +1061,7 @@ private Long waitForFlowNode(final long processInstanceId, final TestStates stat params = ClientEventUtil.getFlowNodeInStateWithParentId(processInstanceId, state.getStateName(), flowNodeName); } - return ClientEventUtil.executeWaitServerCommand(getCommandAPI(), params, timeout); + return ClientEventUtil.executeWaitServerCommand(getCommandAPI(), params, timeoutInMillis); } public FlowNodeInstance waitForFlowNodeInReadyState(final ProcessInstance processInstance, @@ -1355,13 +1362,11 @@ protected void cleanCategories() throws DeletionException { protected void cleanProcessDefinitions() throws BonitaException { final List processes = getProcessAPI().getProcessDeploymentInfos(0, 200, ProcessDeploymentInfoCriterion.DEFAULT); - if (processes.size() > 0) { - for (final ProcessDeploymentInfo processDeploymentInfo : processes) { - if (ActivationState.ENABLED.equals(processDeploymentInfo.getActivationState())) { - getProcessAPI().disableProcess(processDeploymentInfo.getProcessId()); - } - getProcessAPI().deleteProcessDefinition(processDeploymentInfo.getProcessId()); + for (final ProcessDeploymentInfo processDeploymentInfo : processes) { + if (ActivationState.ENABLED.equals(processDeploymentInfo.getActivationState())) { + getProcessAPI().disableProcess(processDeploymentInfo.getProcessId()); } + getProcessAPI().deleteProcessDefinition(processDeploymentInfo.getProcessId()); } } @@ -1370,17 +1375,15 @@ protected void cleanSupervisors() throws SearchException, DeletionException { builder.sort(ProcessSupervisorSearchDescriptor.ID, Order.ASC); final List supervisors = getProcessAPI().searchProcessSupervisors(builder.done()) .getResult(); - if (supervisors.size() > 0) { - for (final ProcessSupervisor supervisor : supervisors) { - getProcessAPI().deleteSupervisor(supervisor.getSupervisorId()); - } + for (final ProcessSupervisor supervisor : supervisors) { + getProcessAPI().deleteSupervisor(supervisor.getSupervisorId()); } } protected void cleanApplications() throws SearchException, DeletionException { - final SearchResult applications = getApplicationAPI() - .searchApplications(new SearchOptionsBuilder(0, 100).done()); - for (Application application : applications.getResult()) { + final SearchResult applications = getApplicationAPI() + .searchIApplications(new SearchOptionsBuilder(0, 100).done()); + for (IApplication application : applications.getResult()) { if (application.isEditable()) { getApplicationAPI().deleteApplication(application.getId()); } @@ -1463,6 +1466,10 @@ protected void cleanCommands() throws SearchException, CommandNotFoundException, } } + public PlatformInformationAPI getPlatformInformationAPI() { + return getApiClient().getPlatformInformationAPI(); + } + public ProcessAPI getProcessAPI() { return getApiClient().getProcessAPI(); } diff --git a/bonita-integration-tests/bonita-test-utils/src/main/java/org/bonitasoft/engine/test/EventUtil.java b/bonita-integration-tests/bonita-test-utils/src/main/java/org/bonitasoft/engine/test/EventUtil.java deleted file mode 100644 index cecd29a0fdb..00000000000 --- a/bonita-integration-tests/bonita-test-utils/src/main/java/org/bonitasoft/engine/test/EventUtil.java +++ /dev/null @@ -1,152 +0,0 @@ -/** - * Copyright (C) 2019 Bonitasoft S.A. - * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble - * This library is free software; you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Foundation - * version 2.1 of the License. - * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * You should have received a copy of the GNU Lesser General Public License along with this - * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth - * Floor, Boston, MA 02110-1301, USA. - **/ -package org.bonitasoft.engine.test; - -import java.io.IOException; -import java.io.Serializable; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeoutException; - -import org.bonitasoft.engine.api.CommandAPI; -import org.bonitasoft.engine.api.TenantAPIAccessor; -import org.bonitasoft.engine.command.CommandExecutionException; -import org.bonitasoft.engine.command.CommandNotFoundException; -import org.bonitasoft.engine.command.CommandParameterizationException; -import org.bonitasoft.engine.exception.BonitaException; -import org.bonitasoft.engine.exception.RetrieveException; -import org.bonitasoft.engine.io.IOUtil; -import org.bonitasoft.engine.session.APISession; - -/** - * Utility methods to get maps that match process as wanted - * - * @author Baptiste Mesta - */ -public class EventUtil { - - private static final String FLOW_NODE = "flowNode"; - - private static final String PROCESS = "process"; - - private static final String TYPE = "type"; - - private static final String NAME = "name"; - - private static final String ROOT_CONTAINER_ID = "rootContainerId"; - - private static final String PARENT_CONTAINER_ID = "parentContainerId"; - - private static final String STATE_ID = "stateId"; - - private static final String ID = "id"; - - private static final String STATE = "state"; - - public static Map getReadyTaskEvent(final long processInstanceId, final String taskName) { - final Map map = new HashMap(5); - map.put(TYPE, FLOW_NODE); - map.put(ROOT_CONTAINER_ID, processInstanceId); - map.put(NAME, taskName); - map.put(STATE_ID, 4); - return map; - } - - public static Map getProcessInstanceFinishedEvent(final long processInstanceId) { - final Map map = new HashMap(4); - map.put(TYPE, PROCESS); - map.put(ID, processInstanceId); - map.put(STATE_ID, 6); - return map; - } - - public static void undeployCommand(final APISession apiSession) throws BonitaException { - final CommandAPI commandAPI = TenantAPIAccessor.getCommandAPI(apiSession); - commandAPI.unregister("waitServerCommand"); - commandAPI.removeDependency("commands"); - } - - public static void deployCommand(final APISession apiSession) throws BonitaException { - final CommandAPI commandAPI = TenantAPIAccessor.getCommandAPI(apiSession); - - byte[] commandJar; - try { - commandJar = IOUtil.getAllContentFrom(APITestUtil.class.getResourceAsStream("/server-command.bak")); - } catch (final IOException e) { - throw new RetrieveException(e); - } - commandAPI.addDependency("commands", commandJar); - - commandAPI.register("waitServerCommand", "waitServerCommand", - "org.bonitasoft.engine.test.synchro.WaitServerCommand"); - commandAPI.register("addHandlerCommand", "addHandlerCommand", - "org.bonitasoft.engine.test.synchro.AddHandlerCommand"); - - final Map parameters = Collections.emptyMap(); - commandAPI.execute("addHandlerCommand", parameters); - } - - static Long executeWaitServerCommand(final CommandAPI commandAPI, final Map event, - final int defaultTimeout) - throws CommandNotFoundException, CommandParameterizationException, CommandExecutionException, - TimeoutException { - final Map parameters = new HashMap(2); - parameters.put("event", (Serializable) event); - parameters.put("timeout", defaultTimeout); - try { - return (Long) commandAPI.execute("waitServerCommand", parameters); - } catch (final CommandExecutionException e) { - if (e.getMessage().toLowerCase().contains("timeout")) { - throw new TimeoutException("Timeout (" + defaultTimeout + "ms)looking for element: " + event); - } - throw e; - } - } - - public static void clearRepo(final CommandAPI commandAPI) throws BonitaException { - final Map parameters = new HashMap(); - parameters.put("clear", true); - commandAPI.execute("waitServerCommand", parameters); - } - - public static Map getTaskInState(final long processInstanceId, final String stateName) { - final Map map = new HashMap(3); - map.put(TYPE, FLOW_NODE); - map.put(ROOT_CONTAINER_ID, processInstanceId); - map.put(STATE, stateName); - return map; - } - - public static Map getTaskInState(final long processInstanceId, final String state, - final String flowNodeName) { - final Map map = new HashMap(3); - map.put(TYPE, FLOW_NODE); - map.put(ROOT_CONTAINER_ID, processInstanceId); - map.put(STATE, state); - map.put(NAME, flowNodeName); - return map; - } - - public static Map getTaskInStateWithParentId(final long processInstanceId, final String state, - final String flowNodeName) { - final Map map = new HashMap(3); - map.put(TYPE, FLOW_NODE); - map.put(PARENT_CONTAINER_ID, processInstanceId); - map.put(STATE, state); - map.put(NAME, flowNodeName); - return map; - } - -} diff --git a/bonita-integration-tests/bonita-test-utils/src/main/java/org/bonitasoft/engine/test/PlatformTestUtil.java b/bonita-integration-tests/bonita-test-utils/src/main/java/org/bonitasoft/engine/test/PlatformTestUtil.java index 90c86e66b8a..7ab58df7664 100644 --- a/bonita-integration-tests/bonita-test-utils/src/main/java/org/bonitasoft/engine/test/PlatformTestUtil.java +++ b/bonita-integration-tests/bonita-test-utils/src/main/java/org/bonitasoft/engine/test/PlatformTestUtil.java @@ -23,11 +23,16 @@ import org.bonitasoft.engine.exception.BonitaHomeNotSetException; import org.bonitasoft.engine.exception.ServerAPIException; import org.bonitasoft.engine.exception.UnknownAPITypeException; +import org.bonitasoft.engine.execution.ProcessStarterVerifier; import org.bonitasoft.engine.session.PlatformSession; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.ContextConfiguration; /** * @author Celine Souchet */ +@ContextConfiguration(classes = PlatformTestUtil.TestConfiguration.class) public class PlatformTestUtil { public static final String DEFAULT_TECHNICAL_LOGGER_USERNAME = "install"; @@ -72,4 +77,17 @@ public void deployCommandsOnDefaultTenant() throws BonitaException { apiClient.logout(); } + /** + * Configuration class used to override bean definitions for test purposes. + */ + @Configuration + static class TestConfiguration { + + @Bean + ProcessStarterVerifier processStarterVerifierImpl() { + return processInstance -> { + // Override this bean to disable the process starter verifier + }; + } + } } diff --git a/bonita-test-api/build.gradle b/bonita-test-api/build.gradle index 734b8ece093..2e6c5a18a39 100644 --- a/bonita-test-api/build.gradle +++ b/bonita-test-api/build.gradle @@ -4,6 +4,8 @@ dependencies { api libs.junit4 api(project(':platform:platform-resources')) + implementation libs.springTest + // for http tests: compileOnly(libs.jettyServer) compileOnly(libs.jettyServlet) diff --git a/bonita-test-api/src/main/java/org/bonitasoft/engine/test/TestEngineImpl.java b/bonita-test-api/src/main/java/org/bonitasoft/engine/test/TestEngineImpl.java index 80b4d0c8815..196c98cfa37 100644 --- a/bonita-test-api/src/main/java/org/bonitasoft/engine/test/TestEngineImpl.java +++ b/bonita-test-api/src/main/java/org/bonitasoft/engine/test/TestEngineImpl.java @@ -16,15 +16,21 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.bonitasoft.engine.BonitaDatabaseConfiguration; +import org.bonitasoft.engine.execution.ProcessStarterVerifier; import org.bonitasoft.engine.test.http.BonitaHttpServer; import org.bonitasoft.engine.test.internal.EngineCommander; import org.bonitasoft.engine.test.internal.EngineStarter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.test.context.ContextConfiguration; /** * @author Baptiste Mesta */ @Getter @Slf4j +@ContextConfiguration(classes = TestEngineImpl.TestConfiguration.class) public class TestEngineImpl implements TestEngine { private static TestEngineImpl INSTANCE = createTestEngine(); @@ -129,4 +135,18 @@ public void setBusinessDataDatabaseProperties(BonitaDatabaseConfiguration databa this.businessDataDatabaseConfiguration = database; } + /** + * Configuration class used to override bean definitions for test purposes. + */ + @Configuration + @Profile("!update-tool") // to allow to remove this default bypass in Update Tool tests (and so test it in the real condition) + static class TestConfiguration { + + @Bean + ProcessStarterVerifier processStarterVerifierImpl() { + return processInstance -> { + // Override this bean to disable the process starter verifier + }; + } + } } diff --git a/bonita-test-api/src/main/java/org/bonitasoft/engine/test/internal/EngineStarter.java b/bonita-test-api/src/main/java/org/bonitasoft/engine/test/internal/EngineStarter.java index 294f2474c5a..53071b3d42a 100644 --- a/bonita-test-api/src/main/java/org/bonitasoft/engine/test/internal/EngineStarter.java +++ b/bonita-test-api/src/main/java/org/bonitasoft/engine/test/internal/EngineStarter.java @@ -21,6 +21,8 @@ import java.nio.file.Path; import java.util.*; +import javax.naming.NamingException; + import org.apache.commons.io.FileUtils; import org.bonitasoft.engine.BonitaDatabaseConfiguration; import org.bonitasoft.engine.BonitaEngine; @@ -40,6 +42,7 @@ import org.bonitasoft.engine.test.ClientEventUtil; import org.bonitasoft.engine.test.TestEngineImpl; import org.bonitasoft.engine.util.APITypeManager; +import org.bonitasoft.platform.database.DatabaseVendor; import org.bonitasoft.platform.setup.PlatformSetup; import org.bonitasoft.platform.setup.PlatformSetupAccessor; import org.slf4j.Logger; @@ -56,7 +59,7 @@ public class EngineStarter { private static boolean hasFailed = false; private boolean dropOnStart = true; - private BonitaEngine engine; + private final BonitaEngine engine; protected EngineStarter(BonitaEngine engine) { this.engine = engine; @@ -76,7 +79,7 @@ public void start() throws Exception { } try { LOGGER.info("====================================================="); - LOGGER.info("============ Starting Bonita Engine ==========="); + LOGGER.info("============== Starting Bonita Engine ============="); LOGGER.info("====================================================="); final long startTime = System.currentTimeMillis(); System.setProperty("com.arjuna.ats.arjuna.common.propertiesFile", "jbossts-properties.xml"); @@ -102,19 +105,24 @@ public void start() throws Exception { } protected void setupPlatform() throws Exception { - PlatformSetup platformSetup = PlatformSetupAccessor.getPlatformSetup(); + PlatformSetup platformSetup = getPlatformSetup(); if (isDropOnStart()) { platformSetup.destroy(); } } + protected PlatformSetup getPlatformSetup() throws NamingException { + return PlatformSetupAccessor.getInstance().getPlatformSetup(); + } + //-------------- engine life cycle methods protected void prepareEnvironment() throws Exception { LOGGER.info("========= PREPARE ENVIRONMENT ======="); - String dbVendor = setSystemPropertyIfNotSet("sysprop.bonita.db.vendor", "h2"); + String dbVendor = setSystemPropertyIfNotSet(PlatformSetup.BONITA_DB_VENDOR_PROPERTY, + DatabaseVendor.H2.getValue()); //is h2 and not started outside - if (Objects.equals("h2", dbVendor)) { + if (DatabaseVendor.H2.equalsValue(dbVendor)) { setSystemPropertyIfNotSet(DATABASE_DIR, "build/database"); } engine.initializeEnvironment(); diff --git a/bonita-test-api/src/main/java/org/bonitasoft/engine/test/junit/BonitaEngineRule.java b/bonita-test-api/src/main/java/org/bonitasoft/engine/test/junit/BonitaEngineRule.java index 3e2ed4e4647..2a9127158bc 100644 --- a/bonita-test-api/src/main/java/org/bonitasoft/engine/test/junit/BonitaEngineRule.java +++ b/bonita-test-api/src/main/java/org/bonitasoft/engine/test/junit/BonitaEngineRule.java @@ -13,6 +13,8 @@ **/ package org.bonitasoft.engine.test.junit; +import java.lang.reflect.InvocationTargetException; + import org.bonitasoft.engine.test.TestEngine; import org.bonitasoft.engine.test.TestEngineImpl; import org.junit.rules.MethodRule; @@ -32,6 +34,16 @@ protected BonitaEngineRule(TestEngine testEngine) { } public static BonitaEngineRule create() { + try { + var testEngineSpClazz = BonitaEngineRule.class.getClassLoader() + .loadClass("com.bonitasoft.engine.test.TestEngineSP"); + TestEngine testEngineSpInstance = (TestEngine) testEngineSpClazz.getMethod("getInstance").invoke(null); + return new BonitaEngineRule(testEngineSpInstance); + } catch (ClassNotFoundException e) { + // Use Community TestEngine + } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) { + throw new RuntimeException(e); + } return new BonitaEngineRule(TestEngineImpl.getInstance()); } diff --git a/bpm/bonita-api/bonita-server-api-http/build.gradle b/bpm/bonita-api/bonita-server-api-http/build.gradle index e521dba2c9e..e487b450bc6 100644 --- a/bpm/bonita-api/bonita-server-api-http/build.gradle +++ b/bpm/bonita-api/bonita-server-api-http/build.gradle @@ -8,10 +8,6 @@ dependencies { api libs.commonsFileUpload api libs.commonsIO testImplementation libs.springTest - testImplementation libs.junit5api - testRuntimeOnly libs.junitJupiterEngine - testImplementation libs.junit4 - testRuntimeOnly libs.junitVintageEngine testImplementation libs.mockitoJunitJupiter testImplementation libs.assertj testImplementation libs.mockitoCore @@ -20,7 +16,3 @@ dependencies { compileOnly libs.jakartaServletApi testImplementation libs.jakartaServletApi } - -test { - useJUnitPlatform() -} diff --git a/bpm/bonita-api/bonita-server-api-http/src/main/java/org/bonitasoft/engine/api/internal/servlet/EngineInitializerListener.java b/bpm/bonita-api/bonita-server-api-http/src/main/java/org/bonitasoft/engine/api/internal/servlet/EngineInitializerListener.java index 13742c3e61a..556785ce973 100644 --- a/bpm/bonita-api/bonita-server-api-http/src/main/java/org/bonitasoft/engine/api/internal/servlet/EngineInitializerListener.java +++ b/bpm/bonita-api/bonita-server-api-http/src/main/java/org/bonitasoft/engine/api/internal/servlet/EngineInitializerListener.java @@ -13,11 +13,13 @@ **/ package org.bonitasoft.engine.api.internal.servlet; +import javax.naming.NamingException; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import org.bonitasoft.engine.EngineInitializer; import org.bonitasoft.engine.service.impl.ServiceAccessorFactory; +import org.bonitasoft.platform.setup.PlatformSetup; import org.bonitasoft.platform.setup.PlatformSetupAccessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,6 +30,7 @@ public class EngineInitializerListener implements ServletContextListener { static final String UPDATE_ONLY_STARTUP_PROPERTY = "bonita.runtime.startup.update-only"; + private static final Logger log = LoggerFactory.getLogger(EngineInitializerListener.class); @Override @@ -56,17 +59,20 @@ public void contextInitialized(final ServletContextEvent event) { AnnotationConfigWebApplicationContext initializeWebApplicationContext(ServletContextEvent event, EngineInitializer engineInitializer) throws Exception { - PlatformSetupAccessor.getPlatformSetup().init(); // init tables and default configuration + getPlatformSetup().init(); // init tables and default configuration engineInitializer.initializeEngine(); ApplicationContext engineContext = ServiceAccessorFactory.getInstance() .createServiceAccessor() .getContext(); - AnnotationConfigWebApplicationContext webApplicationContext = initializeWebContext(event, engineContext); webApplicationContext.refresh(); return webApplicationContext; } + protected PlatformSetup getPlatformSetup() throws NamingException { + return PlatformSetupAccessor.getInstance().getPlatformSetup(); + } + void exit(int code) { System.exit(code); } @@ -87,7 +93,7 @@ protected EngineInitializer getEngineInitializer() { } @Override - public void contextDestroyed(final ServletContextEvent arg0) { + public void contextDestroyed(final ServletContextEvent event) { try { getEngineInitializer().unloadEngine(); } catch (final Throwable e) { diff --git a/bpm/bonita-client/build.gradle b/bpm/bonita-client/build.gradle index a905b4ebf9b..b3ef29bb163 100644 --- a/bpm/bonita-client/build.gradle +++ b/bpm/bonita-client/build.gradle @@ -10,7 +10,6 @@ dependencies { api libs.httpComponentsClient api libs.xstream api libs.httpComponentsMime - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.logback testImplementation libs.mockitoCore diff --git a/bpm/bonita-client/src/main/java/org/bonitasoft/engine/api/APIClient.java b/bpm/bonita-client/src/main/java/org/bonitasoft/engine/api/APIClient.java index c1950dbd3ca..94fb65e2541 100644 --- a/bpm/bonita-client/src/main/java/org/bonitasoft/engine/api/APIClient.java +++ b/bpm/bonita-client/src/main/java/org/bonitasoft/engine/api/APIClient.java @@ -22,6 +22,7 @@ import org.bonitasoft.engine.api.impl.ClientInterceptor; import org.bonitasoft.engine.api.impl.LocalServerAPIFactory; import org.bonitasoft.engine.api.internal.ServerAPI; +import org.bonitasoft.engine.api.platform.PlatformInformationAPI; import org.bonitasoft.engine.bdm.BusinessObjectDaoCreationException; import org.bonitasoft.engine.bdm.dao.BusinessObjectDAO; import org.bonitasoft.engine.exception.ServerAPIException; @@ -135,12 +136,10 @@ protected T getLoginAPI(Class apiClass) { /** * Connects a user, identified by his (her) username and password, in order to use API methods of a tenant. * - * @param username - * the user name - * @param password - * the password - * @throws LoginException - * occurs when an exception is thrown during the login (userName does not exist, or couple (userName, + * @param username the user name + * @param password the password + * @throws LoginException occurs when an exception is thrown during the login (userName does not exist, or couple + * (userName, * password) is incorrect) * @since 7.2 */ @@ -325,4 +324,14 @@ public TemporaryContentAPI getTemporaryContentAPI() { public MaintenanceAPI getMaintenanceAPI() { return getAPI(MaintenanceAPI.class); } + + /** + * Get API that retrieves information on the platform: basic information in a Community edition, + * More detailed information on license in a Subscription edition. + * + * @since 10.2.0 + */ + public PlatformInformationAPI getPlatformInformationAPI() { + return getAPI(PlatformInformationAPI.class); + } } diff --git a/bpm/bonita-client/src/main/java/org/bonitasoft/engine/api/TenantAPIAccessor.java b/bpm/bonita-client/src/main/java/org/bonitasoft/engine/api/TenantAPIAccessor.java index 16bddb9aa7e..519ed39342d 100644 --- a/bpm/bonita-client/src/main/java/org/bonitasoft/engine/api/TenantAPIAccessor.java +++ b/bpm/bonita-client/src/main/java/org/bonitasoft/engine/api/TenantAPIAccessor.java @@ -17,6 +17,7 @@ import org.bonitasoft.engine.api.impl.ClientInterceptor; import org.bonitasoft.engine.api.internal.ServerAPI; +import org.bonitasoft.engine.api.platform.PlatformInformationAPI; import org.bonitasoft.engine.exception.BonitaHomeNotSetException; import org.bonitasoft.engine.exception.ServerAPIException; import org.bonitasoft.engine.exception.UnknownAPITypeException; @@ -132,4 +133,9 @@ public static MaintenanceAPI getMaintenanceAPI(final APISession session) throws BonitaHomeNotSetException, ServerAPIException, UnknownAPITypeException { return getAPI(MaintenanceAPI.class, session); } + + public static PlatformInformationAPI getPlatformInformationAPI(final APISession session) + throws ServerAPIException, BonitaHomeNotSetException, UnknownAPITypeException { + return getAPI(PlatformInformationAPI.class, session); + } } diff --git a/bpm/bonita-common/build.gradle b/bpm/bonita-common/build.gradle index 65df762fc95..9edda66bab5 100644 --- a/bpm/bonita-common/build.gradle +++ b/bpm/bonita-common/build.gradle @@ -22,7 +22,6 @@ dependencies { annotationProcessor libs.lombok testImplementation project(':bpm:bonita-sap-jco-connector-api') - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.mockitoCore testImplementation libs.logback diff --git a/bpm/bonita-common/src/main/java/org/bonitasoft/engine/api/ApplicationAPI.java b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/api/ApplicationAPI.java index bfda5ec8fb6..4dac4892cd5 100755 --- a/bpm/bonita-common/src/main/java/org/bonitasoft/engine/api/ApplicationAPI.java +++ b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/api/ApplicationAPI.java @@ -18,6 +18,9 @@ import org.bonitasoft.engine.business.application.Application; import org.bonitasoft.engine.business.application.ApplicationCreator; import org.bonitasoft.engine.business.application.ApplicationImportPolicy; +import org.bonitasoft.engine.business.application.ApplicationLink; +import org.bonitasoft.engine.business.application.ApplicationLinkCreator; +import org.bonitasoft.engine.business.application.ApplicationLinkUpdater; import org.bonitasoft.engine.business.application.ApplicationMenu; import org.bonitasoft.engine.business.application.ApplicationMenuCreator; import org.bonitasoft.engine.business.application.ApplicationMenuNotFoundException; @@ -26,6 +29,7 @@ import org.bonitasoft.engine.business.application.ApplicationPage; import org.bonitasoft.engine.business.application.ApplicationPageNotFoundException; import org.bonitasoft.engine.business.application.ApplicationUpdater; +import org.bonitasoft.engine.business.application.IApplication; import org.bonitasoft.engine.business.application.Icon; import org.bonitasoft.engine.exception.AlreadyExistsException; import org.bonitasoft.engine.exception.CreationException; @@ -38,9 +42,11 @@ import org.bonitasoft.engine.search.SearchResult; /** - * This API allows to list and manage Bonita Living Applications ({@link Application}). + * This API allows to list and manage Bonita Living Applications ({@link IApplication}). * * @author Elias Ricken de Medeiros + * @see org.bonitasoft.engine.business.application.IApplication + * @see org.bonitasoft.engine.business.application.ApplicationLink * @see org.bonitasoft.engine.business.application.Application * @since 6.4 */ @@ -61,6 +67,22 @@ public interface ApplicationAPI { Application createApplication(ApplicationCreator applicationCreator) throws AlreadyExistsException, CreationException; + /** + * Creates a new {@link ApplicationLink} based on the supplied {@link ApplicationLinkCreator} + * + * @param applicationLinkCreator creator describing characteristics of application link to be created + * @return the created ApplicationLink + * @throws AlreadyExistsException if an application already exists with the same name + * @throws CreationException if an error occurs during the creation + * @see ApplicationLink + * @see ApplicationLinkCreator + * @deprecated as of 9.0.0, Applications should be created at startup. This also concerns application links + * introduced in 10.2.0. + */ + @Deprecated(since = "10.2.0") + ApplicationLink createApplicationLink(ApplicationLinkCreator applicationLinkCreator) + throws AlreadyExistsException, CreationException; + /** * Retrieves an {@link Application} from its identifier. * @@ -68,8 +90,27 @@ Application createApplication(ApplicationCreator applicationCreator) * @return an Application from its identifier. * @throws ApplicationNotFoundException if no application is found for the given identifier * @see Application + * @deprecated as of 10.2.0, use {@link #getIApplication(long)} instead to include application links. */ - Application getApplication(final long applicationId) throws ApplicationNotFoundException; + @Deprecated(since = "10.2.0") + default Application getApplication(final long applicationId) throws ApplicationNotFoundException { + var res = getIApplication(applicationId); + if (res instanceof Application legacy) { + return legacy; + } else { + throw new ApplicationNotFoundException(applicationId); + } + } + + /** + * Retrieves an {@link IApplication} from its identifier. + * + * @param applicationId the application identifier + * @return an Application from its identifier. + * @throws ApplicationNotFoundException if no application is found for the given identifier + * @see IApplication + */ + IApplication getIApplication(final long applicationId) throws ApplicationNotFoundException; /** * Retrieves an {@link Application} from its token. @@ -78,17 +119,36 @@ Application createApplication(ApplicationCreator applicationCreator) * @return an Application from its token. * @throws ApplicationNotFoundException if no application is found for the given token * @see Application + * @deprecated as of 10.2.0, use {@link #getIApplicationByToken(String)} instead to include application links. + */ + @Deprecated(since = "10.2.0") + default Application getApplicationByToken(final String applicationToken) throws ApplicationNotFoundException { + var app = getIApplicationByToken(applicationToken); + if (app instanceof Application legacy) { + return legacy; + } else { + throw new ApplicationNotFoundException(applicationToken); + } + } + + /** + * Retrieves an {@link IApplication} from its token. + * + * @param applicationToken the application token used in the URL + * @return an Application from its token. + * @throws ApplicationNotFoundException if no application is found for the given token + * @see IApplication */ - Application getApplicationByToken(final String applicationToken) throws ApplicationNotFoundException; + IApplication getIApplicationByToken(final String applicationToken) throws ApplicationNotFoundException; /** - * Deletes an {@link Application} by its identifier. All related + * Deletes an {@link IApplication} by its identifier. All related * {@link org.bonitasoft.engine.business.application.ApplicationPage}s and * {@link org.bonitasoft.engine.business.application.ApplicationMenu}s will be automatically deleted. * * @param applicationId the Application identifier * @throws DeletionException if an error occurs during the deletion - * @see Application + * @see IApplication * @see org.bonitasoft.engine.business.application.ApplicationPage * @see org.bonitasoft.engine.business.application.ApplicationMenu */ @@ -101,7 +161,7 @@ Application createApplication(ApplicationCreator applicationCreator) * @param updater an ApplicationUpdater describing the fields to be updated. * @return the Application as it is after the update. * @throws ApplicationNotFoundException if no Application is found for the given id - * @throws AlreadyExistsException if another Application already exists with the new name value + * @throws AlreadyExistsException if another IApplication already exists with the new name value * @throws UpdateException if an error occurs during the update * @see Application * @see ApplicationUpdater @@ -111,6 +171,24 @@ Application createApplication(ApplicationCreator applicationCreator) Application updateApplication(long applicationId, ApplicationUpdater updater) throws ApplicationNotFoundException, UpdateException, AlreadyExistsException; + /** + * Updates an {@link ApplicationLink} based on the information supplied by the {@link ApplicationLinkUpdater} + * + * @param applicationId a long representing the application identifier + * @param updater an ApplicationLinkUpdater describing the fields to be updated. + * @return the ApplicationLink as it is after the update. + * @throws ApplicationNotFoundException if no ApplicationLink is found for the given id + * @throws AlreadyExistsException if another IApplication already exists with the new name value + * @throws UpdateException if an error occurs during the update + * @see ApplicationLink + * @see ApplicationLinkUpdater + * @deprecated as of 9.0.0, Applications should be updated at startup. This also concerns application links + * introduced in 10.2.0. + */ + @Deprecated(since = "10.2.0") + ApplicationLink updateApplicationLink(long applicationId, ApplicationLinkUpdater updater) + throws ApplicationNotFoundException, UpdateException, AlreadyExistsException; + /** * Searches for {@link Application}s with specific search criteria. Use * {@link org.bonitasoft.engine.business.application.ApplicationSearchDescriptor} to @@ -123,9 +201,26 @@ Application updateApplication(long applicationId, ApplicationUpdater updater) * @see org.bonitasoft.engine.business.application.ApplicationSearchDescriptor * @see SearchOptions * @see SearchResult + * @deprecated as of 10.2.0, use {@link #searchIApplications(SearchOptions)} instead to include application links. */ + @Deprecated(since = "10.2.0") SearchResult searchApplications(final SearchOptions searchOptions) throws SearchException; + /** + * Searches for {@link IApplication}s with specific search criteria. Use + * {@link org.bonitasoft.engine.business.application.ApplicationSearchDescriptor} to + * know the available filters. + * + * @param searchOptions the search criteria. See {@link SearchOptions} for details. + * @return a {@link SearchResult} containing the number and the list of applications matching the search criteria. + * @throws SearchException if an error occurs during search + * @see IApplication + * @see org.bonitasoft.engine.business.application.ApplicationSearchDescriptor + * @see SearchOptions + * @see SearchResult + */ + SearchResult searchIApplications(final SearchOptions searchOptions) throws SearchException; + /** * Creates an {@link ApplicationPage} * @@ -341,13 +436,13 @@ ApplicationMenu updateApplicationMenu(long applicationMenuId, ApplicationMenuUpd List getAllPagesForProfile(String profile); /** - * Exports the {@link org.bonitasoft.engine.business.application.Application}s which identifier is in + * Exports the {@link IApplication}s which identifier is in * {@code applicationIds} * * @param applicationIds the identifiers of {@code Application}s to be exported * @return a byte array representing the content of XML file containing the exported {@code Application}s * @throws ExportException if an exception occurs during the export. - * @see org.bonitasoft.engine.business.application.Application + * @see org.bonitasoft.engine.business.application.IApplication */ byte[] exportApplications(long... applicationIds) throws ExportException; diff --git a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/dbconfig/H2LocalDataSourceConfig.java b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/api/platform/PlatformInformationAPI.java similarity index 59% rename from platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/dbconfig/H2LocalDataSourceConfig.java rename to bpm/bonita-common/src/main/java/org/bonitasoft/engine/api/platform/PlatformInformationAPI.java index 9d5ab498ddc..29d5041fbcd 100644 --- a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/dbconfig/H2LocalDataSourceConfig.java +++ b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/api/platform/PlatformInformationAPI.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2019 Bonitasoft S.A. + * Copyright (C) 2024 Bonitasoft S.A. * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble * This library is free software; you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Foundation @@ -11,20 +11,14 @@ * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301, USA. **/ -package org.bonitasoft.platform.setup.dbconfig; +package org.bonitasoft.engine.api.platform; -import org.springframework.context.annotation.Profile; -import org.springframework.context.annotation.PropertySource; -import org.springframework.stereotype.Component; +import java.util.Map; -/** - * This is enough to get a Datasource that spring creates using parameters provided in properties. - * - * @author Emmanuel Duchastenier - */ -@Component -@PropertySource("classpath:/h2.properties") -@Profile("h2") -public class H2LocalDataSourceConfig { +import org.bonitasoft.engine.platform.PlatformNotFoundException; + +public interface PlatformInformationAPI { + + Map getPlatformInformation() throws PlatformNotFoundException; } diff --git a/bpm/bonita-common/src/main/java/org/bonitasoft/engine/bpm/process/ProcessExecutionException.java b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/bpm/process/ProcessExecutionException.java index 7fcf5bac335..d4b3573aa53 100644 --- a/bpm/bonita-common/src/main/java/org/bonitasoft/engine/bpm/process/ProcessExecutionException.java +++ b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/bpm/process/ProcessExecutionException.java @@ -13,6 +13,7 @@ **/ package org.bonitasoft.engine.bpm.process; +import lombok.Getter; import org.bonitasoft.engine.exception.ExecutionException; /** @@ -26,6 +27,8 @@ public class ProcessExecutionException extends ExecutionException { private static final long serialVersionUID = 4412292065541283593L; + @Getter + private long retryAfter = -1L; /** * Constructs a new exception with the specified detail cause. @@ -39,6 +42,11 @@ public ProcessExecutionException(Throwable cause) { super(cause); } + public ProcessExecutionException(Throwable cause, long retryAfter) { + super(cause); + this.retryAfter = retryAfter; + } + /** * Constructs a new exception with the specified detail message. * diff --git a/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/AbstractApplicationCreator.java b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/AbstractApplicationCreator.java new file mode 100644 index 00000000000..63f2060af14 --- /dev/null +++ b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/AbstractApplicationCreator.java @@ -0,0 +1,165 @@ +/** + * Copyright (C) 2019 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.engine.business.application; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import org.bonitasoft.engine.profile.Profile; + +/** + * Describes the information about an {@link IApplication} to be created + * + * @see IApplication + * @deprecated This class should no longer be used. Since 9.0.0, Applications should be created at startup. + * @param the concrete subtype of {@link AbstractApplicationCreator} (for returning self, subclasses must ensure to + * use the concrete instance) + */ +@Deprecated(since = "10.2.0") +public abstract class AbstractApplicationCreator> implements Serializable { + + private static final long serialVersionUID = -8837280485050745580L; + + private final Map fields; + + /** + * Creates an instance of ApplicationCreator containing mandatory information. + *

The created {@link Application} will used the default layout.

+ * + * @param token the {@code Application} token. The token will be part of application URL. It cannot be null or empty + * and should contain only alpha numeric + * characters and the following special characters '-', '.', '_' or '~'. In addition, the following words are + * reserved key words and cannot be used + * as token: 'api', 'content', 'theme'. + * @param displayName the Application display name. It cannot be null or empty + * @param version the Application version + * @see Application + */ + public AbstractApplicationCreator(final String token, final String displayName, final String version) { + fields = new HashMap<>(3); + fields.put(ApplicationField.TOKEN, token); + fields.put(ApplicationField.VERSION, version); + fields.put(ApplicationField.DISPLAY_NAME, displayName); + } + + /** + * Retrieves the {@link Application} token + * + * @return the Application token + * @see Application + */ + public String getToken() { + return (String) fields.get(ApplicationField.TOKEN); + } + + /** + * Defines the {@link Application} description and returns the current ApplicationCreator + * + * @param description the Application description + * @return the current ApplicationCreator + * @see Application + */ + public T setDescription(final String description) { + fields.put(ApplicationField.DESCRIPTION, description); + return (T) this; + } + + /** + * Defines the {@link Application} icon path and returns the current ApplicationCreator + * + * @param iconPath the Application icon path + * @return the current ApplicationCreator + * @see Application + * @deprecated since 7.13.0, use {@link #setIcon(String, byte[])} + */ + @Deprecated(since = "7.13.0") + public T setIconPath(final String iconPath) { + fields.put(ApplicationField.ICON_PATH, iconPath); + return (T) this; + } + + /** + * Defines the icon for the {@link Application}. + * + * @param fileName of the icon + * @param content of the icon + * @return the current builder + * @since 7.13.0 + */ + public T setIcon(String fileName, byte[] content) { + fields.put(ApplicationField.ICON_FILE_NAME, fileName); + fields.put(ApplicationField.ICON_CONTENT, content); + return (T) this; + } + + /** + * Defines the identifier of the {@link Profile} related to this {@link Application} and returns the current + * ApplicationCreator + * + * @param profileId the Profile identifier + * @return the current ApplicationCreator + * @see Application + * @see Profile + */ + public T setProfileId(final Long profileId) { + fields.put(ApplicationField.PROFILE_ID, profileId); + return (T) this; + } + + /** + * Retrieves all fields defined in this ApplicationCreator + * + * @return a {@link Map}<{@link ApplicationField}, {@link Serializable}> containing all fields defined in this + * ApplicationCreator + * @see ApplicationField + */ + public Map getFields() { + return fields; + } + + /** Test whether application is an application link. */ + public abstract boolean isLink(); + + @Override + public int hashCode() { + final int prime = 31; + int result = getClass().hashCode(); + result = prime * result + (fields == null ? 0 : fields.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final AbstractApplicationCreator other = (AbstractApplicationCreator) obj; + if (fields == null) { + if (other.fields != null) { + return false; + } + } else if (!fields.equals(other.fields)) { + return false; + } + return true; + } + +} diff --git a/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/AbstractApplicationUpdater.java b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/AbstractApplicationUpdater.java new file mode 100644 index 00000000000..7fed447331f --- /dev/null +++ b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/AbstractApplicationUpdater.java @@ -0,0 +1,167 @@ +/** + * Copyright (C) 2019 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.engine.business.application; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import org.bonitasoft.engine.profile.Profile; + +/** + * Allows to define which {@link IApplication} fields will be updated + * + * @see IApplication + * @deprecated This class should no longer be used. Since 9.0.0, Applications should be updated at startup. + * @param the concrete subtype of {@link AbstractApplicationUpdater} (for returning self, subclasses must ensure to + * use the concrete instance) + */ +@Deprecated(since = "10.2.0") +public abstract class AbstractApplicationUpdater> implements Serializable { + + private static final long serialVersionUID = -5301609836484089900L; + + private final Map fields; + + /** + * Creates an instance of ApplicationUpdater + */ + public AbstractApplicationUpdater() { + fields = new HashMap<>(8); + } + + /** + * Retrieves all fields to be updated + * + * @return a {@link Map}<{@link ApplicationField}, {@link Serializable}> containing all fields to be updated + * @see ApplicationField + */ + public Map getFields() { + return fields; + } + + /** + * Defines the new value for the {@link IApplication} token. It cannot be empty or null and should contain only + * alpha numeric characters and the following special characters '-', '.', '_' or '~'. + * + * @param token the new value for the {@code Application} token + * @return the current {@code ApplicationUpdater} + * @see IApplication + */ + public T setToken(final String token) { + fields.put(ApplicationField.TOKEN, token); + return (T) this; + } + + /** + * Defines the new value for the {@link IApplication} display name. It cannot be empty or null. + * + * @param displayName the new value for the {@code Application} display name + * @return the current {@code ApplicationUpdater} + * @see IApplication + */ + public T setDisplayName(final String displayName) { + fields.put(ApplicationField.DISPLAY_NAME, displayName); + return (T) this; + } + + /** + * Defines the new value for the {@link IApplication} version + * + * @param version the new value for the {@code Application} version + * @return the current {@code ApplicationUpdater} + * @see IApplication + */ + public T setVersion(final String version) { + fields.put(ApplicationField.VERSION, version); + return (T) this; + } + + /** + * Defines the new value for the {@link IApplication} description + * + * @param description the new value for the {@code Application} description + * @return the current {@code ApplicationUpdater} + * @see IApplication + */ + public T setDescription(final String description) { + fields.put(ApplicationField.DESCRIPTION, description); + return (T) this; + } + + /** + * Defines the new value for the {@link IApplication} icon path + * + * @param iconPath the new value for the {@code Application} icon path + * @return the current {@code ApplicationUpdater} + * @see IApplication + * @deprecated since 7.13.0, use {@link #setIcon(String, byte[])} + */ + @Deprecated(since = "7.13.0") + public T setIconPath(final String iconPath) { + fields.put(ApplicationField.ICON_PATH, iconPath); + return (T) this; + } + + /** + * Defines the new icon for the {@link IApplication}. + *

+ * The icons are accessible using {@link org.bonitasoft.engine.api.ApplicationAPI#getIconOfApplication(long)} + * Calling that method with {@code setIcon(null, null)} will remove the icon. + * + * @param iconFileName of the icon + * @param content of the icon + * @return the current builder + * @since 7.13.0 + */ + public T setIcon(String iconFileName, byte[] content) { + fields.put(ApplicationField.ICON_FILE_NAME, iconFileName); + fields.put(ApplicationField.ICON_CONTENT, content); + return (T) this; + } + + /** + * Defines the new value for the {@link IApplication} state + * + * @param state the new value for the {@code Application} state + * @return the current {@code ApplicationUpdater} + * @see IApplication + */ + public T setState(final String state) { + fields.put(ApplicationField.STATE, state); + return (T) this; + } + + /** + * Defines the identifier of the new {@link Profile} associated to the {@link IApplication} + * + * @param profileId the identifier of {@code Profile} associated to the {@code Application} + * @return the current {@code ApplicationUpdater} + * @see IApplication + * @see Profile + */ + public T setProfileId(final Long profileId) { + fields.put(ApplicationField.PROFILE_ID, profileId); + return (T) this; + } + + /** + * Determines if this updater has at least one field to update + * + * @return true if there is at least one field to update; false otherwise + */ + public boolean hasFields() { + return !getFields().isEmpty(); + } +} diff --git a/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationCreator.java b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationCreator.java index c3e75b750ed..9112014e012 100755 --- a/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationCreator.java +++ b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationCreator.java @@ -13,25 +13,19 @@ **/ package org.bonitasoft.engine.business.application; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - -import org.bonitasoft.engine.profile.Profile; - /** - * Describes the information about an {@link Application} to be created + * Describes the information about a Legacy {@link Application} to be created * * @author Elias Ricken de Medeiros * @see Application * @since 7.0.0 + * @deprecated This class should no longer be used. Since 9.0.0, Applications should be created at startup. */ -public class ApplicationCreator implements Serializable { +@Deprecated(since = "10.2.0") +public class ApplicationCreator extends AbstractApplicationCreator { private static final long serialVersionUID = -916041825489100271L; - private final Map fields; - /** * Creates an instance of ApplicationCreator containing mandatory information. *

The created {@link Application} will used the default layout.

@@ -46,115 +40,12 @@ public class ApplicationCreator implements Serializable { * @see Application */ public ApplicationCreator(final String token, final String displayName, final String version) { - fields = new HashMap<>(3); - fields.put(ApplicationField.TOKEN, token); - fields.put(ApplicationField.VERSION, version); - fields.put(ApplicationField.DISPLAY_NAME, displayName); - } - - /** - * Retrieves the {@link Application} token - * - * @return the Application token - * @see Application - */ - public String getToken() { - return (String) fields.get(ApplicationField.TOKEN); - } - - /** - * Defines the {@link Application} description and returns the current ApplicationCreator - * - * @param description the Application description - * @return the current ApplicationCreator - * @see Application - */ - public ApplicationCreator setDescription(final String description) { - fields.put(ApplicationField.DESCRIPTION, description); - return this; - } - - /** - * Defines the {@link Application} icon path and returns the current ApplicationCreator - * - * @param iconPath the Application icon path - * @return the current ApplicationCreator - * @see Application - * @deprecated since 7.13.0, use {@link #setIcon(String, byte[])} - */ - @Deprecated(since = "7.13.0") - public ApplicationCreator setIconPath(final String iconPath) { - fields.put(ApplicationField.ICON_PATH, iconPath); - return this; - } - - /** - * Defines the icon for the {@link Application}. - * - * @param fileName of the icon - * @param content of the icon - * @return the current builder - * @since 7.13.0 - */ - public ApplicationCreator setIcon(String fileName, byte[] content) { - fields.put(ApplicationField.ICON_FILE_NAME, fileName); - fields.put(ApplicationField.ICON_CONTENT, content); - return this; - } - - /** - * Defines the identifier of the {@link Profile} related to this {@link Application} and returns the current - * ApplicationCreator - * - * @param profileId the Profile identifier - * @return the current ApplicationCreator - * @see Application - * @see Profile - */ - public ApplicationCreator setProfileId(final Long profileId) { - fields.put(ApplicationField.PROFILE_ID, profileId); - return this; - } - - /** - * Retrieves all fields defined in this ApplicationCreator - * - * @return a {@link Map}<{@link ApplicationField}, {@link Serializable}> containing all fields defined in this - * ApplicationCreator - * @see ApplicationField - */ - public Map getFields() { - return fields; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + (fields == null ? 0 : fields.hashCode()); - return result; + super(token, displayName, version); } @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final ApplicationCreator other = (ApplicationCreator) obj; - if (fields == null) { - if (other.fields != null) { - return false; - } - } else if (!fields.equals(other.fields)) { - return false; - } - return true; + public boolean isLink() { + return false; } } diff --git a/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationField.java b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationField.java index 0d5df503bcf..d5ce2b8f9f0 100755 --- a/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationField.java +++ b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationField.java @@ -22,71 +22,73 @@ * @see ApplicationCreator * @see ApplicationUpdater * @since 7.0.0 + * @deprecated This class should no longer be used. Since 9.0.0, Applications should be updated at startup. */ +@Deprecated(since = "10.2.0") public enum ApplicationField { /** - * References the {@link Application} token + * References the {@link IApplication} token * - * @see Application + * @see IApplication */ TOKEN, /** - * References the {@link Application} display name + * References the {@link IApplication} display name * - * @see Application + * @see IApplication */ DISPLAY_NAME, /** - * References the {@link Application} version + * References the {@link IApplication} version * - * @see Application + * @see IApplication */ VERSION, /** - * References the {@link Application} description + * References the {@link IApplication} description * - * @see Application + * @see IApplication */ DESCRIPTION, /** - * References the {@link Application} icon path + * References the {@link IApplication} icon path * - * @see Application + * @see IApplication * @deprecated since 7.13.0, use {@link #ICON_CONTENT} and {@link #ICON_FILE_NAME} instead */ @Deprecated(since = "7.13.0") ICON_PATH, /** - * byte array content of the icon of the {@link Application} + * byte array content of the icon of the {@link IApplication} * * @since 7.13.0 */ ICON_CONTENT, /** - * Filename of the icon of the {@link Application} + * Filename of the icon of the {@link IApplication} * * @since 7.13.0 */ ICON_FILE_NAME, /** - * References the {@link Application} state + * References the {@link IApplication} state * - * @see Application + * @see IApplication */ STATE, /** - * References the identifier of the {@link Profile} associated to the {@link Application} + * References the identifier of the {@link Profile} associated to the {@link IApplication} * - * @see Application + * @see IApplication * @see Profile */ PROFILE_ID, @@ -97,7 +99,7 @@ public enum ApplicationField { * @see org.bonitasoft.engine.business.application.ApplicationPage * @see org.bonitasoft.engine.business.application.Application */ - HOME_PAGE_ID, + HOME_PAGE_ID(Application.class), /** * References the identifier of the {@link org.bonitasoft.engine.page.Page} defined as the {@link Application} @@ -107,7 +109,7 @@ public enum ApplicationField { * @see org.bonitasoft.engine.business.application.Application * @since 7.0.0 */ - LAYOUT_ID, + LAYOUT_ID(Application.class), /** * References the identifier of the {@link org.bonitasoft.engine.page.Page} defined as the {@link Application} @@ -117,6 +119,37 @@ public enum ApplicationField { * @see org.bonitasoft.engine.business.application.Application * @since 7.0.0 */ - THEME_ID + THEME_ID(Application.class); + + /** The class which support this type of field */ + private Class supportingClass; + + /** + * Private Constructor for fields which are suitable for all application types. + */ + private ApplicationField() { + this(IApplication.class); + } + + /** + * Private Constructor for fields which are suitable only for a particular application type (e.g. Legacy, but not + * Link). + * + * @param appropriateClazz the class which support this type of field. + */ + private ApplicationField(Class appropriateClazz) { + supportingClass = appropriateClazz; + } + + /** + * Test whether this application field is suitable for a particular application type + * + * @param clazz the application type to test (usually {@link Application} for legacy applications of + * {@link ApplicationLink}) + * @return + */ + public boolean isForClass(Class clazz) { + return supportingClass.isAssignableFrom(clazz); + } } diff --git a/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationLinkCreator.java b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationLinkCreator.java new file mode 100644 index 00000000000..0cd0493d649 --- /dev/null +++ b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationLinkCreator.java @@ -0,0 +1,63 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.engine.business.application; + +import java.io.Serializable; +import java.util.Map; + +/** + * Describes the information about an {@link ApplicationLink} to be created + * + * @see ApplicationLink + * @since 10.2.0 + * @deprecated This class should no longer be used. Since 9.0.0, Applications should be created at startup. + */ +@Deprecated(since = "10.2.0") +public class ApplicationLinkCreator extends AbstractApplicationCreator { + + private static final long serialVersionUID = 5045658936235401181L; + private transient Map fieldsCheckedMap; + + /** + * Creates an instance of ApplicationCreator containing mandatory information. + * + * @param token the {@code ApplicationLink} token. The token will be part of application URL. It cannot be null or + * empty and should contain only alpha numeric + * characters and the following special characters '-', '.', '_' or '~'. In addition, the following words are + * reserved key words and cannot be used + * as token: 'api', 'content', 'theme'. + * @param displayName the ApplicationLink display name. It cannot be null or empty + * @param version the ApplicationLink version + * @see ApplicationLink + */ + public ApplicationLinkCreator(final String token, final String displayName, final String version) { + super(token, displayName, version); + } + + @Override + public boolean isLink() { + return true; + } + + @Override + public Map getFields() { + // make sure no field for Legacy Application and not suitable for Application Link will get inserted there + if (fieldsCheckedMap == null) { + fieldsCheckedMap = new CheckedApplicationFieldMap(super.getFields(), + k -> k.isForClass(ApplicationLink.class)); + } + return fieldsCheckedMap; + } + +} diff --git a/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationLinkUpdater.java b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationLinkUpdater.java new file mode 100644 index 00000000000..1ea8ca2de97 --- /dev/null +++ b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationLinkUpdater.java @@ -0,0 +1,41 @@ +/** + * Copyright (C) 2019 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.engine.business.application; + +import java.io.Serializable; +import java.util.Map; + +/** + * Allows to define which {@link ApplicationLink} fields will be updated + * + * @see ApplicationLink + * @since 10.2.0 + * @deprecated This class should no longer be used. Since 9.0.0, Applications should be updated at startup. + */ +@Deprecated(since = "10.2.0") +public class ApplicationLinkUpdater extends AbstractApplicationUpdater { + + private static final long serialVersionUID = 1732835829535757371L; + private transient Map fieldsCheckedMap; + + @Override + public Map getFields() { + // make sure no field for Legacy Application and not suitable for Application Link will get inserted there + if (fieldsCheckedMap == null) { + fieldsCheckedMap = new CheckedApplicationFieldMap(super.getFields(), + k -> k.isForClass(ApplicationLink.class)); + } + return fieldsCheckedMap; + } +} diff --git a/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationSearchDescriptor.java b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationSearchDescriptor.java index bcab98e70f5..dbe932692f1 100755 --- a/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationSearchDescriptor.java +++ b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationSearchDescriptor.java @@ -118,4 +118,13 @@ public class ApplicationSearchDescriptor { * @see Application */ public static final String USER_ID = "userId"; + + /** + * Used to filter or order Application items by legacy or link criteria + * + * @since 10.2.0 for some Subscription editions only + */ + public static final String LINK = "link"; + // keeping this constant here for convenience reasons + // having a subscription descriptor with just this field would not be user-friendly } diff --git a/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationUpdater.java b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationUpdater.java index f6be4131963..657117349da 100755 --- a/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationUpdater.java +++ b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/ApplicationUpdater.java @@ -13,148 +13,19 @@ **/ package org.bonitasoft.engine.business.application; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - -import org.bonitasoft.engine.profile.Profile; - /** * Allows to define which {@link Application} fields will be updated * * @author Elias Ricken de Medeiros * @see Application * @since 7.0.0 + * @deprecated This class should no longer be used. Since 9.0.0, Applications should be updated at startup. */ -public class ApplicationUpdater implements Serializable { +@Deprecated(since = "10.2.0") +public class ApplicationUpdater extends AbstractApplicationUpdater { private static final long serialVersionUID = 4565052647320534796L; - private final Map fields; - - /** - * Creates an instance of ApplicationUpdater - */ - public ApplicationUpdater() { - fields = new HashMap<>(8); - } - - /** - * Retrieves all fields to be updated - * - * @return a {@link Map}<{@link ApplicationField}, {@link Serializable}> containing all fields to be updated - * @see ApplicationField - */ - public Map getFields() { - return fields; - } - - /** - * Defines the new value for the {@link Application} token. It cannot be empty or null and should contain only alpha - * numeric - * characters and the following special characters '-', '.', '_' or '~'. - * - * @param token the new value for the {@code Application} token - * @return the current {@code ApplicationUpdater} - * @see Application - */ - public ApplicationUpdater setToken(final String token) { - fields.put(ApplicationField.TOKEN, token); - return this; - } - - /** - * Defines the new value for the {@link Application} display name. It cannot be empty or null. - * - * @param displayName the new value for the {@code Application} display name - * @return the current {@code ApplicationUpdater} - * @see Application - */ - public ApplicationUpdater setDisplayName(final String displayName) { - fields.put(ApplicationField.DISPLAY_NAME, displayName); - return this; - } - - /** - * Defines the new value for the {@link Application} version - * - * @param version the new value for the {@code Application} version - * @return the current {@code ApplicationUpdater} - * @see Application - */ - public ApplicationUpdater setVersion(final String version) { - fields.put(ApplicationField.VERSION, version); - return this; - } - - /** - * Defines the new value for the {@link Application} description - * - * @param description the new value for the {@code Application} description - * @return the current {@code ApplicationUpdater} - * @see Application - */ - public ApplicationUpdater setDescription(final String description) { - fields.put(ApplicationField.DESCRIPTION, description); - return this; - } - - /** - * Defines the new value for the {@link Application} icon path - * - * @param iconPath the new value for the {@code Application} icon path - * @return the current {@code ApplicationUpdater} - * @see Application - * @deprecated since 7.13.0, use {@link #setIcon(String, byte[])} - */ - @Deprecated(since = "7.13.0") - public ApplicationUpdater setIconPath(final String iconPath) { - fields.put(ApplicationField.ICON_PATH, iconPath); - return this; - } - - /** - * Defines the new icon for the {@link Application}. - *

- * The icons are accessible using {@link org.bonitasoft.engine.api.ApplicationAPI#getIconOfApplication(long)} - * Calling that method with {@code setIcon(null, null)} will remove the icon. - * - * @param iconFileName of the icon - * @param content of the icon - * @return the current builder - * @since 7.13.0 - */ - public ApplicationUpdater setIcon(String iconFileName, byte[] content) { - fields.put(ApplicationField.ICON_FILE_NAME, iconFileName); - fields.put(ApplicationField.ICON_CONTENT, content); - return this; - } - - /** - * Defines the new value for the {@link Application} state - * - * @param state the new value for the {@code Application} state - * @return the current {@code ApplicationUpdater} - * @see Application - */ - public ApplicationUpdater setState(final String state) { - fields.put(ApplicationField.STATE, state); - return this; - } - - /** - * Defines the identifier of the new {@link Profile} associated to the {@link Application} - * - * @param profileId the identifier of {@code Profile} associated to the {@code Application} - * @return the current {@code ApplicationUpdater} - * @see Application - * @see Profile - */ - public ApplicationUpdater setProfileId(final Long profileId) { - fields.put(ApplicationField.PROFILE_ID, profileId); - return this; - } - /** * Defines the identifier of the new {@link org.bonitasoft.engine.business.application.ApplicationPage} defined as * the {@link Application} home page @@ -165,16 +36,7 @@ public ApplicationUpdater setProfileId(final Long profileId) { * @see org.bonitasoft.engine.business.application.ApplicationPage */ public ApplicationUpdater setHomePageId(final Long applicationPageId) { - fields.put(ApplicationField.HOME_PAGE_ID, applicationPageId); + getFields().put(ApplicationField.HOME_PAGE_ID, applicationPageId); return this; } - - /** - * Determines if this updater has at least one field to update - * - * @return true if there is at least one field to update; false otherwise - */ - public boolean hasFields() { - return !getFields().isEmpty(); - } } diff --git a/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/CheckedApplicationFieldMap.java b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/CheckedApplicationFieldMap.java new file mode 100644 index 00000000000..e27b6349399 --- /dev/null +++ b/bpm/bonita-common/src/main/java/org/bonitasoft/engine/business/application/CheckedApplicationFieldMap.java @@ -0,0 +1,107 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.engine.business.application; + +import java.io.Serializable; +import java.text.MessageFormat; +import java.util.Collection; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Predicate; + +/** + * A Map which first checks that the key {@link ApplicationField} is correct. + */ +class CheckedApplicationFieldMap implements Map { + + private final Map m; + private final Predicate isValidKey; + + CheckedApplicationFieldMap(Map m, Predicate isValidKey) { + this.m = Objects.requireNonNull(m); + this.isValidKey = Objects.requireNonNull(isValidKey); + } + + private ApplicationField checkKey(ApplicationField key) { + if (!isValidKey.test(key)) { + throw new IllegalArgumentException( + MessageFormat.format("Attempt to insert {0} in a specialized map which does not support it.", + key.name())); + } + return key; + } + + @Override + public int size() { + return m.size(); + } + + @Override + public boolean isEmpty() { + return m.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return m.containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return m.containsValue(value); + } + + @Override + public Serializable get(Object key) { + return m.get(key); + } + + @Override + public Serializable put(ApplicationField key, Serializable value) { + return m.put(checkKey(key), value); + } + + @Override + public Serializable remove(Object key) { + return m.remove(key); + } + + @Override + public void putAll(Map map) { + map.keySet().forEach(this::checkKey); + m.putAll(map); + } + + @Override + public void clear() { + m.clear(); + } + + @Override + public Set keySet() { + return m.keySet(); + } + + @Override + public Collection values() { + return m.values(); + } + + @Override + public Set> entrySet() { + return m.entrySet(); + } + +} diff --git a/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/SQLServerInterceptor.java b/bpm/bonita-common/src/test/java/org/bonitasoft/engine/business/application/ApplicationLinkUpdaterTest.java similarity index 60% rename from services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/SQLServerInterceptor.java rename to bpm/bonita-common/src/test/java/org/bonitasoft/engine/business/application/ApplicationLinkUpdaterTest.java index 7a8cd5c7d93..0266ab11f1a 100644 --- a/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/SQLServerInterceptor.java +++ b/bpm/bonita-common/src/test/java/org/bonitasoft/engine/business/application/ApplicationLinkUpdaterTest.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2019 Bonitasoft S.A. + * Copyright (C) 2024 Bonitasoft S.A. * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble * This library is free software; you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Foundation @@ -11,20 +11,19 @@ * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301, USA. **/ -package org.bonitasoft.engine.persistence; +package org.bonitasoft.engine.business.application; -import org.hibernate.EmptyInterceptor; +import static org.junit.Assert.assertThrows; -/** - * @author Matthieu Chaffotte - */ -public class SQLServerInterceptor extends EmptyInterceptor { +import org.junit.Test; + +public class ApplicationLinkUpdaterTest { - private static final long serialVersionUID = -6720122264417020259L; + @Test + public void should_not_update_home_page_field() { + ApplicationLinkUpdater linkUpdater = new ApplicationLinkUpdater(); - @Override - public String onPrepareStatement(final String sql) { - // this replace does not work with prepared statements - return sql.replace("like '", "like N'").replace("LIKE '", "like N'"); + assertThrows(IllegalArgumentException.class, + () -> linkUpdater.getFields().put(ApplicationField.HOME_PAGE_ID, 2L)); } } diff --git a/bpm/bonita-core/bonita-actor-mapping/build.gradle b/bpm/bonita-core/bonita-actor-mapping/build.gradle index 8302cc28bb9..3a23372a30a 100644 --- a/bpm/bonita-core/bonita-actor-mapping/build.gradle +++ b/bpm/bonita-core/bonita-actor-mapping/build.gradle @@ -7,7 +7,6 @@ dependencies { api project(':services:bonita-events') api project(':services:bonita-log') api project(':services:bonita-persistence') - testImplementation libs.junit4 testImplementation libs.mockitoCore testImplementation libs.assertj diff --git a/bpm/bonita-core/bonita-category/build.gradle b/bpm/bonita-core/bonita-category/build.gradle index 2040855d348..30ce73cd80d 100644 --- a/bpm/bonita-core/bonita-category/build.gradle +++ b/bpm/bonita-core/bonita-category/build.gradle @@ -7,7 +7,6 @@ dependencies { api project(':services:bonita-events') api project(':services:bonita-log') api project(':services:bonita-persistence') - testImplementation libs.junit4 testImplementation libs.mockitoCore annotationProcessor libs.lombok diff --git a/bpm/bonita-core/bonita-contract-data/build.gradle b/bpm/bonita-core/bonita-contract-data/build.gradle index 2337b70aaa7..07ee5e19754 100644 --- a/bpm/bonita-core/bonita-contract-data/build.gradle +++ b/bpm/bonita-core/bonita-contract-data/build.gradle @@ -6,7 +6,6 @@ dependencies { api project(':services:bonita-log') api project(':services:bonita-archive') api project(':services:bonita-persistence') - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.mockitoCore diff --git a/bpm/bonita-core/bonita-core-data/build.gradle b/bpm/bonita-core/bonita-core-data/build.gradle index cf3d6104388..2e057e50e7a 100644 --- a/bpm/bonita-core/bonita-core-data/build.gradle +++ b/bpm/bonita-core/bonita-core-data/build.gradle @@ -6,7 +6,6 @@ dependencies { api libs.commonsLang api project(':services:bonita-cache') api project(':services:bonita-persistence') - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.mockitoCore } diff --git a/bpm/bonita-core/bonita-core-data/src/main/java/org/bonitasoft/engine/core/data/instance/impl/TransientDataServiceImpl.java b/bpm/bonita-core/bonita-core-data/src/main/java/org/bonitasoft/engine/core/data/instance/impl/TransientDataServiceImpl.java index c901181699e..8f38c3360f5 100644 --- a/bpm/bonita-core/bonita-core-data/src/main/java/org/bonitasoft/engine/core/data/instance/impl/TransientDataServiceImpl.java +++ b/bpm/bonita-core/bonita-core-data/src/main/java/org/bonitasoft/engine/core/data/instance/impl/TransientDataServiceImpl.java @@ -272,7 +272,7 @@ public List getDataInstances(final long containerId, final String } catch (SProcessDefinitionNotFoundException | SFlowNodeNotFoundException | SFlowNodeReadException | SBonitaReadException e) { throw new SDataInstanceException( - String.format("An error occured while retrieving transient data for container %s with type %s", + String.format("An error occurred while retrieving transient data for container %s with type %s", containerId, containerType), e); } diff --git a/bpm/bonita-core/bonita-form-mapping/build.gradle b/bpm/bonita-core/bonita-form-mapping/build.gradle index aea34a5c38c..7b4992b1a70 100644 --- a/bpm/bonita-core/bonita-form-mapping/build.gradle +++ b/bpm/bonita-core/bonita-form-mapping/build.gradle @@ -10,7 +10,6 @@ dependencies { api project(':services:bonita-commons') api project(':services:bonita-events') api libs.hibernateCore - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.mockitoCore diff --git a/bpm/bonita-core/bonita-home-server/build.gradle b/bpm/bonita-core/bonita-home-server/build.gradle index c7ad1f6bfb2..73cf669c326 100644 --- a/bpm/bonita-core/bonita-home-server/build.gradle +++ b/bpm/bonita-core/bonita-home-server/build.gradle @@ -4,7 +4,6 @@ dependencies { api project(':bpm:bonita-common') api libs.commonsIO api project(':platform:platform-resources') - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.mockitoCore testImplementation libs.systemRules diff --git a/bpm/bonita-core/bonita-home-server/src/main/java/org/bonitasoft/engine/home/BonitaHomeServer.java b/bpm/bonita-core/bonita-home-server/src/main/java/org/bonitasoft/engine/home/BonitaHomeServer.java index 55bab6bd13b..bf2b1b1e153 100644 --- a/bpm/bonita-core/bonita-home-server/src/main/java/org/bonitasoft/engine/home/BonitaHomeServer.java +++ b/bpm/bonita-core/bonita-home-server/src/main/java/org/bonitasoft/engine/home/BonitaHomeServer.java @@ -107,7 +107,6 @@ public Properties getTenantProperties(long tenantId) throws IOException { Properties allProperties = getPlatformProperties(); Properties tenantProperties = mergeProperties(getPropertiesFromClassPath( "bonita-tenant-community.properties", - "bonita-tenant-private-community.properties", "bonita-tenant-sp.properties", "bonita-tenant-sp-cluster.properties"), getConfigurationService().getTenantEngineConf(tenantId)); allProperties.putAll(tenantProperties); diff --git a/bpm/bonita-core/bonita-login/build.gradle b/bpm/bonita-core/bonita-login/build.gradle index af2d9e56711..995361e9f0e 100644 --- a/bpm/bonita-core/bonita-login/build.gradle +++ b/bpm/bonita-core/bonita-login/build.gradle @@ -6,7 +6,6 @@ dependencies { api project(':services:bonita-authentication') api project(':services:bonita-profile') api project(':services:bonita-authorization') - testImplementation libs.junit4 testImplementation libs.mockitoCore testImplementation libs.assertj testImplementation libs.logback diff --git a/bpm/bonita-core/bonita-parameter/build.gradle b/bpm/bonita-core/bonita-parameter/build.gradle index a2543c28fe3..035fcda6e30 100644 --- a/bpm/bonita-core/bonita-parameter/build.gradle +++ b/bpm/bonita-core/bonita-parameter/build.gradle @@ -7,7 +7,6 @@ dependencies { api project(':services:bonita-cache') api project(':services:bonita-builder') api project(':services:bonita-persistence') - testImplementation libs.junit4 testImplementation libs.mockitoCore testImplementation libs.assertj testImplementation libs.systemRules diff --git a/bpm/bonita-core/bonita-parameter/src/main/java/org/bonitasoft/engine/parameter/ParameterService.java b/bpm/bonita-core/bonita-parameter/src/main/java/org/bonitasoft/engine/parameter/ParameterService.java index 7d40201e7b7..366d4dc454c 100644 --- a/bpm/bonita-core/bonita-parameter/src/main/java/org/bonitasoft/engine/parameter/ParameterService.java +++ b/bpm/bonita-core/bonita-parameter/src/main/java/org/bonitasoft/engine/parameter/ParameterService.java @@ -50,9 +50,9 @@ void update(final long processDefinitionId, final String parameterName, final St * @param parameters * parameters to merge * @throws SBonitaReadException - * error thrown if an error occured while retrieving the process definition + * error thrown if an error occurred while retrieving the process definition * @throws SObjectModificationException - * error thrown if an error occured while updating the parameter value + * error thrown if an error occurred while updating the parameter value */ void merge(long processDefinitionId, Map parameters) throws SBonitaReadException, SObjectModificationException; diff --git a/bpm/bonita-core/bonita-platform-login/build.gradle b/bpm/bonita-core/bonita-platform-login/build.gradle index f5feb9734dc..2a2789d992a 100644 --- a/bpm/bonita-core/bonita-platform-login/build.gradle +++ b/bpm/bonita-core/bonita-platform-login/build.gradle @@ -4,6 +4,5 @@ dependencies { api project(':services:bonita-commons') api project(':services:bonita-platform-session') api project(':services:bonita-platform-authentication') - testImplementation libs.junit4 testImplementation libs.mockitoCore } diff --git a/bpm/bonita-core/bonita-process-definition/build.gradle b/bpm/bonita-core/bonita-process-definition/build.gradle index 6f06cb4b8cf..3a2751dd301 100644 --- a/bpm/bonita-core/bonita-process-definition/build.gradle +++ b/bpm/bonita-core/bonita-process-definition/build.gradle @@ -12,7 +12,6 @@ dependencies { api project(':services:bonita-data-instance') api project(':services:bonita-classloader') api project(':services:bonita-builder') - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.mockitoCore testImplementation libs.logback diff --git a/bpm/bonita-core/bonita-process-engine/build.gradle b/bpm/bonita-core/bonita-process-engine/build.gradle index ed884f6b7b2..49c411191f8 100644 --- a/bpm/bonita-core/bonita-process-engine/build.gradle +++ b/bpm/bonita-core/bonita-process-engine/build.gradle @@ -72,13 +72,9 @@ dependencies { annotationProcessor libs.lombok compileOnly libs.lombok - testImplementation libs.junit5api testImplementation libs.junit5params - testRuntimeOnly libs.junitJupiterEngine - testRuntimeOnly libs.junitVintageEngine testAnnotationProcessor libs.lombok - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.mockitoJunitJupiter testImplementation libs.systemRules // works with Junit4 @@ -89,7 +85,3 @@ dependencies { testImplementation libs.awaitility testRuntimeOnly libs.logback } - -test { - useJUnitPlatform() -} diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/EngineInitializer.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/EngineInitializer.java index e8ec4bfef69..288e9f9e8ea 100644 --- a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/EngineInitializer.java +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/EngineInitializer.java @@ -68,6 +68,8 @@ public void initializeEngine() throws Exception { LOGGER.info("Starting node..."); logEditionMessage(); + logDataCollectionMessage(); + platformAPI.startNode(); LOGGER.info("Node started successfully."); final long after = System.currentTimeMillis(); @@ -92,6 +94,27 @@ protected void logEditionMessage() { LOGGER.info(" |___/ "); } + public void logDataCollectionMessage() { + LOGGER.info("-----------------------------------------------------------------------------------------"); + LOGGER.info("Anonymous Data Collection for Product Improvement"); + LOGGER.info(""); + LOGGER.info("Dear User,"); + LOGGER.info(""); + LOGGER.info("We collect strictly anonymous usage data from Bonita Studio and the Runtime (production"); + LOGGER.info("environment) to help us continuously improve the product and enhance the user experience."); + LOGGER.info("The data collected is fully anonymous and cannot be used to identify you in any way."); + LOGGER.info(""); + LOGGER.info("This data helps us understand how the product is used in both development and production"); + LOGGER.info("settings, allowing us to optimize performance, fix bugs, and introduce new features that"); + LOGGER.info("benefit all users."); + LOGGER.info(""); + LOGGER.info("For more information on what data we collect and how to opt-out, please visit our"); + LOGGER.info("Product Documentation (https://documentation.bonitasoft.com/bonita/latest)."); + LOGGER.info(""); + LOGGER.info("Thank you for supporting the ongoing improvement of our product!"); + LOGGER.info("-----------------------------------------------------------------------------------------"); + } + SessionAccessor getSessionAccessor() throws BonitaHomeNotSetException, IOException, BonitaHomeConfigurationException, ReflectiveOperationException { return getServiceAccessorFactory().createSessionAccessor(); diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/ApplicationAPIImpl.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/ApplicationAPIImpl.java index 573515b2bdc..9f7651e3163 100755 --- a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/ApplicationAPIImpl.java +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/ApplicationAPIImpl.java @@ -72,6 +72,16 @@ public Application createApplication(final ApplicationCreator applicationCreator return getLivingApplicationAPIDelegate().createApplication(applicationCreator); } + /** + * {@inheritDoc} + */ + @Override + @Deprecated(since = "10.2.0") + public ApplicationLink createApplicationLink(final ApplicationLinkCreator applicationLinkCreator) + throws CreationException { + return getLivingApplicationAPIDelegate().createApplicationLink(applicationLinkCreator); + } + private LivingApplicationAPIDelegate getLivingApplicationAPIDelegate() { return new LivingApplicationAPIDelegate(getServiceAccessor(), getApplicationModelConverter(getServiceAccessor().getPageService()), @@ -117,13 +127,13 @@ protected NodeToApplicationConverter getNodeToApplicationConverter(final PageSer } @Override - public Application getApplication(final long applicationId) throws ApplicationNotFoundException { - return getLivingApplicationAPIDelegate().getApplication(applicationId); + public IApplication getIApplication(final long applicationId) throws ApplicationNotFoundException { + return getLivingApplicationAPIDelegate().getIApplication(applicationId); } @Override - public Application getApplicationByToken(final String applicationToken) throws ApplicationNotFoundException { - return getLivingApplicationAPIDelegate().getApplicationByToken(applicationToken); + public IApplication getIApplicationByToken(final String applicationToken) throws ApplicationNotFoundException { + return getLivingApplicationAPIDelegate().getIApplicationByToken(applicationToken); } @Override @@ -142,6 +152,17 @@ public Application updateApplication(final long applicationId, final Application return getLivingApplicationAPIDelegate().updateApplication(applicationId, updater); } + /** + * {@inheritDoc} + */ + @Override + @Deprecated(since = "10.2.0") + public ApplicationLink updateApplicationLink(final long applicationId, final ApplicationLinkUpdater updater) + throws ApplicationNotFoundException, UpdateException, + AlreadyExistsException { + return getLivingApplicationAPIDelegate().updateApplicationLink(applicationId, updater); + } + protected ServiceAccessor getServiceAccessor() { try { return ServiceAccessorFactory.getInstance().createServiceAccessor(); @@ -150,6 +171,10 @@ protected ServiceAccessor getServiceAccessor() { } } + /** + * @deprecated as of 10.2.0, use {@link #searchIApplications(SearchOptions)} instead to include application links. + */ + @Deprecated(since = "10.2.0") @Override public SearchResult searchApplications(final SearchOptions searchOptions) throws SearchException { final ServiceAccessor serviceAccessor = getServiceAccessor(); @@ -165,22 +190,64 @@ public SearchResult searchApplications(final SearchOptions searchOp .collect(Collectors.toList())); final String userId = String.valueOf(filterOnUserId.get().getValue()); if (String.valueOf(SessionService.SYSTEM_ID).equals(userId)) { // It's the tenant admin user - return getLivingApplicationAPIDelegate().searchApplications(new SearchApplications( + return getLivingApplicationAPIDelegate().searchIApplications(new SearchApplications( + Application.class, applicationService, appSearchDescriptor, searchOptionsWithoutUserId .filter(APPLICATION_VISIBILITY, INTERNAL_PROFILE_SUPER_ADMIN.getProfileName()).done(), converter)); } else { - return getLivingApplicationAPIDelegate().searchApplications(new SearchApplicationsOfUser( + return getLivingApplicationAPIDelegate().searchIApplications(new SearchApplicationsOfUser( + Application.class, Long.parseLong(userId), applicationService, appSearchDescriptor, searchOptionsWithoutUserId.done(), converter)); } } return getLivingApplicationAPIDelegate() - .searchApplications(new SearchApplications(applicationService, appSearchDescriptor, + .searchIApplications(new SearchApplications(Application.class, applicationService, appSearchDescriptor, searchOptions, converter)); } + @Override + public SearchResult searchIApplications(final SearchOptions searchOptions) throws SearchException { + final ServiceAccessor serviceAccessor = getServiceAccessor(); + final SearchApplicationDescriptor appSearchDescriptor = serviceAccessor.getSearchEntitiesDescriptor() + .getSearchApplicationDescriptor(); + return internalSearchIApplications(serviceAccessor, appSearchDescriptor, searchOptions); + } + + protected SearchResult internalSearchIApplications(ServiceAccessor serviceAccessor, + SearchApplicationDescriptor appSearchDescriptor, SearchOptions searchOptions) throws SearchException { + final ApplicationModelConverter converter = getApplicationModelConverter(serviceAccessor.getPageService()); + final ApplicationService applicationService = serviceAccessor.getApplicationService(); + final Optional filterOnUserId = searchOptions.getFilters().stream() + .filter(s -> s.getField().equals(USER_ID)).findFirst(); + if (filterOnUserId.isPresent()) { + final SearchOptionsBuilder searchOptionsWithoutUserId = new SearchOptionsBuilder(searchOptions) + .setFilters(searchOptions.getFilters().stream().filter(s -> !s.getField().equals(USER_ID)) + .collect(Collectors.toList())); + final String userId = String.valueOf(filterOnUserId.get().getValue()); + if (String.valueOf(SessionService.SYSTEM_ID).equals(userId)) { // It's the tenant admin user + return getLivingApplicationAPIDelegate() + .searchIApplications(SearchApplications.defaultSearchApplications( + applicationService, appSearchDescriptor, + searchOptionsWithoutUserId + .filter(APPLICATION_VISIBILITY, INTERNAL_PROFILE_SUPER_ADMIN.getProfileName()) + .done(), + converter)); + } else { + return getLivingApplicationAPIDelegate() + .searchIApplications(SearchApplicationsOfUser.defaultSearchApplicationsOfUser( + Long.parseLong(userId), applicationService, appSearchDescriptor, + searchOptionsWithoutUserId.done(), converter)); + } + } + return getLivingApplicationAPIDelegate() + .searchIApplications( + SearchApplications.defaultSearchApplications(applicationService, appSearchDescriptor, + searchOptions, converter)); + } + /** * {@inheritDoc} */ diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/ProcessStarter.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/ProcessStarter.java index c2235986869..05d8c9453eb 100755 --- a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/ProcessStarter.java +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/ProcessStarter.java @@ -39,7 +39,11 @@ import org.bonitasoft.engine.core.process.instance.model.SProcessInstance; import org.bonitasoft.engine.exception.BonitaRuntimeException; import org.bonitasoft.engine.exception.RetrieveException; -import org.bonitasoft.engine.execution.*; +import org.bonitasoft.engine.execution.Filter; +import org.bonitasoft.engine.execution.FlowNodeNameFilter; +import org.bonitasoft.engine.execution.FlowNodeSelector; +import org.bonitasoft.engine.execution.ProcessExecutor; +import org.bonitasoft.engine.execution.StartFlowNodeFilter; import org.bonitasoft.engine.identity.IdentityService; import org.bonitasoft.engine.identity.model.SUser; import org.bonitasoft.engine.operation.Operation; @@ -110,6 +114,12 @@ public ProcessInstance start() throw new RetrieveException(e); } catch (final SProcessDefinitionException e) { throw new ProcessActivationException(e); + } catch (final SProcessInstanceCreationException e) { + if (e.getRetryAfter() != -1L) { + throw new ProcessExecutionException(e, e.getRetryAfter()); + } else { + throw new ProcessExecutionException(e); + } } catch (final SBonitaException e) { throw new ProcessExecutionException(e); } diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/ServerAPIImpl.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/ServerAPIImpl.java index 26241b8f519..ffb2814c121 100644 --- a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/ServerAPIImpl.java +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/ServerAPIImpl.java @@ -70,8 +70,9 @@ * valid, is on the right scope (tenant or platform), and renew it *

  • When the method is NOT annotated with {@link CustomTransactions}, it opens a transaction
  • *
  • When the method is deprecated, it print a warning
  • - *
  • When the method or class is annotated with {@link AvailableInMaintenanceMode}, it verifies the maintenance mode - * is enabled
  • + *
  • When the method or class is NOT annotated with {@link AvailableInMaintenanceMode}, it verifies the + * maintenance mode + * is disabled
  • *
  • When the method or class is annotated with {@link AvailableInMaintenanceMode} and onlyAvailableInMaintenanceMode * is set * to true, it verifies the maintenance mode is enabled
  • @@ -135,17 +136,21 @@ public Object invokeMethod(final Map options, final String } } catch (final BonitaRuntimeException | BonitaException bre) { fillGlobalContextForException(session, bre); + // reset class loader + Thread.currentThread().setContextClassLoader(baseClassLoader); throw createServerWrappedException(bre); } catch (final UndeclaredThrowableException ute) { + // reset class loader + Thread.currentThread().setContextClassLoader(baseClassLoader); throw createServerWrappedException(ute); } catch (final Throwable cause) { final BonitaRuntimeException throwableToWrap = wrapThrowable(cause); fillGlobalContextForException(session, throwableToWrap); + // reset class loader + Thread.currentThread().setContextClassLoader(baseClassLoader); throw createServerWrappedException(throwableToWrap); } finally { cleanSessionIfNeeded(sessionAccessor); - // reset class loader - Thread.currentThread().setContextClassLoader(baseClassLoader); logger.trace("End Server API call {} {}", apiInterfaceName, methodName); } } diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/application/installer/ApplicationInstaller.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/application/installer/ApplicationInstaller.java index 530fe56d461..14bbc478df0 100644 --- a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/application/installer/ApplicationInstaller.java +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/application/installer/ApplicationInstaller.java @@ -13,868 +13,17 @@ **/ package org.bonitasoft.engine.api.impl.application.installer; -import static java.lang.String.format; -import static java.lang.System.lineSeparator; -import static java.util.stream.Collectors.joining; -import static org.apache.commons.lang3.StringUtils.isNotBlank; -import static org.bonitasoft.engine.api.result.Status.*; -import static org.bonitasoft.engine.api.result.StatusCode.*; -import static org.bonitasoft.engine.api.result.StatusContext.*; -import static org.bonitasoft.engine.bpm.process.ActivationState.DISABLED; -import static org.bonitasoft.engine.bpm.process.ConfigurationState.RESOLVED; -import static org.bonitasoft.engine.business.application.ApplicationImportPolicy.FAIL_ON_DUPLICATES; +import java.io.File; -import java.io.*; -import java.net.URLConnection; -import java.nio.file.Files; -import java.util.*; -import java.util.concurrent.Callable; -import java.util.stream.Collectors; - -import javax.xml.bind.JAXBException; - -import lombok.Builder; -import lombok.Data; -import lombok.NonNull; -import lombok.extern.slf4j.Slf4j; -import org.bonitasoft.engine.api.ImportError; -import org.bonitasoft.engine.api.ImportStatus; -import org.bonitasoft.engine.api.impl.ProcessDeploymentAPIDelegate; -import org.bonitasoft.engine.api.impl.ProcessManagementAPIImplDelegate; -import org.bonitasoft.engine.api.impl.organization.OrganizationAPIDelegate; -import org.bonitasoft.engine.api.impl.page.PageAPIDelegate; -import org.bonitasoft.engine.api.impl.resolver.BusinessArchiveArtifactsManager; import org.bonitasoft.engine.api.result.ExecutionResult; -import org.bonitasoft.engine.api.result.Status; -import org.bonitasoft.engine.api.result.StatusCode; -import org.bonitasoft.engine.api.utils.VisibleForTesting; -import org.bonitasoft.engine.bpm.bar.BusinessArchive; -import org.bonitasoft.engine.bpm.bar.BusinessArchiveFactory; -import org.bonitasoft.engine.bpm.bar.InvalidBusinessArchiveFormatException; -import org.bonitasoft.engine.bpm.process.*; -import org.bonitasoft.engine.business.application.ApplicationImportPolicy; -import org.bonitasoft.engine.business.application.exporter.ApplicationNodeContainerConverter; -import org.bonitasoft.engine.business.application.importer.ApplicationImporter; -import org.bonitasoft.engine.business.application.importer.StrategySelector; -import org.bonitasoft.engine.business.application.xml.ApplicationNode; -import org.bonitasoft.engine.business.data.*; -import org.bonitasoft.engine.commons.exceptions.SBonitaException; -import org.bonitasoft.engine.exception.*; -import org.bonitasoft.engine.identity.ImportPolicy; -import org.bonitasoft.engine.identity.OrganizationImportException; -import org.bonitasoft.engine.io.FileOperations; -import org.bonitasoft.engine.page.Page; -import org.bonitasoft.engine.page.PageCreator; -import org.bonitasoft.engine.page.PageSearchDescriptor; -import org.bonitasoft.engine.page.PageUpdater; -import org.bonitasoft.engine.platform.PlatformService; -import org.bonitasoft.engine.platform.exception.SPlatformUpdateException; -import org.bonitasoft.engine.platform.model.STenant; -import org.bonitasoft.engine.platform.model.builder.SPlatformUpdateBuilder; -import org.bonitasoft.engine.platform.model.builder.impl.SPlatformUpdateBuilderImpl; -import org.bonitasoft.engine.recorder.model.EntityUpdateDescriptor; -import org.bonitasoft.engine.search.SearchOptionsBuilder; -import org.bonitasoft.engine.service.InstallationFailedException; -import org.bonitasoft.engine.service.InstallationService; -import org.bonitasoft.engine.service.ServiceAccessor; -import org.bonitasoft.engine.service.ServiceAccessorSingleton; -import org.bonitasoft.engine.session.SessionService; -import org.bonitasoft.engine.session.model.SSession; -import org.bonitasoft.engine.sessionaccessor.SessionAccessor; -import org.bonitasoft.engine.tenant.TenantStateManager; -import org.bonitasoft.engine.transaction.UserTransactionService; -import org.bonitasoft.platform.exception.PlatformException; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; -import org.springframework.stereotype.Component; -import org.xml.sax.SAXException; - -/** - * Main entry point to deploy an {@link ApplicationArchive}. - * - * @author Baptiste Mesta. - * @author Danila Mazour - * @author Haroun El Alami - */ - -@Slf4j -@Component -@ConditionalOnSingleCandidate(ApplicationInstaller.class) -public class ApplicationInstaller { - - private static final String PAGE_TOKEN_PROPERTY = "name"; - private static final String PAGE_DISPLAY_NAME_PROPERTY = "displayName"; - private static final String PAGE_DESCRIPTION_PROPERTY = "description"; - private static final String PAGE_CONTENT_TYPE_PROPERTY = "contentType"; - - private final InstallationService installationService; - private final BusinessDataModelRepository bdmRepository; - private final UserTransactionService transactionService; - private final TenantStateManager tenantStateManager; - private final SessionAccessor sessionAccessor; - private final SessionService sessionService; - private final BusinessArchiveArtifactsManager businessArchiveArtifactsManager; - private final ApplicationImporter applicationImporter; - private final Long tenantId; - private final ApplicationNodeContainerConverter appXmlConverter = new ApplicationNodeContainerConverter(); - - public ApplicationInstaller(InstallationService installationService, - @Qualifier("businessDataModelRepository") BusinessDataModelRepository bdmRepository, - UserTransactionService transactionService, @Value("${tenantId}") Long tenantId, - SessionAccessor sessionAccessor, SessionService sessionService, TenantStateManager tenantStateManager, - @Qualifier("dependencyResolver") BusinessArchiveArtifactsManager businessArchiveArtifactsManager, - ApplicationImporter applicationImporter) { - this.installationService = installationService; - this.bdmRepository = bdmRepository; - this.transactionService = transactionService; - this.tenantId = tenantId; - this.sessionAccessor = sessionAccessor; - this.sessionService = sessionService; - this.tenantStateManager = tenantStateManager; - this.businessArchiveArtifactsManager = businessArchiveArtifactsManager; - this.applicationImporter = applicationImporter; - } - - private PageAPIDelegate getPageAPIDelegate() { - return PageAPIDelegate.getInstance(); - } - - private OrganizationAPIDelegate getOrganizationImporter() { - return OrganizationAPIDelegate.getInstance(); - } - - public void install(ApplicationArchive applicationArchive) throws ApplicationInstallationException { - if (applicationArchive.isEmpty()) { - throw new ApplicationInstallationException("The Application Archive contains no valid artifact to install"); - } - final ExecutionResult executionResult = new ExecutionResult(); - try { - final long startPoint = System.currentTimeMillis(); - log.info("Starting Application Archive installation..."); - installBusinessDataModel(applicationArchive); - inSession(() -> inTransaction(() -> { - var newlyInstalledProcessIds = installArtifacts(applicationArchive, executionResult); - enableResolvedProcesses(newlyInstalledProcessIds, executionResult); - updateApplicationVersion(applicationArchive.getVersion()); - return null; - })); - log.info("The Application Archive (version {}) has been installed successfully in {} ms.", - applicationArchive.getVersion(), (System.currentTimeMillis() - startPoint)); - } catch (Exception e) { - throw new ApplicationInstallationException("The Application Archive install operation has been aborted", e); - } finally { - logInstallationResult(executionResult); - } - if (executionResult.hasErrors()) { - throw new ApplicationInstallationException("The Application Archive install operation has been aborted"); - } - } - - protected List installArtifacts(ApplicationArchive applicationArchive, ExecutionResult executionResult) - throws Exception { - installOrganization(applicationArchive, executionResult); - installOrUpdateRestApiExtensions(applicationArchive, executionResult); - installOrUpdatePages(applicationArchive, executionResult); - installOrUpdateLayouts(applicationArchive, executionResult); - installOrUpdateThemes(applicationArchive, executionResult); - installLivingApplications(applicationArchive, executionResult, FAIL_ON_DUPLICATES); - var installedProcessIds = installProcesses(applicationArchive, executionResult); - applicationArchive.getConfigurationFile().ifPresent(configFile -> installConfiguration(configFile, - executionResult)); - return installedProcessIds; - } - - public void update(ApplicationArchive applicationArchive) throws ApplicationInstallationException { - if (applicationArchive.isEmpty()) { - throw new ApplicationInstallationException("The Application Archive contains no valid artifact to install"); - } - final ExecutionResult executionResult = new ExecutionResult(); - try { - final long startPoint = System.currentTimeMillis(); - log.info("Starting Application Archive installation..."); - installBusinessDataModel(applicationArchive); - inSession(() -> inTransaction(() -> { - List newlyInstalledProcessIds = updateArtifacts(applicationArchive, executionResult); - disableOldProcesses(newlyInstalledProcessIds, executionResult); - enableResolvedProcesses(newlyInstalledProcessIds, executionResult); - updateApplicationVersion(applicationArchive.getVersion()); - return null; - })); - log.info("The Application Archive has been installed successfully in {} ms.", - (System.currentTimeMillis() - startPoint)); - } catch (Exception e) { - throw new ApplicationInstallationException("The Application Archive update operation has been aborted", e); - } finally { - logInstallationResult(executionResult); - } - if (executionResult.hasErrors()) { - throw new ApplicationInstallationException("The Application Archive update operation has been aborted"); - } - } - - @VisibleForTesting - public void resumeTenantInSession() throws Exception { - inSession(() -> { - try { - if (Objects.equals(STenant.PAUSED, tenantStateManager.getStatus())) { - tenantStateManager.resume(); - transactionService.executeInTransaction(() -> { - businessArchiveArtifactsManager.resolveDependenciesForAllProcesses(getServiceAccessor()); - return null; - }); - } - } catch (Exception e) { - throw new UpdateException(e); - } - return null; - }); - } - - @VisibleForTesting - public void pauseTenantInSession() throws Exception { - inSession(() -> { - try { - String status = tenantStateManager.getStatus(); - if (STenant.ACTIVATED.equals(status)) { - tenantStateManager.pause(); - } else if (!STenant.PAUSED.equals(status)) { - throw new UpdateException( - "The default tenant is in state " + status + " and cannot be paused. Aborting."); - } - } catch (Exception e) { - throw new UpdateException(e); - } - return null; - }); - } - - protected List updateArtifacts(ApplicationArchive applicationArchive, ExecutionResult executionResult) - throws Exception { - updateOrganization(applicationArchive, executionResult); - - installOrUpdateRestApiExtensions(applicationArchive, executionResult); - installOrUpdatePages(applicationArchive, executionResult); - installOrUpdateLayouts(applicationArchive, executionResult); - installOrUpdateThemes(applicationArchive, executionResult); - installLivingApplications(applicationArchive, executionResult, ApplicationImportPolicy.REPLACE_DUPLICATES); - - List newlyInstalledProcessIds = installProcesses(applicationArchive, executionResult); - applicationArchive.getConfigurationFile().ifPresent(configFile -> installConfiguration(configFile, - executionResult)); - return newlyInstalledProcessIds; - } - - @VisibleForTesting - public void updateApplicationVersion(String version) throws PlatformException { - try { - PlatformService platformService = getServiceAccessor().getPlatformService(); - platformService.updatePlatform(getPlatformUpdateBuilder() - .setApplicationVersion(version).done()); - } catch (SPlatformUpdateException e) { - throw new PlatformException("Error when updating Platform application version", e); - } - } - - protected SPlatformUpdateBuilder getPlatformUpdateBuilder() { - return SPlatformUpdateBuilderImpl.builder() - .descriptor(new EntityUpdateDescriptor()) - .build(); - } - - @VisibleForTesting - void disableProcess(long processDefinitionId) throws SBonitaException { - getProcessManagementAPIDelegate().disableProcess(processDefinitionId); - } - - @VisibleForTesting - List getDeployedProcessIds() throws SearchException { - SearchOptionsBuilder optsBuilder = new SearchOptionsBuilder(0, Integer.MAX_VALUE); - return getProcessDeploymentAPIDelegate() - .searchProcessDeploymentInfos(optsBuilder.done()).getResult() - .stream().map(ProcessDeploymentInfo::getProcessId).collect(Collectors.toList()); - } - - @VisibleForTesting - Optional getDeployedProcessId(String name, String version) { - try { - return Optional.of(getProcessDeploymentAPIDelegate().getProcessDefinitionId(name, version)); - } catch (ProcessDefinitionNotFoundException e) { - return Optional.empty(); - } - } - - public void disableOldProcesses(List installedProcessIds, ExecutionResult executionResult) - throws SearchException, SBonitaException, ProcessDefinitionNotFoundException { - List deployedProcessIds = getDeployedProcessIds(); - // remove installed process ids - deployedProcessIds.removeAll(installedProcessIds); - // disable all processes - for (Long processId : deployedProcessIds) { - // get process Info - ProcessDeploymentInfo info = getProcessDeploymentInfo(processId); - if (info.getActivationState() == ActivationState.ENABLED) { - disableProcess(processId); - executionResult.addStatus(infoStatus(PROCESS_DEPLOYMENT_DISABLEMENT_OK, - format("Process %s (%s) has been disabled successfully", - info.getDisplayName(), info.getVersion()))); - } - } - } - - @VisibleForTesting - ProcessDeploymentInfo getProcessDeploymentInfo(Long processId) throws ProcessDefinitionNotFoundException { - return getProcessDeploymentAPIDelegate().getProcessDeploymentInfo(processId); - } - - public void enableResolvedProcesses(List processDefinitionIds, ExecutionResult executionResult) - throws ProcessDeployException { - Collection processDeploymentInfos = getProcessDeploymentAPIDelegate() - .getProcessDeploymentInfosFromIds(processDefinitionIds) - .values(); - - boolean atLeastOneBlockingProblem = false; - // for all deployed process - // if resolved and not already enabled, - // enable it => if exception, add error status - // if enablement ok, add info status Ok - // if not resolved, add error status and list resolution problems - // At the end, if at least one process disabled, throw Exception to cancel deployment and startup - for (ProcessDeploymentInfo info : processDeploymentInfos) { - if (info.getConfigurationState() == RESOLVED) { - if (info.getActivationState() == DISABLED) { - try { - getProcessDeploymentAPIDelegate().enableProcess(info.getProcessId()); - } catch (ProcessDefinitionNotFoundException | ProcessEnablementException e) { - final Map context = new HashMap<>(); - context.put(PROCESS_NAME_KEY, info.getName()); - context.put(PROCESS_VERSION_KEY, info.getVersion()); - executionResult.addStatus(errorStatus(PROCESS_DEPLOYMENT_ENABLEMENT_KO, - format("Process %s (%s) could not be enabled", info.getName(), info.getVersion()), - context)); - atLeastOneBlockingProblem = true; - continue; - } - } - executionResult.addStatus(infoStatus(PROCESS_DEPLOYMENT_ENABLEMENT_OK, - format("Process %s (%s) has been enabled successfully", - info.getDisplayName(), info.getVersion()))); - } else { - try { - atLeastOneBlockingProblem = true; - List problems = getProcessDeploymentAPIDelegate() - .getProcessResolutionProblems(info.getProcessId()); - String message = format( - "Process '%s' (%s) is unresolved. It cannot be enabled for now.", - info.getDisplayName(), info.getVersion()); - String description = message + lineSeparator() - + problems.stream().map(Problem::getDescription) - .collect(joining(lineSeparator())); - executionResult.addStatus(errorStatus(PROCESS_DEPLOYMENT_ENABLEMENT_KO, description)); - } catch (ProcessDefinitionNotFoundException e) { - executionResult - .addStatus(errorStatus(PROCESS_DEPLOYMENT_ENABLEMENT_KO, "Process definition not found")); - } - } - } - - if (atLeastOneBlockingProblem) { - throw new ProcessDeployException("At least one process failed to deploy / enable. Canceling installation."); - } - } - - @VisibleForTesting - List importOrganization(File organization, ImportPolicy failOnDuplicates) - throws OrganizationImportException, IOException { - return getOrganizationImporter().importOrganizationWithWarnings( - Files.readString(organization.toPath()), - failOnDuplicates); - } - - protected void installOrganization(ApplicationArchive applicationArchive, ExecutionResult executionResult) - throws Exception { - final List warnings; - if (applicationArchive.getOrganization() == null) { - executionResult.addStatus(Status.infoStatus(ORGANIZATION_IMPORT_WARNING, - "No organization found. Use the technical user to configure the organization.")); - return; - } - try { - warnings = importOrganization(applicationArchive.getOrganization(), ImportPolicy.FAIL_ON_DUPLICATES); - } catch (IOException e) { - throw new OrganizationImportException(e); - } - for (String warning : warnings) { - executionResult.addStatus(warningStatus(ORGANIZATION_IMPORT_WARNING, warning)); - } - } - - protected void updateOrganization(ApplicationArchive applicationArchive, ExecutionResult executionResult) - throws Exception { - final List warnings; - if (applicationArchive.getOrganization() == null) { - log.info("There is no organization file in the archive. Ignoring the organization update step."); - return; - } - try { - warnings = importOrganization(applicationArchive.getOrganization(), ImportPolicy.IGNORE_DUPLICATES); - } catch (IOException e) { - throw new OrganizationImportException(e); - } - for (String warning : warnings) { - executionResult.addStatus(warningStatus(ORGANIZATION_IMPORT_WARNING, warning)); - } - } - - protected void installBusinessDataModel(ApplicationArchive applicationArchive) throws Exception { - if (applicationArchive.getBdm() != null) { - var alreadyDeployed = sameBdmContentDeployed(applicationArchive.getBdm()); - if (alreadyDeployed) { - log.info("Installed and current BDM are equivalent. No BDM update required."); - return; - } - log.info("BDM must be installed or updated..."); - pauseTenantInSession(); - final String bdmVersion = inSession( - () -> inTransaction(() -> updateBusinessDataModel(applicationArchive))); - log.info("BDM successfully installed (version({})", bdmVersion); - resumeTenantInSession(); - } - } - - boolean sameBdmContentDeployed(File bdmArchive) throws Exception { - return inSession(() -> inTransaction(() -> { - log.info("Comparing BDM to install with current BDM..."); - return bdmRepository - .isDeployed(Files.readAllBytes(bdmArchive.toPath())); - })); - } - - protected String updateBusinessDataModel(ApplicationArchive applicationArchive) - throws InvalidBusinessDataModelException, BusinessDataRepositoryDeploymentException { - String bdmVersion; - try { - uninstallBusinessDataModel(); - bdmVersion = installBusinessDataModel(Files.readAllBytes(applicationArchive.getBdm().toPath())); - } catch (IOException e) { - log.warn("Cannot read the BDM file on disk"); - log.warn( - "Caught an error when installing/updating the BDM, the transaction will be reverted and the previous BDM restored."); - throw new BusinessDataRepositoryDeploymentException(e); - } catch (Exception e) { - log.warn( - "Caught an error when installing/updating the BDM, the transaction will be reverted and the previous BDM restored."); - throw e; - } - log.info("Update operation completed, the BDM was successfully updated"); - return bdmVersion; - } - - protected void uninstallBusinessDataModel() throws BusinessDataRepositoryDeploymentException { - log.info("Uninstalling the currently deployed BDM"); - try { - tenantStateManager.executeTenantManagementOperation("BDM Uninstallation", () -> { - bdmRepository.uninstall(tenantId); - return null; - }); - log.info("BDM successfully uninstalled"); - } catch (final SBusinessDataRepositoryException sbdre) { - throw new BusinessDataRepositoryDeploymentException(sbdre); - } catch (final Exception e) { - throw new BonitaRuntimeException(e); - } - } - - protected String installBusinessDataModel(final byte[] zip) - throws InvalidBusinessDataModelException, BusinessDataRepositoryDeploymentException { - log.info("Starting the installation of the BDM."); - try { - String bdmVersion = tenantStateManager.executeTenantManagementOperation("BDM Installation", - () -> bdmRepository.install(zip, SessionService.SYSTEM_ID)); - log.info("Installation of the BDM completed."); - return bdmVersion; - } catch (final SBusinessDataRepositoryDeploymentException e) { - throw new BusinessDataRepositoryDeploymentException(e); - } catch (final InvalidBusinessDataModelException e) { - throw e; - } catch (final Exception e) { - throw new BonitaRuntimeException(e); - } - } - - protected void installLivingApplications(ApplicationArchive applicationArchive, ExecutionResult executionResult, - ApplicationImportPolicy policy) - throws AlreadyExistsException, ImportException, ApplicationInstallationException { - try { - boolean atLeastOneBlockingProblem = false; - for (File livingApplicationFile : applicationArchive.getApplications()) { - log.info("Installing Living Application from file '{}'", livingApplicationFile.getName()); - var appContainer = appXmlConverter - .unmarshallFromXML(Files.readAllBytes(livingApplicationFile.toPath())); - for (var application : appContainer.getApplications()) { - var status = importApplication(application, - getIconContent(application, applicationArchive), policy); - final Map context = new HashMap<>(); - context.put(LIVING_APPLICATION_TOKEN_KEY, status.getName()); - context.put(LIVING_APPLICATION_IMPORT_STATUS_KEY, status.getStatus()); - final List errors = status.getErrors(); - if (errors != null && !errors.isEmpty()) { - errors.forEach(error -> { - Status errorStatus = buildErrorStatus(error, livingApplicationFile.getName()); - executionResult.addStatus(errorStatus); - }); - - atLeastOneBlockingProblem = true; - continue; - } - - executionResult.addStatus( - infoStatus(LIVING_APP_DEPLOYMENT, - format("Application '%s' has been %s", status.getName(), - status.getStatus().name().toLowerCase()), - context)); - } - } - - if (atLeastOneBlockingProblem) { - throw new ApplicationInstallationException( - "At least one application failed to be installed. Canceling installation."); - } - } catch (IOException | JAXBException | SAXException e) { - throw new ImportException(e); - } - } - - private IconContent getIconContent(ApplicationNode application, ApplicationArchive applicationArchive) { - var iconPath = application.getIconPath(); - if (iconPath != null && !iconPath.isBlank()) { - var icon = applicationArchive.getApplicationIcons().stream() - .filter(iconFile -> Objects.equals(iconPath, iconFile.getName())) - .findFirst() - .map(File::toPath) - .orElse(null); - try { - if (icon != null) { - log.info("Application icon {} found for {}", icon.getFileName().toString(), - application.getDisplayName()); - var bytes = Files.readAllBytes(icon); - return IconContent.builder() - .bytes(bytes) - .mimeType(URLConnection.guessContentTypeFromName(icon.getFileName().toString())) - .build(); - } - } catch (IOException e) { - log.warn("Failed to read icon {}", icon, e); - } - } - return IconContent.builder().build(); - } - - private Status buildErrorStatus(ImportError importError, @NonNull String applicationName) { - StatusCode code = null; - switch (importError.getType()) { - case PAGE: - code = LIVING_APP_REFERENCES_UNKNOWN_PAGE; - break; - case PROFILE: - code = LIVING_APP_REFERENCES_UNKNOWN_PROFILE; - break; - case APPLICATION_PAGE: - code = LIVING_APP_REFERENCES_UNKNOWN_APPLICATION_PAGE; - break; - case LAYOUT: - code = LIVING_APP_REFERENCES_UNKNOWN_LAYOUT; - break; - case THEME: - code = LIVING_APP_REFERENCES_UNKNOWN_THEME; - break; - default: - break; - } - final Map context = new HashMap<>(); - context.put(LIVING_APPLICATION_TOKEN_KEY, applicationName); - context.put(LIVING_APPLICATION_INVALID_ELEMENT_NAME, importError.getName()); - context.put(LIVING_APPLICATION_INVALID_ELEMENT_TYPE, importError.getType()); - return errorStatus( - code, - String.format("Unknown %s named '%s'", importError.getType().name(), importError.getName()), - context); - } - - ImportStatus importApplication(final ApplicationNode application, IconContent iconContent, - ApplicationImportPolicy policy) - throws ImportException, AlreadyExistsException { - return applicationImporter.importApplication(application, true, SessionService.SYSTEM_ID, - iconContent.getBytes(), iconContent.getMimeType(), - true, - new StrategySelector().selectStrategy(policy)); - } - - protected void installOrUpdatePages(ApplicationArchive applicationArchive, ExecutionResult executionResult) - throws IOException, BonitaException { - for (File pageFile : applicationArchive.getPages()) { - installUnitPage(pageFile, "page", executionResult); - } - } - - protected void installOrUpdateLayouts(ApplicationArchive applicationArchive, ExecutionResult executionResult) - throws IOException, BonitaException { - for (File layoutFile : applicationArchive.getLayouts()) { - installUnitPage(layoutFile, "layout", executionResult); - } - } - - protected void installOrUpdateThemes(ApplicationArchive applicationArchive, ExecutionResult executionResult) - throws IOException, BonitaException { - for (File pageFile : applicationArchive.getThemes()) { - installUnitPage(pageFile, "theme", executionResult); - } - } - - protected void installOrUpdateRestApiExtensions(ApplicationArchive applicationArchive, - ExecutionResult executionResult) - throws IOException, BonitaException { - for (File pageFile : applicationArchive.getRestAPIExtensions()) { - installUnitPage(pageFile, "REST API extension", executionResult); - } - } - - /** - * From the Engine perspective, all custom pages, layouts, themes, custom Rest APIs are of type Page - */ - protected void installUnitPage(File pageFile, String precisePageType, ExecutionResult executionResult) - throws IOException, BonitaException { - var pageProperties = loadPageProperties(pageFile); - var pageToken = pageProperties.getProperty(PAGE_TOKEN_PROPERTY); - final Map context = new HashMap<>(); - context.put(PAGE_NAME_KEY, pageToken); - Page existingPage = getPageIfExist(pageToken); - if (existingPage == null) { - final Page page = createPage(pageFile, pageProperties); - log.info("Creating new {} '{}'", precisePageType, getPageName(page)); - executionResult.addStatus(infoStatus(PAGE_DEPLOYMENT_CREATE_NEW, - format("New %s '%s' has been installed", precisePageType, getPageName(page)), - context)); - } else { - updatePageContent(pageFile, existingPage.getId()); - } - } - - @VisibleForTesting - void updatePageContent(File pageFile, long pageId) throws UpdateException, IOException, AlreadyExistsException { - getPageAPIDelegate().updatePageContent(pageId, Files.readAllBytes(pageFile.toPath()), SessionService.SYSTEM_ID); - // update content name - final PageUpdater pageUpdater = new PageUpdater(); - pageUpdater.setContentName(pageFile.getName()); - getPageAPIDelegate().updatePage(pageId, pageUpdater, SessionService.SYSTEM_ID); - } - - @VisibleForTesting - Page getPageIfExist(String pageToken) throws SearchException { - List pageResearch = getPageAPIDelegate().searchPages(new SearchOptionsBuilder(0, 1) - .filter(PageSearchDescriptor.NAME, pageToken).done()).getResult(); - if (!pageResearch.isEmpty()) { - return pageResearch.get(0); - } - return null; - } - - Page createPage(File pageFile, Properties pageProperties) throws CreationException { - try { - var pageCreator = new PageCreator(pageProperties.getProperty(PAGE_TOKEN_PROPERTY), pageFile.getName()) - .setContentType(pageProperties.getProperty(PAGE_CONTENT_TYPE_PROPERTY)) - .setDisplayName(pageProperties.getProperty(PAGE_DISPLAY_NAME_PROPERTY)) - .setDescription(pageProperties.getProperty(PAGE_DESCRIPTION_PROPERTY)); - return getPageAPIDelegate().createPage(pageCreator, - Files.readAllBytes(pageFile.toPath()), - SessionService.SYSTEM_ID); - } catch (IOException e) { - throw new CreationException("Failed to read custom page content", e); - } - } - - private String getPageName(Page page) { - return isNotBlank(page.getDisplayName()) ? page.getDisplayName() : page.getName(); - } - - private Properties loadPageProperties(File zipFile) throws IOException { - var properties = new Properties(); - try (var pagePropertiesIs = new ByteArrayInputStream( - FileOperations.getFileFromZip(zipFile, "page.properties"))) { - properties.load(pagePropertiesIs); - return validatePageProperties(zipFile, properties); - } - } - - private Properties validatePageProperties(File file, Properties properties) { - String name = properties.getProperty(PAGE_TOKEN_PROPERTY); - if (name == null || name.isEmpty()) { - throw new IllegalArgumentException( - format("Invalid page %s, page.properties file do not contain mandatory '%s' attribute", - file.getName(), PAGE_TOKEN_PROPERTY)); - } - String type = properties.getProperty(PAGE_CONTENT_TYPE_PROPERTY); - if (type == null || type.isEmpty()) { - throw new IllegalArgumentException( - format("Invalid page %s, page.properties file do not contain mandatory '%s' attribute", - file.getName(), PAGE_CONTENT_TYPE_PROPERTY)); - } - return properties; - } - - protected List installProcesses(ApplicationArchive applicationArchive, ExecutionResult executionResult) - throws InvalidBusinessArchiveFormatException, IOException, ProcessDeployException { - List processDefinitionIds = new ArrayList<>(); - for (File processFile : applicationArchive.getProcesses()) { - try (var is = new FileInputStream(processFile)) { - final BusinessArchive businessArchive = BusinessArchiveFactory - .readBusinessArchive(is); - String name = businessArchive.getProcessDefinition().getName(); - String version = businessArchive.getProcessDefinition().getVersion(); - - final Map context = new HashMap<>(); - context.put(PROCESS_NAME_KEY, name); - context.put(PROCESS_VERSION_KEY, version); - - Optional deployedProcessId = getDeployedProcessId(name, version); - if (deployedProcessId.isPresent()) { - // skip install - processDefinitionIds.add(deployedProcessId.get()); - executionResult.addStatus(infoStatus(PROCESS_DEPLOYMENT_SKIP_INSTALL, - format("Process %s (%s) already exists in the database. Skipping installation.", name, - version), - context)); - } else { - processDefinitionIds.add(deployProcess(businessArchive, executionResult)); - } - } - } - return processDefinitionIds; - } - - /** - * Must be called in a transaction with active session - * - * @param configurationFileArchive - * @param executionResult - * @throws ApplicationInstallationException - */ - void installConfiguration(File configurationFileArchive, - ExecutionResult executionResult) - throws ApplicationInstallationException { - try (var is = Files.newInputStream(configurationFileArchive.toPath())) { - log.info("Installing application configuration from file"); - installationService.install(null, is.readAllBytes()); - executionResult.addStatus(Status.infoStatus(Status.okStatus().getCode(), - "Configuration file has been imported")); - } catch (IOException | InstallationFailedException e) { - throw new ApplicationInstallationException("The Application Archive install operation has been aborted", e); - } - } - - /** - * Update configuration with the given bconf file - * - * @param configurationFileArchive A bconf file - * @param executionResult - * @throws Exception - */ - public void updateConfiguration(File configurationFileArchive, ExecutionResult executionResult) throws Exception { - inSession(() -> inTransaction(() -> { - installConfiguration(configurationFileArchive, executionResult); - return null; - })); - } - - protected Long deployProcess(BusinessArchive businessArchive, ExecutionResult executionResult) - throws ProcessDeployException { - final String processName = businessArchive.getProcessDefinition().getName(); - final String processVersion = businessArchive.getProcessDefinition().getVersion(); - long processDefinitionId; - - final Map context = new HashMap<>(); - context.put(PROCESS_NAME_KEY, processName); - context.put(PROCESS_VERSION_KEY, processVersion); - try { - // Let's try to deploy the process, even if it already exists: - processDefinitionId = getProcessDeploymentAPIDelegate().deploy(businessArchive).getId(); - executionResult.addStatus(infoStatus(PROCESS_DEPLOYMENT_CREATE_NEW, - format("New process %s (%s) has been installed successfully", processName, processVersion), - context)); - - } catch (AlreadyExistsException e) { - final String message = format("Process %s - %s already exists. Abandoning.", processName, processVersion); - log.error(message); - throw new ProcessDeployException(message); - } - return processDefinitionId; - } - - @VisibleForTesting - ProcessDeploymentAPIDelegate getProcessDeploymentAPIDelegate() { - return ProcessDeploymentAPIDelegate.getInstance(); - } - - @VisibleForTesting - ProcessManagementAPIImplDelegate getProcessManagementAPIDelegate() { - return ProcessManagementAPIImplDelegate.getInstance(); - } - - @VisibleForTesting - public T inSession(Callable callable) throws Exception { - final SSession session = sessionService.createSession(tenantId, SessionService.SYSTEM); - final long sessionId = session.getId(); - log.trace("New session created with id {}", sessionId); - try { - sessionAccessor.setSessionInfo(sessionId, tenantId); - return callable.call(); - } finally { - sessionAccessor.deleteSessionId(); - sessionAccessor.deleteTenantId(); - } - } - - protected T inTransaction(Callable callable) throws ApplicationInstallationException { - try { - return transactionService.executeInTransaction(callable); - } catch (Exception e) { - throw new ApplicationInstallationException("Problem installing application", e); - } - } +import org.bonitasoft.engine.exception.ApplicationInstallationException; - private ServiceAccessor getServiceAccessor() { - return ServiceAccessorSingleton.getInstance(); - } +public interface ApplicationInstaller { - void logInstallationResult(ExecutionResult result) { - log.info("Result of the installation of the application:"); - for (Status s : result.getAllStatus()) { - var message = s.getContext() != null && !s.getContext().isEmpty() - ? String.format("%s - %s - %s", s.getCode(), s.getMessage(), - s.getContext().toString()) - : String.format("%s - %s", s.getCode(), s.getMessage()); - switch (s.getLevel()) { - case ERROR: - log.error(message); - break; - case WARNING: - log.warn(message); - break; - case INFO: - case OK: - default: - log.info(message); - break; - } - } - } + void install(ApplicationArchive applicationArchive) throws ApplicationInstallationException; - @Builder - @Data - static class IconContent { + void update(ApplicationArchive applicationArchive) throws ApplicationInstallationException; - private byte[] bytes; - private String mimeType; - } + void updateConfiguration(File configurationFileArchive, ExecutionResult executionResult) throws Exception; } diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/application/installer/ApplicationInstallerImpl.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/application/installer/ApplicationInstallerImpl.java new file mode 100644 index 00000000000..a7157875a2a --- /dev/null +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/application/installer/ApplicationInstallerImpl.java @@ -0,0 +1,882 @@ +/** + * Copyright (C) 2019 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.engine.api.impl.application.installer; + +import static java.lang.String.format; +import static java.lang.System.lineSeparator; +import static java.util.stream.Collectors.joining; +import static org.apache.commons.lang3.StringUtils.isNotBlank; +import static org.bonitasoft.engine.api.result.Status.*; +import static org.bonitasoft.engine.api.result.StatusCode.*; +import static org.bonitasoft.engine.api.result.StatusContext.*; +import static org.bonitasoft.engine.bpm.process.ActivationState.DISABLED; +import static org.bonitasoft.engine.bpm.process.ConfigurationState.RESOLVED; +import static org.bonitasoft.engine.business.application.ApplicationImportPolicy.FAIL_ON_DUPLICATES; + +import java.io.*; +import java.net.URLConnection; +import java.nio.file.Files; +import java.util.*; +import java.util.concurrent.Callable; +import java.util.stream.Collectors; + +import javax.xml.bind.JAXBException; + +import lombok.Builder; +import lombok.Data; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import org.bonitasoft.engine.api.ImportError; +import org.bonitasoft.engine.api.ImportStatus; +import org.bonitasoft.engine.api.impl.ProcessDeploymentAPIDelegate; +import org.bonitasoft.engine.api.impl.ProcessManagementAPIImplDelegate; +import org.bonitasoft.engine.api.impl.organization.OrganizationAPIDelegate; +import org.bonitasoft.engine.api.impl.page.PageAPIDelegate; +import org.bonitasoft.engine.api.impl.resolver.BusinessArchiveArtifactsManager; +import org.bonitasoft.engine.api.result.ExecutionResult; +import org.bonitasoft.engine.api.result.Status; +import org.bonitasoft.engine.api.result.StatusCode; +import org.bonitasoft.engine.api.utils.VisibleForTesting; +import org.bonitasoft.engine.bpm.bar.BusinessArchive; +import org.bonitasoft.engine.bpm.bar.BusinessArchiveFactory; +import org.bonitasoft.engine.bpm.bar.InvalidBusinessArchiveFormatException; +import org.bonitasoft.engine.bpm.process.*; +import org.bonitasoft.engine.business.application.ApplicationImportPolicy; +import org.bonitasoft.engine.business.application.exporter.ApplicationNodeContainerConverter; +import org.bonitasoft.engine.business.application.importer.ApplicationImporter; +import org.bonitasoft.engine.business.application.importer.StrategySelector; +import org.bonitasoft.engine.business.application.xml.AbstractApplicationNode; +import org.bonitasoft.engine.business.data.*; +import org.bonitasoft.engine.commons.exceptions.SBonitaException; +import org.bonitasoft.engine.exception.*; +import org.bonitasoft.engine.identity.ImportPolicy; +import org.bonitasoft.engine.identity.OrganizationImportException; +import org.bonitasoft.engine.io.FileOperations; +import org.bonitasoft.engine.page.Page; +import org.bonitasoft.engine.page.PageCreator; +import org.bonitasoft.engine.page.PageSearchDescriptor; +import org.bonitasoft.engine.page.PageUpdater; +import org.bonitasoft.engine.platform.PlatformService; +import org.bonitasoft.engine.platform.exception.SPlatformUpdateException; +import org.bonitasoft.engine.platform.model.STenant; +import org.bonitasoft.engine.platform.model.builder.SPlatformUpdateBuilder; +import org.bonitasoft.engine.platform.model.builder.impl.SPlatformUpdateBuilderImpl; +import org.bonitasoft.engine.recorder.model.EntityUpdateDescriptor; +import org.bonitasoft.engine.search.SearchOptionsBuilder; +import org.bonitasoft.engine.service.InstallationFailedException; +import org.bonitasoft.engine.service.InstallationService; +import org.bonitasoft.engine.service.ServiceAccessor; +import org.bonitasoft.engine.service.ServiceAccessorSingleton; +import org.bonitasoft.engine.session.SessionService; +import org.bonitasoft.engine.session.model.SSession; +import org.bonitasoft.engine.sessionaccessor.SessionAccessor; +import org.bonitasoft.engine.tenant.TenantStateManager; +import org.bonitasoft.engine.transaction.UserTransactionService; +import org.bonitasoft.platform.exception.PlatformException; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; +import org.springframework.stereotype.Component; +import org.xml.sax.SAXException; + +/** + * Main entry point to deploy an {@link ApplicationArchive}. + * + * @author Baptiste Mesta. + * @author Danila Mazour + * @author Haroun El Alami + */ +@Slf4j +@Component +@ConditionalOnSingleCandidate(ApplicationInstaller.class) +public class ApplicationInstallerImpl implements ApplicationInstaller { + + private static final String PAGE_TOKEN_PROPERTY = "name"; + private static final String PAGE_DISPLAY_NAME_PROPERTY = "displayName"; + private static final String PAGE_DESCRIPTION_PROPERTY = "description"; + private static final String PAGE_CONTENT_TYPE_PROPERTY = "contentType"; + + private final InstallationService installationService; + private final BusinessDataModelRepository bdmRepository; + private final UserTransactionService transactionService; + private final TenantStateManager tenantStateManager; + private final SessionAccessor sessionAccessor; + private final SessionService sessionService; + private final BusinessArchiveArtifactsManager businessArchiveArtifactsManager; + private final ApplicationImporter applicationImporter; + private final Long tenantId; + private final ApplicationNodeContainerConverter appXmlConverter = new ApplicationNodeContainerConverter(); + + public ApplicationInstallerImpl(InstallationService installationService, + @Qualifier("businessDataModelRepository") BusinessDataModelRepository bdmRepository, + UserTransactionService transactionService, @Value("${tenantId}") Long tenantId, + SessionAccessor sessionAccessor, SessionService sessionService, TenantStateManager tenantStateManager, + @Qualifier("dependencyResolver") BusinessArchiveArtifactsManager businessArchiveArtifactsManager, + ApplicationImporter applicationImporter) { + this.installationService = installationService; + this.bdmRepository = bdmRepository; + this.transactionService = transactionService; + this.tenantId = tenantId; + this.sessionAccessor = sessionAccessor; + this.sessionService = sessionService; + this.tenantStateManager = tenantStateManager; + this.businessArchiveArtifactsManager = businessArchiveArtifactsManager; + this.applicationImporter = applicationImporter; + } + + private PageAPIDelegate getPageAPIDelegate() { + return PageAPIDelegate.getInstance(); + } + + private OrganizationAPIDelegate getOrganizationImporter() { + return OrganizationAPIDelegate.getInstance(); + } + + @Override + public void install(ApplicationArchive applicationArchive) throws ApplicationInstallationException { + if (applicationArchive.isEmpty()) { + throw new ApplicationInstallationException("The Application Archive contains no valid artifact to install"); + } + final ExecutionResult executionResult = new ExecutionResult(); + try { + final long startPoint = System.currentTimeMillis(); + log.info("Starting Application Archive installation..."); + installBusinessDataModel(applicationArchive); + inSession(() -> inTransaction(() -> { + var newlyInstalledProcessIds = installArtifacts(applicationArchive, executionResult); + enableResolvedProcesses(newlyInstalledProcessIds, executionResult); + updateApplicationVersion(applicationArchive.getVersion()); + return null; + })); + log.info("The Application Archive (version {}) has been installed successfully in {} ms.", + applicationArchive.getVersion(), (System.currentTimeMillis() - startPoint)); + } catch (Exception e) { + throw new ApplicationInstallationException("The Application Archive install operation has been aborted", e); + } finally { + logInstallationResult(executionResult); + } + if (executionResult.hasErrors()) { + throw new ApplicationInstallationException("The Application Archive install operation has been aborted"); + } + } + + protected List installArtifacts(ApplicationArchive applicationArchive, ExecutionResult executionResult) + throws Exception { + installOrganization(applicationArchive, executionResult); + installOrUpdateRestApiExtensions(applicationArchive, executionResult); + installOrUpdatePages(applicationArchive, executionResult); + installOrUpdateLayouts(applicationArchive, executionResult); + installOrUpdateThemes(applicationArchive, executionResult); + installLivingApplications(applicationArchive, executionResult, FAIL_ON_DUPLICATES); + var installedProcessIds = installProcesses(applicationArchive, executionResult); + applicationArchive.getConfigurationFile().ifPresent(configFile -> installConfiguration(configFile, + executionResult)); + return installedProcessIds; + } + + @Override + public void update(ApplicationArchive applicationArchive) throws ApplicationInstallationException { + if (applicationArchive.isEmpty()) { + throw new ApplicationInstallationException("The Application Archive contains no valid artifact to install"); + } + final ExecutionResult executionResult = new ExecutionResult(); + try { + final long startPoint = System.currentTimeMillis(); + log.info("Starting Application Archive installation..."); + installBusinessDataModel(applicationArchive); + inSession(() -> inTransaction(() -> { + List newlyInstalledProcessIds = updateArtifacts(applicationArchive, executionResult); + disableOldProcesses(newlyInstalledProcessIds, executionResult); + enableResolvedProcesses(newlyInstalledProcessIds, executionResult); + updateApplicationVersion(applicationArchive.getVersion()); + return null; + })); + log.info("The Application Archive has been installed successfully in {} ms.", + (System.currentTimeMillis() - startPoint)); + } catch (Exception e) { + throw new ApplicationInstallationException("The Application Archive update operation has been aborted", e); + } finally { + logInstallationResult(executionResult); + } + if (executionResult.hasErrors()) { + throw new ApplicationInstallationException("The Application Archive update operation has been aborted"); + } + } + + @VisibleForTesting + public void resumeTenantInSession() throws Exception { + inSession(() -> { + try { + if (Objects.equals(STenant.PAUSED, tenantStateManager.getStatus())) { + tenantStateManager.resume(); + transactionService.executeInTransaction(() -> { + businessArchiveArtifactsManager.resolveDependenciesForAllProcesses(getServiceAccessor()); + return null; + }); + } + } catch (Exception e) { + throw new UpdateException(e); + } + return null; + }); + } + + @VisibleForTesting + public void pauseTenantInSession() throws Exception { + inSession(() -> { + try { + String status = tenantStateManager.getStatus(); + if (STenant.ACTIVATED.equals(status)) { + tenantStateManager.pause(); + } else if (!STenant.PAUSED.equals(status)) { + throw new UpdateException( + "The default tenant is in state " + status + " and cannot be paused. Aborting."); + } + } catch (Exception e) { + throw new UpdateException(e); + } + return null; + }); + } + + protected List updateArtifacts(ApplicationArchive applicationArchive, ExecutionResult executionResult) + throws Exception { + updateOrganization(applicationArchive, executionResult); + + installOrUpdateRestApiExtensions(applicationArchive, executionResult); + installOrUpdatePages(applicationArchive, executionResult); + installOrUpdateLayouts(applicationArchive, executionResult); + installOrUpdateThemes(applicationArchive, executionResult); + installLivingApplications(applicationArchive, executionResult, ApplicationImportPolicy.REPLACE_DUPLICATES); + + List newlyInstalledProcessIds = installProcesses(applicationArchive, executionResult); + applicationArchive.getConfigurationFile().ifPresent(configFile -> installConfiguration(configFile, + executionResult)); + return newlyInstalledProcessIds; + } + + @VisibleForTesting + public void updateApplicationVersion(String version) throws PlatformException { + try { + PlatformService platformService = getServiceAccessor().getPlatformService(); + platformService.updatePlatform(getPlatformUpdateBuilder() + .setApplicationVersion(version).done()); + } catch (SPlatformUpdateException e) { + throw new PlatformException("Error when updating Platform application version", e); + } + } + + protected SPlatformUpdateBuilder getPlatformUpdateBuilder() { + return SPlatformUpdateBuilderImpl.builder() + .descriptor(new EntityUpdateDescriptor()) + .build(); + } + + @VisibleForTesting + void disableProcess(long processDefinitionId) throws SBonitaException { + getProcessManagementAPIDelegate().disableProcess(processDefinitionId); + } + + @VisibleForTesting + List getDeployedProcessIds() throws SearchException { + SearchOptionsBuilder optsBuilder = new SearchOptionsBuilder(0, Integer.MAX_VALUE); + return getProcessDeploymentAPIDelegate() + .searchProcessDeploymentInfos(optsBuilder.done()).getResult() + .stream().map(ProcessDeploymentInfo::getProcessId).collect(Collectors.toList()); + } + + @VisibleForTesting + Optional getDeployedProcessId(String name, String version) { + try { + return Optional.of(getProcessDeploymentAPIDelegate().getProcessDefinitionId(name, version)); + } catch (ProcessDefinitionNotFoundException e) { + return Optional.empty(); + } + } + + public void disableOldProcesses(List installedProcessIds, ExecutionResult executionResult) + throws SearchException, SBonitaException, ProcessDefinitionNotFoundException { + List deployedProcessIds = getDeployedProcessIds(); + // remove installed process ids + deployedProcessIds.removeAll(installedProcessIds); + // disable all processes + for (Long processId : deployedProcessIds) { + // get process Info + ProcessDeploymentInfo info = getProcessDeploymentInfo(processId); + if (info.getActivationState() == ActivationState.ENABLED) { + disableProcess(processId); + executionResult.addStatus(infoStatus(PROCESS_DEPLOYMENT_DISABLEMENT_OK, + format("Process %s (%s) has been disabled successfully", + info.getDisplayName(), info.getVersion()))); + } + } + } + + @VisibleForTesting + ProcessDeploymentInfo getProcessDeploymentInfo(Long processId) throws ProcessDefinitionNotFoundException { + return getProcessDeploymentAPIDelegate().getProcessDeploymentInfo(processId); + } + + public void enableResolvedProcesses(List processDefinitionIds, ExecutionResult executionResult) + throws ProcessDeployException { + Collection processDeploymentInfos = getProcessDeploymentAPIDelegate() + .getProcessDeploymentInfosFromIds(processDefinitionIds) + .values(); + + boolean atLeastOneBlockingProblem = false; + // for all deployed process + // if resolved and not already enabled, + // enable it => if exception, add error status + // if enablement ok, add info status Ok + // if not resolved, add error status and list resolution problems + // At the end, if at least one process disabled, throw Exception to cancel deployment and startup + for (ProcessDeploymentInfo info : processDeploymentInfos) { + if (info.getConfigurationState() == RESOLVED) { + if (info.getActivationState() == DISABLED) { + try { + getProcessDeploymentAPIDelegate().enableProcess(info.getProcessId()); + } catch (ProcessDefinitionNotFoundException | ProcessEnablementException e) { + final Map context = new HashMap<>(); + context.put(PROCESS_NAME_KEY, info.getName()); + context.put(PROCESS_VERSION_KEY, info.getVersion()); + executionResult.addStatus(errorStatus(PROCESS_DEPLOYMENT_ENABLEMENT_KO, + format("Process %s (%s) could not be enabled", info.getName(), info.getVersion()), + context)); + atLeastOneBlockingProblem = true; + continue; + } + } + executionResult.addStatus(infoStatus(PROCESS_DEPLOYMENT_ENABLEMENT_OK, + format("Process %s (%s) has been enabled successfully", + info.getDisplayName(), info.getVersion()))); + } else { + try { + atLeastOneBlockingProblem = true; + List problems = getProcessDeploymentAPIDelegate() + .getProcessResolutionProblems(info.getProcessId()); + String message = format( + "Process '%s' (%s) is unresolved. It cannot be enabled for now.", + info.getDisplayName(), info.getVersion()); + String description = message + lineSeparator() + + problems.stream().map(Problem::getDescription) + .collect(joining(lineSeparator())); + executionResult.addStatus(errorStatus(PROCESS_DEPLOYMENT_ENABLEMENT_KO, description)); + } catch (ProcessDefinitionNotFoundException e) { + executionResult + .addStatus(errorStatus(PROCESS_DEPLOYMENT_ENABLEMENT_KO, "Process definition not found")); + } + } + } + + if (atLeastOneBlockingProblem) { + throw new ProcessDeployException("At least one process failed to deploy / enable. Canceling installation."); + } + } + + @VisibleForTesting + List importOrganization(File organization, ImportPolicy failOnDuplicates) + throws OrganizationImportException, IOException { + return getOrganizationImporter().importOrganizationWithWarnings( + Files.readString(organization.toPath()), + failOnDuplicates); + } + + protected void installOrganization(ApplicationArchive applicationArchive, ExecutionResult executionResult) + throws Exception { + final List warnings; + if (applicationArchive.getOrganization() == null) { + executionResult.addStatus(Status.infoStatus(ORGANIZATION_IMPORT_WARNING, + "No organization found. Use the technical user to configure the organization.")); + return; + } + try { + warnings = importOrganization(applicationArchive.getOrganization(), ImportPolicy.FAIL_ON_DUPLICATES); + } catch (IOException e) { + throw new OrganizationImportException(e); + } + for (String warning : warnings) { + executionResult.addStatus(warningStatus(ORGANIZATION_IMPORT_WARNING, warning)); + } + } + + protected void updateOrganization(ApplicationArchive applicationArchive, ExecutionResult executionResult) + throws Exception { + final List warnings; + if (applicationArchive.getOrganization() == null) { + log.info("There is no organization file in the archive. Ignoring the organization update step."); + return; + } + try { + warnings = importOrganization(applicationArchive.getOrganization(), ImportPolicy.IGNORE_DUPLICATES); + } catch (IOException e) { + throw new OrganizationImportException(e); + } + for (String warning : warnings) { + executionResult.addStatus(warningStatus(ORGANIZATION_IMPORT_WARNING, warning)); + } + } + + protected void installBusinessDataModel(ApplicationArchive applicationArchive) throws Exception { + if (applicationArchive.getBdm() != null) { + var alreadyDeployed = sameBdmContentDeployed(applicationArchive.getBdm()); + if (alreadyDeployed) { + log.info("Installed and current BDM are equivalent. No BDM update required."); + return; + } + log.info("BDM must be installed or updated..."); + pauseTenantInSession(); + final String bdmVersion = inSession( + () -> inTransaction(() -> updateBusinessDataModel(applicationArchive))); + log.info("BDM successfully installed (version({})", bdmVersion); + resumeTenantInSession(); + } + } + + boolean sameBdmContentDeployed(File bdmArchive) throws Exception { + return inSession(() -> inTransaction(() -> { + log.info("Comparing BDM to install with current BDM..."); + return bdmRepository + .isDeployed(Files.readAllBytes(bdmArchive.toPath())); + })); + } + + protected String updateBusinessDataModel(ApplicationArchive applicationArchive) + throws InvalidBusinessDataModelException, BusinessDataRepositoryDeploymentException { + String bdmVersion; + try { + uninstallBusinessDataModel(); + bdmVersion = installBusinessDataModel(Files.readAllBytes(applicationArchive.getBdm().toPath())); + } catch (IOException e) { + log.warn("Cannot read the BDM file on disk"); + log.warn( + "Caught an error when installing/updating the BDM, the transaction will be reverted and the previous BDM restored."); + throw new BusinessDataRepositoryDeploymentException(e); + } catch (Exception e) { + log.warn( + "Caught an error when installing/updating the BDM, the transaction will be reverted and the previous BDM restored."); + throw e; + } + log.info("Update operation completed, the BDM was successfully updated"); + return bdmVersion; + } + + protected void uninstallBusinessDataModel() throws BusinessDataRepositoryDeploymentException { + log.info("Uninstalling the currently deployed BDM"); + try { + tenantStateManager.executeTenantManagementOperation("BDM Uninstallation", () -> { + bdmRepository.uninstall(tenantId); + return null; + }); + log.info("BDM successfully uninstalled"); + } catch (final SBusinessDataRepositoryException sbdre) { + throw new BusinessDataRepositoryDeploymentException(sbdre); + } catch (final Exception e) { + throw new BonitaRuntimeException(e); + } + } + + protected String installBusinessDataModel(final byte[] zip) + throws InvalidBusinessDataModelException, BusinessDataRepositoryDeploymentException { + log.info("Starting the installation of the BDM."); + try { + String bdmVersion = tenantStateManager.executeTenantManagementOperation("BDM Installation", + () -> bdmRepository.install(zip, SessionService.SYSTEM_ID)); + log.info("Installation of the BDM completed."); + return bdmVersion; + } catch (final SBusinessDataRepositoryDeploymentException e) { + throw new BusinessDataRepositoryDeploymentException(e); + } catch (final InvalidBusinessDataModelException e) { + throw e; + } catch (final Exception e) { + throw new BonitaRuntimeException(e); + } + } + + protected void installLivingApplications(ApplicationArchive applicationArchive, ExecutionResult executionResult, + ApplicationImportPolicy policy) + throws AlreadyExistsException, ImportException, ApplicationInstallationException { + try { + boolean atLeastOneBlockingProblem = false; + for (File livingApplicationFile : applicationArchive.getApplications()) { + log.info("Installing Living Application from file '{}'", livingApplicationFile.getName()); + var appContainer = appXmlConverter + .unmarshallFromXML(Files.readAllBytes(livingApplicationFile.toPath())); + for (var application : appContainer.getAllApplications()) { + var status = importApplication(application, + getIconContent(application, applicationArchive), policy); + final Map context = new HashMap<>(); + context.put(LIVING_APPLICATION_TOKEN_KEY, status.getName()); + context.put(LIVING_APPLICATION_IMPORT_STATUS_KEY, status.getStatus()); + final List errors = status.getErrors(); + if (errors != null && !errors.isEmpty()) { + errors.forEach(error -> { + Status errorStatus = buildErrorStatus(error, livingApplicationFile.getName()); + executionResult.addStatus(errorStatus); + }); + + atLeastOneBlockingProblem = true; + continue; + } + + executionResult.addStatus( + infoStatus(LIVING_APP_DEPLOYMENT, + format("Application '%s' has been %s", status.getName(), + status.getStatus().name().toLowerCase()), + context)); + } + } + + if (atLeastOneBlockingProblem) { + throw new ApplicationInstallationException( + "At least one application failed to be installed. Canceling installation."); + } + } catch (IOException | JAXBException | SAXException e) { + throw new ImportException(e); + } + } + + private IconContent getIconContent(AbstractApplicationNode application, ApplicationArchive applicationArchive) { + var iconPath = application.getIconPath(); + if (iconPath != null && !iconPath.isBlank()) { + var icon = applicationArchive.getApplicationIcons().stream() + .filter(iconFile -> Objects.equals(iconPath, iconFile.getName())) + .findFirst() + .map(File::toPath) + .orElse(null); + try { + if (icon != null) { + log.info("Application icon {} found for {}", icon.getFileName().toString(), + application.getDisplayName()); + var bytes = Files.readAllBytes(icon); + return IconContent.builder() + .bytes(bytes) + .mimeType(URLConnection.guessContentTypeFromName(icon.getFileName().toString())) + .build(); + } + } catch (IOException e) { + log.warn("Failed to read icon {}", icon, e); + } + } + return IconContent.builder().build(); + } + + private Status buildErrorStatus(ImportError importError, @NonNull String applicationName) { + StatusCode code = null; + switch (importError.getType()) { + case PAGE: + code = LIVING_APP_REFERENCES_UNKNOWN_PAGE; + break; + case PROFILE: + code = LIVING_APP_REFERENCES_UNKNOWN_PROFILE; + break; + case APPLICATION_PAGE: + code = LIVING_APP_REFERENCES_UNKNOWN_APPLICATION_PAGE; + break; + case LAYOUT: + code = LIVING_APP_REFERENCES_UNKNOWN_LAYOUT; + break; + case THEME: + code = LIVING_APP_REFERENCES_UNKNOWN_THEME; + break; + default: + break; + } + final Map context = new HashMap<>(); + context.put(LIVING_APPLICATION_TOKEN_KEY, applicationName); + context.put(LIVING_APPLICATION_INVALID_ELEMENT_NAME, importError.getName()); + context.put(LIVING_APPLICATION_INVALID_ELEMENT_TYPE, importError.getType()); + return errorStatus( + code, + String.format("Unknown %s named '%s'", importError.getType().name(), importError.getName()), + context); + } + + ImportStatus importApplication(final AbstractApplicationNode application, IconContent iconContent, + ApplicationImportPolicy policy) + throws ImportException, AlreadyExistsException { + return applicationImporter.importApplication(application, true, SessionService.SYSTEM_ID, + iconContent.getBytes(), iconContent.getMimeType(), + true, + new StrategySelector().selectStrategy(policy)); + } + + protected void installOrUpdatePages(ApplicationArchive applicationArchive, ExecutionResult executionResult) + throws IOException, BonitaException { + for (File pageFile : applicationArchive.getPages()) { + installUnitPage(pageFile, "page", executionResult); + } + } + + protected void installOrUpdateLayouts(ApplicationArchive applicationArchive, ExecutionResult executionResult) + throws IOException, BonitaException { + for (File layoutFile : applicationArchive.getLayouts()) { + installUnitPage(layoutFile, "layout", executionResult); + } + } + + protected void installOrUpdateThemes(ApplicationArchive applicationArchive, ExecutionResult executionResult) + throws IOException, BonitaException { + for (File pageFile : applicationArchive.getThemes()) { + installUnitPage(pageFile, "theme", executionResult); + } + } + + protected void installOrUpdateRestApiExtensions(ApplicationArchive applicationArchive, + ExecutionResult executionResult) + throws IOException, BonitaException { + for (File pageFile : applicationArchive.getRestAPIExtensions()) { + installUnitPage(pageFile, "REST API extension", executionResult); + } + } + + /** + * From the Engine perspective, all custom pages, layouts, themes, custom Rest APIs are of type Page + */ + protected void installUnitPage(File pageFile, String precisePageType, ExecutionResult executionResult) + throws IOException, BonitaException { + var pageProperties = loadPageProperties(pageFile); + var pageToken = pageProperties.getProperty(PAGE_TOKEN_PROPERTY); + final Map context = new HashMap<>(); + context.put(PAGE_NAME_KEY, pageToken); + Page existingPage = getPageIfExist(pageToken); + if (existingPage == null) { + final Page page = createPage(pageFile, pageProperties); + log.info("Creating new {} '{}'", precisePageType, getPageName(page)); + executionResult.addStatus(infoStatus(PAGE_DEPLOYMENT_CREATE_NEW, + format("New %s '%s' has been installed", precisePageType, getPageName(page)), + context)); + } else { + updatePageContent(pageFile, existingPage.getId()); + } + } + + @VisibleForTesting + void updatePageContent(File pageFile, long pageId) throws UpdateException, IOException, AlreadyExistsException { + getPageAPIDelegate().updatePageContent(pageId, Files.readAllBytes(pageFile.toPath()), SessionService.SYSTEM_ID); + // update content name + final PageUpdater pageUpdater = new PageUpdater(); + pageUpdater.setContentName(pageFile.getName()); + getPageAPIDelegate().updatePage(pageId, pageUpdater, SessionService.SYSTEM_ID); + } + + @VisibleForTesting + Page getPageIfExist(String pageToken) throws SearchException { + List pageResearch = getPageAPIDelegate().searchPages(new SearchOptionsBuilder(0, 1) + .filter(PageSearchDescriptor.NAME, pageToken).done()).getResult(); + if (!pageResearch.isEmpty()) { + return pageResearch.get(0); + } + return null; + } + + Page createPage(File pageFile, Properties pageProperties) throws CreationException { + try { + var pageCreator = new PageCreator(pageProperties.getProperty(PAGE_TOKEN_PROPERTY), pageFile.getName()) + .setContentType(pageProperties.getProperty(PAGE_CONTENT_TYPE_PROPERTY)) + .setDisplayName(pageProperties.getProperty(PAGE_DISPLAY_NAME_PROPERTY)) + .setDescription(pageProperties.getProperty(PAGE_DESCRIPTION_PROPERTY)); + return getPageAPIDelegate().createPage(pageCreator, + Files.readAllBytes(pageFile.toPath()), + SessionService.SYSTEM_ID); + } catch (IOException e) { + throw new CreationException("Failed to read custom page content", e); + } + } + + private String getPageName(Page page) { + return isNotBlank(page.getDisplayName()) ? page.getDisplayName() : page.getName(); + } + + private Properties loadPageProperties(File zipFile) throws IOException { + var properties = new Properties(); + try (var pagePropertiesIs = new ByteArrayInputStream( + FileOperations.getFileFromZip(zipFile, "page.properties"))) { + properties.load(pagePropertiesIs); + return validatePageProperties(zipFile, properties); + } + } + + private Properties validatePageProperties(File file, Properties properties) { + String name = properties.getProperty(PAGE_TOKEN_PROPERTY); + if (name == null || name.isEmpty()) { + throw new IllegalArgumentException( + format("Invalid page %s, page.properties file do not contain mandatory '%s' attribute", + file.getName(), PAGE_TOKEN_PROPERTY)); + } + String type = properties.getProperty(PAGE_CONTENT_TYPE_PROPERTY); + if (type == null || type.isEmpty()) { + throw new IllegalArgumentException( + format("Invalid page %s, page.properties file do not contain mandatory '%s' attribute", + file.getName(), PAGE_CONTENT_TYPE_PROPERTY)); + } + return properties; + } + + protected List installProcesses(ApplicationArchive applicationArchive, ExecutionResult executionResult) + throws InvalidBusinessArchiveFormatException, IOException, ProcessDeployException { + List processDefinitionIds = new ArrayList<>(); + for (File processFile : applicationArchive.getProcesses()) { + try (var is = new FileInputStream(processFile)) { + final BusinessArchive businessArchive = BusinessArchiveFactory + .readBusinessArchive(is); + String name = businessArchive.getProcessDefinition().getName(); + String version = businessArchive.getProcessDefinition().getVersion(); + + final Map context = new HashMap<>(); + context.put(PROCESS_NAME_KEY, name); + context.put(PROCESS_VERSION_KEY, version); + + Optional deployedProcessId = getDeployedProcessId(name, version); + if (deployedProcessId.isPresent()) { + // skip install + processDefinitionIds.add(deployedProcessId.get()); + executionResult.addStatus(infoStatus(PROCESS_DEPLOYMENT_SKIP_INSTALL, + format("Process %s (%s) already exists in the database. Skipping installation.", name, + version), + context)); + } else { + processDefinitionIds.add(deployProcess(businessArchive, executionResult)); + } + } + } + return processDefinitionIds; + } + + /** + * Must be called in a transaction with active session + * + * @param configurationFileArchive + * @param executionResult + * @throws ApplicationInstallationException + */ + void installConfiguration(File configurationFileArchive, + ExecutionResult executionResult) + throws ApplicationInstallationException { + try (var is = Files.newInputStream(configurationFileArchive.toPath())) { + log.info("Installing application configuration from file"); + installationService.install(null, is.readAllBytes()); + executionResult.addStatus(Status.infoStatus(Status.okStatus().getCode(), + "Configuration file has been imported")); + } catch (IOException | InstallationFailedException e) { + throw new ApplicationInstallationException("The Application Archive install operation has been aborted", e); + } + } + + /** + * Update configuration with the given bconf file + * + * @param configurationFileArchive A bconf file + * @param executionResult + * @throws Exception + */ + @Override + public void updateConfiguration(File configurationFileArchive, ExecutionResult executionResult) throws Exception { + inSession(() -> inTransaction(() -> { + installConfiguration(configurationFileArchive, executionResult); + return null; + })); + } + + protected Long deployProcess(BusinessArchive businessArchive, ExecutionResult executionResult) + throws ProcessDeployException { + final String processName = businessArchive.getProcessDefinition().getName(); + final String processVersion = businessArchive.getProcessDefinition().getVersion(); + long processDefinitionId; + + final Map context = new HashMap<>(); + context.put(PROCESS_NAME_KEY, processName); + context.put(PROCESS_VERSION_KEY, processVersion); + try { + // Let's try to deploy the process, even if it already exists: + processDefinitionId = getProcessDeploymentAPIDelegate().deploy(businessArchive).getId(); + executionResult.addStatus(infoStatus(PROCESS_DEPLOYMENT_CREATE_NEW, + format("New process %s (%s) has been installed successfully", processName, processVersion), + context)); + + } catch (AlreadyExistsException e) { + final String message = format("Process %s - %s already exists. Abandoning.", processName, processVersion); + log.error(message); + throw new ProcessDeployException(message); + } + return processDefinitionId; + } + + @VisibleForTesting + ProcessDeploymentAPIDelegate getProcessDeploymentAPIDelegate() { + return ProcessDeploymentAPIDelegate.getInstance(); + } + + @VisibleForTesting + ProcessManagementAPIImplDelegate getProcessManagementAPIDelegate() { + return ProcessManagementAPIImplDelegate.getInstance(); + } + + @VisibleForTesting + public T inSession(Callable callable) throws Exception { + final SSession session = sessionService.createSession(tenantId, SessionService.SYSTEM); + final long sessionId = session.getId(); + log.trace("New session created with id {}", sessionId); + try { + sessionAccessor.setSessionInfo(sessionId, tenantId); + return callable.call(); + } finally { + sessionAccessor.deleteSessionId(); + sessionAccessor.deleteTenantId(); + } + } + + protected T inTransaction(Callable callable) throws ApplicationInstallationException { + try { + return transactionService.executeInTransaction(callable); + } catch (Exception e) { + throw new ApplicationInstallationException("Problem installing application", e); + } + } + + private ServiceAccessor getServiceAccessor() { + return ServiceAccessorSingleton.getInstance(); + } + + void logInstallationResult(ExecutionResult result) { + log.info("Result of the installation of the application:"); + for (Status s : result.getAllStatus()) { + var message = s.getContext() != null && !s.getContext().isEmpty() + ? String.format("%s - %s - %s", s.getCode(), s.getMessage(), + s.getContext().toString()) + : String.format("%s - %s", s.getCode(), s.getMessage()); + switch (s.getLevel()) { + case ERROR: + log.error(message); + break; + case WARNING: + log.warn(message); + break; + case INFO: + case OK: + default: + log.info(message); + break; + } + } + } + + @Builder + @Data + static class IconContent { + + private byte[] bytes; + private String mimeType; + } + +} diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/application/installer/CustomOrDefaultApplicationInstaller.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/application/installer/CustomOrDefaultApplicationInstaller.java index 828e6805ab1..7ac92143ea2 100644 --- a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/application/installer/CustomOrDefaultApplicationInstaller.java +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/application/installer/CustomOrDefaultApplicationInstaller.java @@ -54,7 +54,7 @@ public class CustomOrDefaultApplicationInstaller { @Getter protected String applicationInstallFolder; - protected final ApplicationInstaller applicationInstaller; + protected final ApplicationInstallerImpl applicationInstaller; private final DefaultLivingApplicationImporter defaultLivingApplicationImporter; private final MandatoryLivingApplicationImporter mandatoryLivingApplicationImporter; diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/application/installer/detector/LivingApplicationDetector.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/application/installer/detector/LivingApplicationDetector.java index 5ea8f151e12..8d7b92a7159 100644 --- a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/application/installer/detector/LivingApplicationDetector.java +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/application/installer/detector/LivingApplicationDetector.java @@ -18,7 +18,7 @@ @Component public class LivingApplicationDetector extends XmlDetector implements ArtifactDetector { - private static final String APPLICATION_NAMESPACE = "http://documentation.bonitasoft.com/application-xml-schema/1.0"; + private static final String APPLICATION_NAMESPACE = "http://documentation.bonitasoft.com/application-xml-schema/1.1"; public LivingApplicationDetector() { super(APPLICATION_NAMESPACE); diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/converter/ApplicationModelConverter.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/converter/ApplicationModelConverter.java index 2e412990166..eeb78a034dc 100644 --- a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/converter/ApplicationModelConverter.java +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/converter/ApplicationModelConverter.java @@ -22,7 +22,7 @@ import lombok.extern.slf4j.Slf4j; import org.bonitasoft.engine.business.application.*; -import org.bonitasoft.engine.business.application.impl.ApplicationImpl; +import org.bonitasoft.engine.business.application.impl.*; import org.bonitasoft.engine.business.application.model.AbstractSApplication; import org.bonitasoft.engine.business.application.model.SApplication; import org.bonitasoft.engine.business.application.model.SApplicationState; @@ -47,14 +47,16 @@ public ApplicationModelConverter(PageService pageService) { this.pageService = pageService; } - public SApplicationWithIcon buildSApplication(final ApplicationCreator creator, final long creatorUserId) + public SApplicationWithIcon buildSApplication(final AbstractApplicationCreator creator, final long creatorUserId) throws CreationException { final Map fields = creator.getFields(); final String description = (String) fields.get(ApplicationField.DESCRIPTION); final String iconPath = (String) fields.get(ApplicationField.ICON_PATH); final Long profileId = (Long) fields.get(ApplicationField.PROFILE_ID); final long now = System.currentTimeMillis(); + final boolean isLink = creator.isLink(); SApplicationWithIcon application = new SApplicationWithIcon(); + application.setLink(isLink); application.setToken((String) fields.get(ApplicationField.TOKEN)); application.setDisplayName((String) fields.get(ApplicationField.DISPLAY_NAME)); application.setVersion((String) fields.get(ApplicationField.VERSION)); @@ -62,8 +64,10 @@ public SApplicationWithIcon buildSApplication(final ApplicationCreator creator, application.setLastUpdateDate(now); application.setCreatedBy(creatorUserId); application.setState(SApplicationState.ACTIVATED.name()); - application.setLayoutId(getLayoutId(creator)); - application.setThemeId(getThemeId(creator)); + if (creator instanceof ApplicationCreator) { + application.setLayoutId(getLayoutId((ApplicationCreator) creator)); + application.setThemeId(getThemeId((ApplicationCreator) creator)); + } application.setUpdatedBy(creatorUserId); byte[] iconContent = (byte[]) fields.get(ApplicationField.ICON_CONTENT); String iconFileName = (String) fields.get(ApplicationField.ICON_FILE_NAME); @@ -114,11 +118,22 @@ private Long getPageId(final String applicationToken, final String pageName) thr } } - public Application toApplication(final AbstractSApplication abstractSApplication) { - final ApplicationImpl application = new ApplicationImpl(abstractSApplication.getToken(), - abstractSApplication.getVersion(), - abstractSApplication.getDescription(), - abstractSApplication.getLayoutId(), abstractSApplication.getThemeId()); + public IApplication toApplication(final AbstractSApplication abstractSApplication) { + final AbstractApplicationImpl application; + if (abstractSApplication.isLink()) { + final ApplicationLinkImpl applicationLink = new ApplicationLinkImpl( + abstractSApplication.getToken(), + abstractSApplication.getVersion(), + abstractSApplication.getDescription()); + application = applicationLink; + } else { + ApplicationImpl legacyApplication = new ApplicationImpl(abstractSApplication.getToken(), + abstractSApplication.getVersion(), + abstractSApplication.getDescription(), + abstractSApplication.getLayoutId(), abstractSApplication.getThemeId()); + legacyApplication.setHomePageId(abstractSApplication.getHomePageId()); + application = legacyApplication; + } application.setId(abstractSApplication.getId()); application.setDisplayName(abstractSApplication.getDisplayName()); application.setCreatedBy(abstractSApplication.getCreatedBy()); @@ -127,7 +142,6 @@ public Application toApplication(final AbstractSApplication abstractSApplication application.setLastUpdateDate(new Date(abstractSApplication.getLastUpdateDate())); application.setState(abstractSApplication.getState()); application.setIconPath(abstractSApplication.getIconPath()); - application.setHomePageId(abstractSApplication.getHomePageId()); application.setProfileId(abstractSApplication.getProfileId()); application.setHasIcon(abstractSApplication.hasIcon()); application.setEditable(abstractSApplication.isEditable()); @@ -136,15 +150,15 @@ public Application toApplication(final AbstractSApplication abstractSApplication return application; } - public List toApplication(final List sApplications) { - final List applications = new ArrayList<>(sApplications.size()); + public List toApplication(final List sApplications) { + final List applications = new ArrayList<>(sApplications.size()); for (final SApplication sApplication : sApplications) { applications.add(toApplication(sApplication)); } return applications; } - public EntityUpdateDescriptor toApplicationUpdateDescriptor(final ApplicationUpdater updater, + public EntityUpdateDescriptor toApplicationUpdateDescriptor(final AbstractApplicationUpdater updater, final long updaterUserId) { final SApplicationUpdateBuilder builder = new SApplicationUpdateBuilder(updaterUserId); updateFields(updater, builder); @@ -152,7 +166,7 @@ public EntityUpdateDescriptor toApplicationUpdateDescriptor(final ApplicationUpd return builder.done(); } - protected void updateFields(final ApplicationUpdater updater, final SApplicationUpdateBuilder builder) { + protected void updateFields(final AbstractApplicationUpdater updater, final SApplicationUpdateBuilder builder) { for (final Entry entry : updater.getFields().entrySet()) { switch (entry.getKey()) { case TOKEN: diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/livingapplication/LivingApplicationAPIDelegate.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/livingapplication/LivingApplicationAPIDelegate.java index 1d34c0d96e4..a983c78a82c 100755 --- a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/livingapplication/LivingApplicationAPIDelegate.java +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/livingapplication/LivingApplicationAPIDelegate.java @@ -13,6 +13,9 @@ **/ package org.bonitasoft.engine.api.impl.livingapplication; +import java.util.Optional; +import java.util.function.Predicate; + import org.bonitasoft.engine.api.impl.converter.ApplicationModelConverter; import org.bonitasoft.engine.business.application.*; import org.bonitasoft.engine.business.application.impl.IconImpl; @@ -58,7 +61,13 @@ public Application createApplication(final ApplicationCreator applicationCreator validateCreator(applicationCreator); final SApplicationWithIcon sApplicationWithIcon = applicationService .createApplication(converter.buildSApplication(applicationCreator, loggedUserId)); - return converter.toApplication(sApplicationWithIcon); + var converted = converter.toApplication(sApplicationWithIcon); + if (converted instanceof Application res) { + return res; + } else { + // should not occur anyway + throw new CreationException("Use dedicated API for application links."); + } } catch (final SObjectAlreadyExistsException e) { throw new AlreadyExistsException(e.getMessage()); } catch (final SBonitaException e) { @@ -66,7 +75,32 @@ public Application createApplication(final ApplicationCreator applicationCreator } } - private void validateCreator(final ApplicationCreator applicationCreator) throws CreationException { + /** + * @deprecated as of 9.0.0, Applications should be created at startup. This also concerns application links + * introduced in 10.2.0. + */ + @Deprecated(since = "10.2.0") + public ApplicationLink createApplicationLink(final ApplicationLinkCreator applicationLinkCreator) + throws CreationException { + try { + validateCreator(applicationLinkCreator); + final SApplicationWithIcon sApplicationWithIcon = applicationService + .createApplication(converter.buildSApplication(applicationLinkCreator, loggedUserId)); + var converted = converter.toApplication(sApplicationWithIcon); + if (converted instanceof ApplicationLink res) { + return res; + } else { + // should not occur anyway + throw new CreationException("Use dedicated API for legacy applications."); + } + } catch (final SObjectAlreadyExistsException e) { + throw new AlreadyExistsException(e.getMessage()); + } catch (final SBonitaException e) { + throw new CreationException(e); + } + } + + private void validateCreator(final AbstractApplicationCreator applicationCreator) throws CreationException { ValidationStatus validationStatus = tokenValidator.validate(applicationCreator.getToken()); if (!validationStatus.isValid()) { throw new CreationException(validationStatus.getMessage()); @@ -75,9 +109,14 @@ private void validateCreator(final ApplicationCreator applicationCreator) throws if (displayName == null || displayName.trim().isEmpty()) { throw new CreationException("The application display name can not be null or empty"); } + Class appClass = applicationCreator.isLink() ? ApplicationLink.class + : Application.class; + if (!applicationCreator.getFields().keySet().stream().allMatch(k -> k.isForClass(appClass))) { + throw new CreationException("The application fields used must be valid for the application type"); + } } - public Application getApplication(final long applicationId) throws ApplicationNotFoundException { + public IApplication getIApplication(final long applicationId) throws ApplicationNotFoundException { try { return converter.toApplication(applicationService.getApplication(applicationId)); } catch (final SBonitaReadException e) { @@ -87,7 +126,7 @@ public Application getApplication(final long applicationId) throws ApplicationNo } } - public Application getApplicationByToken(final String applicationToken) throws ApplicationNotFoundException { + public IApplication getIApplicationByToken(final String applicationToken) throws ApplicationNotFoundException { try { SApplication applicationByToken = applicationService.getApplicationByToken(applicationToken); if (applicationByToken == null) { @@ -123,8 +162,8 @@ public void deleteApplication(final long applicationId) throws DeletionException } } - public SearchResult searchApplications( - final AbstractSearchEntity searchApplications) + public SearchResult searchIApplications( + final AbstractSearchEntity searchApplications) throws SearchException { try { searchApplications.execute(); @@ -145,12 +184,26 @@ public Application updateApplication(final long applicationId, final Application validateUpdater(updater); AbstractSApplication application; if (!updater.getFields().isEmpty()) { + /* + * This API may be called within our without a transaction. + * So we must check first whether the application is a link to have a consistent behavior + * and never update the application link. + */ + if (Optional.ofNullable(applicationService.getApplicationWithIcon(applicationId)) + .filter(AbstractSApplication::isLink).isPresent()) { + throw new UpdateException("Use dedicated API for application links."); + } application = applicationService.updateApplication(applicationId, converter.toApplicationUpdateDescriptor(updater, loggedUserId)); } else { application = applicationService.getApplication(applicationId); } - return converter.toApplication(application); + var converted = converter.toApplication(application); + if (converted instanceof Application res) { + return res; + } else { + throw new UpdateException("Use dedicated API for application links."); + } } catch (final SObjectAlreadyExistsException e) { throw new AlreadyExistsException(e.getMessage()); } catch (final SObjectNotFoundException e) { @@ -160,12 +213,59 @@ public Application updateApplication(final long applicationId, final Application } } - private void validateUpdater(final ApplicationUpdater updater) throws UpdateException { + /** + * @deprecated as of 9.0.0, Applications should be updated at startup. This also concerns application links + * introduced in 10.2.0. + */ + @Deprecated(since = "10.2.0") + public ApplicationLink updateApplicationLink(final long applicationId, final ApplicationLinkUpdater updater) + throws UpdateException, + AlreadyExistsException, ApplicationNotFoundException { + try { + validateUpdater(updater); + AbstractSApplication application; + if (!updater.getFields().isEmpty()) { + /* + * This API may be called within our without a transaction. + * So we must check first whether the application is a link to have a consistent behavior + * and never update the legacy application. + */ + Predicate isLink = AbstractSApplication::isLink; + if (Optional.ofNullable(applicationService.getApplicationWithIcon(applicationId)) + .filter(isLink.negate()).isPresent()) { + throw new UpdateException("Use dedicated API for legacy applications."); + } + application = applicationService.updateApplication(applicationId, + converter.toApplicationUpdateDescriptor(updater, loggedUserId)); + } else { + application = applicationService.getApplication(applicationId); + } + var converted = converter.toApplication(application); + if (converted instanceof ApplicationLink res) { + return res; + } else { + throw new UpdateException("Use dedicated API for legacy applications."); + } + } catch (final SObjectAlreadyExistsException e) { + throw new AlreadyExistsException(e.getMessage()); + } catch (final SObjectNotFoundException e) { + throw new ApplicationNotFoundException(applicationId); + } catch (final SBonitaException e) { + throw new UpdateException(e); + } + } + + private void validateUpdater(final AbstractApplicationUpdater updater) throws UpdateException { validateToken(updater); validateDisplayName(updater); + Class appClass = updater instanceof ApplicationLinkUpdater ? ApplicationLink.class + : Application.class; + if (!updater.getFields().keySet().stream().allMatch(k -> k.isForClass(appClass))) { + throw new UpdateException("The application fields used must be valid for the application type"); + } } - private void validateDisplayName(final ApplicationUpdater updater) throws UpdateException { + private void validateDisplayName(final AbstractApplicationUpdater updater) throws UpdateException { if (updater.getFields().keySet().contains(ApplicationField.DISPLAY_NAME)) { final String displayName = (String) updater.getFields().get(ApplicationField.DISPLAY_NAME); if (displayName == null || displayName.trim().isEmpty()) { @@ -174,7 +274,7 @@ private void validateDisplayName(final ApplicationUpdater updater) throws Update } } - private void validateToken(final ApplicationUpdater updater) throws UpdateException { + private void validateToken(final AbstractApplicationUpdater updater) throws UpdateException { if (updater.getFields().keySet().contains(ApplicationField.TOKEN)) { final String token = (String) updater.getFields().get(ApplicationField.TOKEN); ValidationStatus validationStatus = tokenValidator.validate(token); diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/platform/PlatformInformationAPIImpl.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/platform/PlatformInformationAPIImpl.java new file mode 100644 index 00000000000..e485f9a5b78 --- /dev/null +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/platform/PlatformInformationAPIImpl.java @@ -0,0 +1,59 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.engine.api.impl.platform; + +import static java.lang.String.valueOf; +import static org.bonitasoft.engine.execution.ProcessStarterVerifierImpl.LIMIT; + +import java.util.Map; + +import org.bonitasoft.engine.api.impl.AvailableInMaintenanceMode; +import org.bonitasoft.engine.api.platform.PlatformInformationAPI; +import org.bonitasoft.engine.execution.ProcessStarterVerifier; +import org.bonitasoft.engine.service.ServiceAccessorSingleton; + +/** + * Provides runtime information about the platform. + * Information returned is dependent on the edition (Community or Subscription) + * and the platform configuration / license. + * + * @author Emmanuel Duchastenier + */ +@AvailableInMaintenanceMode +public class PlatformInformationAPIImpl implements PlatformInformationAPI { + + private ProcessStarterVerifier processStarterVerifier; + + public PlatformInformationAPIImpl() { + // Keep this empty constructor for compatibility with the APIAccessResolverImpl + } + + PlatformInformationAPIImpl(ProcessStarterVerifier processStarterVerifier) { + this.processStarterVerifier = processStarterVerifier; + } + + @Override + public Map getPlatformInformation() { + if (processStarterVerifier == null) { + this.processStarterVerifier = ServiceAccessorSingleton.getInstance().getProcessStarterVerifier(); + } + + return Map.of( + "edition", "Community", + "caseCounter", valueOf(processStarterVerifier.getCurrentNumberOfStartedProcessInstances()), + "caseCounterLimit", valueOf(LIMIT), + "enablePromotionMessages", "true"); + } + +} diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/transaction/application/SearchApplications.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/transaction/application/SearchApplications.java index e3a716c55c3..5c9e37dd6b5 100755 --- a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/transaction/application/SearchApplications.java +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/transaction/application/SearchApplications.java @@ -16,8 +16,8 @@ import java.util.List; import org.bonitasoft.engine.api.impl.converter.ApplicationModelConverter; -import org.bonitasoft.engine.business.application.Application; import org.bonitasoft.engine.business.application.ApplicationService; +import org.bonitasoft.engine.business.application.IApplication; import org.bonitasoft.engine.business.application.model.SApplication; import org.bonitasoft.engine.persistence.QueryOptions; import org.bonitasoft.engine.persistence.SBonitaReadException; @@ -28,15 +28,25 @@ /** * @author Elias Ricken de Medeiros */ -public class SearchApplications extends AbstractSearchEntity { +public class SearchApplications extends AbstractSearchEntity { + private final Class applicationClass; private final ApplicationService applicationService; private final ApplicationModelConverter convertor; - public SearchApplications(final ApplicationService applicationService, + public static SearchApplications defaultSearchApplications( + final ApplicationService applicationService, + final SearchEntityDescriptor searchDescriptor, final SearchOptions options, + final ApplicationModelConverter convertor) { + return new SearchApplications(IApplication.class, applicationService, searchDescriptor, options, + convertor); + } + + public SearchApplications(final Class applicationClass, final ApplicationService applicationService, final SearchEntityDescriptor searchDescriptor, final SearchOptions options, final ApplicationModelConverter convertor) { super(searchDescriptor, options); + this.applicationClass = applicationClass; this.applicationService = applicationService; this.convertor = convertor; } @@ -52,8 +62,13 @@ public List executeSearch(final QueryOptions queryOptions) throws } @Override - public List convertToClientObjects(final List serverObjects) { - return convertor.toApplication(serverObjects); + public List convertToClientObjects(final List serverObjects) { + if (IApplication.class.equals(applicationClass)) { + return (List) convertor.toApplication(serverObjects); + } else { + return convertor.toApplication(serverObjects).stream().filter(applicationClass::isInstance) + .map(applicationClass::cast).toList(); + } } } diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/transaction/application/SearchApplicationsOfUser.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/transaction/application/SearchApplicationsOfUser.java index 4d7ae128db6..7084c7339ca 100644 --- a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/transaction/application/SearchApplicationsOfUser.java +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/api/impl/transaction/application/SearchApplicationsOfUser.java @@ -16,8 +16,8 @@ import java.util.List; import org.bonitasoft.engine.api.impl.converter.ApplicationModelConverter; -import org.bonitasoft.engine.business.application.Application; import org.bonitasoft.engine.business.application.ApplicationService; +import org.bonitasoft.engine.business.application.IApplication; import org.bonitasoft.engine.business.application.model.SApplication; import org.bonitasoft.engine.persistence.QueryOptions; import org.bonitasoft.engine.persistence.SBonitaReadException; @@ -25,16 +25,29 @@ import org.bonitasoft.engine.search.SearchOptions; import org.bonitasoft.engine.search.descriptor.SearchEntityDescriptor; -public class SearchApplicationsOfUser extends AbstractSearchEntity { +public class SearchApplicationsOfUser extends AbstractSearchEntity { + private final Class applicationClass; private long userId; private final ApplicationService applicationService; private final ApplicationModelConverter convertor; - public SearchApplicationsOfUser(final long userId, final ApplicationService applicationService, + public static SearchApplicationsOfUser defaultSearchApplicationsOfUser( + final long userId, + final ApplicationService applicationService, + final SearchEntityDescriptor searchDescriptor, + final SearchOptions options, + final ApplicationModelConverter convertor) { + return new SearchApplicationsOfUser(IApplication.class, userId, applicationService, + searchDescriptor, options, convertor); + } + + public SearchApplicationsOfUser(final Class applicationClass, final long userId, + final ApplicationService applicationService, final SearchEntityDescriptor searchDescriptor, final SearchOptions options, final ApplicationModelConverter convertor) { super(searchDescriptor, options); + this.applicationClass = applicationClass; this.userId = userId; this.applicationService = applicationService; this.convertor = convertor; @@ -51,8 +64,13 @@ public List executeSearch(final QueryOptions queryOptions) throws } @Override - public List convertToClientObjects(final List serverObjects) { - return convertor.toApplication(serverObjects); + public List convertToClientObjects(final List serverObjects) { + if (IApplication.class.equals(applicationClass)) { + return (List) convertor.toApplication(serverObjects); + } else { + return convertor.toApplication(serverObjects).stream().filter(applicationClass::isInstance) + .map(applicationClass::cast).toList(); + } } } diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/business/application/converter/ApplicationToNodeConverter.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/business/application/converter/ApplicationToNodeConverter.java index c06d1ed311a..4a16d8e07e0 100644 --- a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/business/application/converter/ApplicationToNodeConverter.java +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/business/application/converter/ApplicationToNodeConverter.java @@ -19,6 +19,8 @@ import org.bonitasoft.engine.business.application.ApplicationService; import org.bonitasoft.engine.business.application.model.SApplication; import org.bonitasoft.engine.business.application.model.SApplicationPage; +import org.bonitasoft.engine.business.application.xml.AbstractApplicationNode; +import org.bonitasoft.engine.business.application.xml.ApplicationLinkNode; import org.bonitasoft.engine.business.application.xml.ApplicationNode; import org.bonitasoft.engine.commons.exceptions.SBonitaException; import org.bonitasoft.engine.commons.exceptions.SObjectNotFoundException; @@ -56,21 +58,28 @@ public ApplicationToNodeConverter(final ProfileService profileService, final App this.pageService = pageService; } - public ApplicationNode toNode(final SApplication application) throws ExportException { + public AbstractApplicationNode toNode(final SApplication application) throws ExportException { try { - final ApplicationNode applicationNode = new ApplicationNode(); + final AbstractApplicationNode applicationNode; + if (application.isLink()) { + applicationNode = new ApplicationLinkNode(); + } else { + ApplicationNode legacyApplicationNode = new ApplicationNode(); + setLayout(application, legacyApplicationNode); + setTheme(application, legacyApplicationNode); + setHomePage(application, legacyApplicationNode); + setPages(application.getId(), legacyApplicationNode); + applicationMenuToNodeConverter.addMenusToApplicationNode(application.getId(), null, + legacyApplicationNode, null); + applicationNode = legacyApplicationNode; + } applicationNode.setToken(application.getToken()); applicationNode.setDisplayName(application.getDisplayName()); applicationNode.setVersion(application.getVersion()); applicationNode.setDescription(application.getDescription()); applicationNode.setState(application.getState()); applicationNode.setIconPath(application.getIconPath()); - setLayout(application, applicationNode); - setTheme(application, applicationNode); setProfile(application, applicationNode); - setHomePage(application, applicationNode); - setPages(application.getId(), applicationNode); - applicationMenuToNodeConverter.addMenusToApplicationNode(application.getId(), null, applicationNode, null); return applicationNode; } catch (SBonitaException e) { throw new ExportException(e); @@ -125,7 +134,7 @@ private void setHomePage(final SApplication application, final ApplicationNode a } } - private void setProfile(final SApplication application, final ApplicationNode applicationNode) + private void setProfile(final SApplication application, final AbstractApplicationNode applicationNode) throws SProfileNotFoundException { if (application.getProfileId() != null) { final SProfile profile = profileService.getProfile(application.getProfileId()); diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/business/application/converter/NodeToApplicationConverter.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/business/application/converter/NodeToApplicationConverter.java index e0cb165ba2a..1810f797b67 100644 --- a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/business/application/converter/NodeToApplicationConverter.java +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/business/application/converter/NodeToApplicationConverter.java @@ -20,6 +20,8 @@ import org.bonitasoft.engine.business.application.importer.ImportResult; import org.bonitasoft.engine.business.application.importer.validator.ApplicationImportValidator; import org.bonitasoft.engine.business.application.model.SApplicationWithIcon; +import org.bonitasoft.engine.business.application.xml.AbstractApplicationNode; +import org.bonitasoft.engine.business.application.xml.ApplicationLinkNode; import org.bonitasoft.engine.business.application.xml.ApplicationNode; import org.bonitasoft.engine.exception.ImportException; import org.bonitasoft.engine.page.PageService; @@ -47,21 +49,13 @@ public NodeToApplicationConverter(final ProfileService profileService, final Pag this.validator = validator; } - public ImportResult toSApplication(final ApplicationNode applicationNode, final long createdBy) - throws SBonitaReadException, ImportException { - return toSApplication(applicationNode, null, "", createdBy); - } - - public ImportResult toSApplication(final ApplicationNode applicationNode, byte[] iconContent, String iconMimeType, - final long createdBy) + public ImportResult toSApplication(final AbstractApplicationNode applicationNode, byte[] iconContent, + String iconMimeType, final long createdBy, final boolean editable) throws SBonitaReadException, ImportException { String token = applicationNode.getToken(); - InternalProfiles internalProfileByApplicationNodeProfile = InternalProfiles - .getInternalProfileByProfileName(applicationNode.getProfile()); validator.validate(token); + final ImportStatus importStatus = new ImportStatus(token); - Long layoutId = getLayoutId(getLayoutName(applicationNode), token, importStatus); - Long themeId = getThemeId(getThemeName(applicationNode), token, importStatus); final long currentDate = System.currentTimeMillis(); SApplicationWithIcon application = new SApplicationWithIcon(); application.setToken(token); @@ -70,22 +64,22 @@ public ImportResult toSApplication(final ApplicationNode applicationNode, byte[] application.setCreationDate(currentDate); application.setLastUpdateDate(currentDate); application.setCreatedBy(createdBy); - application.setLayoutId(layoutId); - application.setThemeId(themeId); + application.setUpdatedBy(createdBy); application.setIconPath(applicationNode.getIconPath()); - application.setIconContent(iconContent); - application.setIconMimeType(iconMimeType); application.setDescription(applicationNode.getDescription()); application.setState(applicationNode.getState()); + application.setEditable(editable); + application.setLink(applicationNode instanceof ApplicationLinkNode); - if (internalProfileByApplicationNodeProfile == null) { - final ImportError importError = setProfile(applicationNode, application); - if (importError != null) { - importStatus.addError(importError); - } - } else { - application.setInternalProfile(internalProfileByApplicationNodeProfile.getProfileName()); - application.setProfileId(null); + if (applicationNode instanceof ApplicationNode legacy) { + application.setLayoutId(getLayoutId(getLayoutName(legacy), token, importStatus)); + application.setThemeId(getThemeId(getThemeName(legacy), token, importStatus)); + } + application.setIconContent(iconContent); + application.setIconMimeType(iconMimeType); + + if (applicationNode.getProfile() != null) { + setProfile(applicationNode.getProfile(), application, importStatus); } return new ImportResult(application, importStatus); @@ -123,27 +117,29 @@ protected Long handleMissingTheme(final String themeName, final String applicati applicationToken, themeName)); } - protected String getLayoutName(final ApplicationNode applicationNode) { + private String getLayoutName(final ApplicationNode applicationNode) { return applicationNode.getLayout() != null ? applicationNode.getLayout() : ApplicationService.DEFAULT_LAYOUT_NAME; } - protected String getThemeName(final ApplicationNode applicationNode) { + private String getThemeName(final ApplicationNode applicationNode) { return applicationNode.getTheme() != null ? applicationNode.getTheme() : ApplicationService.DEFAULT_THEME_NAME; } - private ImportError setProfile(final ApplicationNode applicationNode, - SApplicationWithIcon application) { - ImportError importError = null; - if (applicationNode.getProfile() != null) { + private void setProfile(String profileName, SApplicationWithIcon application, ImportStatus importStatus) { + InternalProfiles internalProfileByApplicationNodeProfile = InternalProfiles + .getInternalProfileByProfileName(profileName); + if (internalProfileByApplicationNodeProfile == null) { try { - final SProfile profile = profileService.getProfileByName(applicationNode.getProfile()); + final SProfile profile = profileService.getProfileByName(profileName); application.setProfileId(profile.getId()); } catch (final SProfileNotFoundException | SBonitaReadException e) { - importError = new ImportError(applicationNode.getProfile(), ImportError.Type.PROFILE); + importStatus.addError(new ImportError(profileName, ImportError.Type.PROFILE)); } + } else { + application.setInternalProfile(internalProfileByApplicationNodeProfile.getProfileName()); + application.setProfileId(null); } - return importError; } protected PageService getPageService() { diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/business/application/importer/ApplicationImporter.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/business/application/importer/ApplicationImporter.java index 16a35c81fe6..e0264d25f45 100755 --- a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/business/application/importer/ApplicationImporter.java +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/business/application/importer/ApplicationImporter.java @@ -26,12 +26,15 @@ import org.bonitasoft.engine.business.application.model.SApplicationPage; import org.bonitasoft.engine.business.application.model.SApplicationWithIcon; import org.bonitasoft.engine.business.application.model.builder.SApplicationUpdateBuilder; +import org.bonitasoft.engine.business.application.xml.AbstractApplicationNode; import org.bonitasoft.engine.business.application.xml.ApplicationNode; import org.bonitasoft.engine.business.application.xml.ApplicationNodeContainer; import org.bonitasoft.engine.commons.exceptions.SBonitaException; +import org.bonitasoft.engine.commons.exceptions.SObjectModificationException; import org.bonitasoft.engine.commons.exceptions.SObjectNotFoundException; import org.bonitasoft.engine.exception.AlreadyExistsException; import org.bonitasoft.engine.exception.ImportException; +import org.bonitasoft.engine.persistence.SBonitaReadException; import org.springframework.stereotype.Component; /** @@ -72,33 +75,20 @@ private void updateHomePage(final SApplicationWithIcon application, final Applic } } - public ImportStatus importApplication(ApplicationNode applicationNode, boolean editable, long createdBy, + public ImportStatus importApplication(AbstractApplicationNode applicationNode, boolean editable, long createdBy, byte[] iconContent, String iconMimeType, boolean addIfMissing, ApplicationImportStrategy strategy) throws ImportException, AlreadyExistsException { try { ImportResult importResult = nodeToApplicationConverter.toSApplication(applicationNode, iconContent, - iconMimeType, createdBy); + iconMimeType, createdBy, editable); + SApplicationWithIcon applicationToBeImported = importResult.getApplication(); - applicationToBeImported.setEditable(editable); ImportStatus importStatus = importResult.getImportStatus(); - SApplication conflictingApplication = applicationService - .getApplicationByToken(applicationToBeImported.getToken()); + importStatus.setStatus(ImportStatus.Status.ADDED); - if (conflictingApplication != null) { - switch (strategy.whenApplicationExists(conflictingApplication, applicationToBeImported)) { - case FAIL: - throw new AlreadyExistsException( - "An application with token '" + conflictingApplication.getToken() + "' already exists", - conflictingApplication.getToken()); - case REPLACE: - importStatus.setStatus(ImportStatus.Status.REPLACED); - applicationService.forceDeleteApplication(conflictingApplication); - break; - case SKIP: - importStatus.setStatus(ImportStatus.Status.SKIPPED); - break; - } - } + + // import status will change depending on the chosen strategy, or will throw exception + applyStrategyWhenApplicationExists(strategy, applicationToBeImported, importStatus); if (!addIfMissing) { importStatus.setStatus(ImportStatus.Status.SKIPPED); @@ -106,25 +96,52 @@ public ImportStatus importApplication(ApplicationNode applicationNode, boolean e if (importStatus.getStatus() != ImportStatus.Status.SKIPPED) { applicationService.createApplication(applicationToBeImported); - importStatus.addErrorsIfNotExists(applicationPageImporter - .importApplicationPages(applicationNode.getApplicationPages(), applicationToBeImported)); - importStatus - .addErrorsIfNotExists( - applicationMenuImporter.importApplicationMenus(applicationNode.getApplicationMenus(), - applicationToBeImported)); - updateHomePage(applicationToBeImported, applicationNode, createdBy, importResult); + + // import more elements for applications built with legacy UID + if (applicationNode instanceof ApplicationNode legacy) { + importStatus.addErrorsIfNotExists( + applicationPageImporter + .importApplicationPages(legacy.getApplicationPages(), applicationToBeImported)); + importStatus.addErrorsIfNotExists( + applicationMenuImporter + .importApplicationMenus(legacy.getApplicationMenus(), applicationToBeImported)); + updateHomePage(applicationToBeImported, legacy, createdBy, importResult); + } } + return importStatus; } catch (SBonitaException e) { throw new ImportException(e); } } + private void applyStrategyWhenApplicationExists(ApplicationImportStrategy strategy, + SApplicationWithIcon applicationToBeImported, ImportStatus importStatus) + throws SBonitaReadException, AlreadyExistsException, SObjectModificationException { + SApplication conflictingApplication = applicationService + .getApplicationByToken(applicationToBeImported.getToken()); + if (conflictingApplication != null) { + switch (strategy.whenApplicationExists(conflictingApplication, applicationToBeImported)) { + case FAIL: + throw new AlreadyExistsException( + "An application with token '" + conflictingApplication.getToken() + "' already exists", + conflictingApplication.getToken()); + case REPLACE: + importStatus.setStatus(ImportStatus.Status.REPLACED); + applicationService.forceDeleteApplication(conflictingApplication); + break; + case SKIP: + importStatus.setStatus(ImportStatus.Status.SKIPPED); + break; + } + } + } + public List importApplications(final byte[] xmlContent, byte[] iconContent, String iconMimeType, long createdBy, ApplicationImportStrategy strategy) throws ImportException, AlreadyExistsException { ApplicationNodeContainer applicationNodeContainer = getApplicationNodeContainer(xmlContent); List importStatus = new ArrayList<>(); - for (ApplicationNode applicationNode : applicationNodeContainer.getApplications()) { + for (AbstractApplicationNode applicationNode : applicationNodeContainer.getAllApplications()) { importStatus.add( importApplication(applicationNode, true, createdBy, iconContent, iconMimeType, true, strategy)); } diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/business/application/importer/LivingApplicationImporter.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/business/application/importer/LivingApplicationImporter.java index 4c36a977c0c..5e407f4f439 100644 --- a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/business/application/importer/LivingApplicationImporter.java +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/business/application/importer/LivingApplicationImporter.java @@ -24,7 +24,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.bonitasoft.engine.api.ImportStatus; -import org.bonitasoft.engine.business.application.xml.ApplicationNode; +import org.bonitasoft.engine.business.application.xml.AbstractApplicationNode; import org.bonitasoft.engine.business.application.xml.ApplicationNodeContainer; import org.bonitasoft.engine.commons.exceptions.SBonitaException; import org.bonitasoft.engine.exception.AlreadyExistsException; @@ -137,7 +137,7 @@ protected List importProvidedApplications(final byte[] xmlContent, throws ImportException, AlreadyExistsException { List importStatuses = new ArrayList<>(); ApplicationNodeContainer applicationNodeContainer = applicationImporter.getApplicationNodeContainer(xmlContent); - for (ApplicationNode applicationNode : applicationNodeContainer.getApplications()) { + for (AbstractApplicationNode applicationNode : applicationNodeContainer.getAllApplications()) { // set the strategy to skip it if a version already exists importStatuses.add( applicationImporter.importApplication(applicationNode, editable, SessionService.SYSTEM_ID, diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/execution/ProcessExecutorImpl.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/execution/ProcessExecutorImpl.java index fa3fa91ed58..f5d98eebcec 100644 --- a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/execution/ProcessExecutorImpl.java +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/execution/ProcessExecutorImpl.java @@ -16,8 +16,14 @@ import static org.bonitasoft.engine.classloader.ClassLoaderIdentifier.identifier; import java.io.Serializable; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import lombok.extern.slf4j.Slf4j; import org.bonitasoft.engine.SArchivingException; @@ -56,15 +62,38 @@ import org.bonitasoft.engine.core.process.definition.ProcessDefinitionService; import org.bonitasoft.engine.core.process.definition.exception.SProcessDefinitionException; import org.bonitasoft.engine.core.process.definition.exception.SProcessDefinitionNotFoundException; -import org.bonitasoft.engine.core.process.definition.model.*; +import org.bonitasoft.engine.core.process.definition.model.SBusinessDataDefinition; +import org.bonitasoft.engine.core.process.definition.model.SConnectorDefinition; +import org.bonitasoft.engine.core.process.definition.model.SContractDefinition; +import org.bonitasoft.engine.core.process.definition.model.SDocumentDefinition; +import org.bonitasoft.engine.core.process.definition.model.SDocumentListDefinition; +import org.bonitasoft.engine.core.process.definition.model.SFlowElementContainerDefinition; +import org.bonitasoft.engine.core.process.definition.model.SFlowNodeDefinition; +import org.bonitasoft.engine.core.process.definition.model.SFlowNodeType; +import org.bonitasoft.engine.core.process.definition.model.SGatewayDefinition; +import org.bonitasoft.engine.core.process.definition.model.SGatewayType; +import org.bonitasoft.engine.core.process.definition.model.SProcessDefinition; +import org.bonitasoft.engine.core.process.definition.model.SProcessDefinitionDeployInfo; +import org.bonitasoft.engine.core.process.definition.model.STransitionDefinition; import org.bonitasoft.engine.core.process.definition.model.event.SEndEventDefinition; import org.bonitasoft.engine.core.process.instance.api.ActivityInstanceService; import org.bonitasoft.engine.core.process.instance.api.GatewayInstanceService; import org.bonitasoft.engine.core.process.instance.api.ProcessInstanceService; import org.bonitasoft.engine.core.process.instance.api.RefBusinessDataService; -import org.bonitasoft.engine.core.process.instance.api.exceptions.*; +import org.bonitasoft.engine.core.process.instance.api.exceptions.SActivityInstanceNotFoundException; +import org.bonitasoft.engine.core.process.instance.api.exceptions.SActivityReadException; +import org.bonitasoft.engine.core.process.instance.api.exceptions.SContractViolationException; +import org.bonitasoft.engine.core.process.instance.api.exceptions.SFlowNodeExecutionException; +import org.bonitasoft.engine.core.process.instance.api.exceptions.SProcessInstanceCreationException; +import org.bonitasoft.engine.core.process.instance.api.exceptions.SProcessInstanceModificationException; import org.bonitasoft.engine.core.process.instance.api.states.FlowNodeState; -import org.bonitasoft.engine.core.process.instance.model.*; +import org.bonitasoft.engine.core.process.instance.model.SActivityInstance; +import org.bonitasoft.engine.core.process.instance.model.SConnectorInstance; +import org.bonitasoft.engine.core.process.instance.model.SFlowElementsContainerType; +import org.bonitasoft.engine.core.process.instance.model.SFlowNodeInstance; +import org.bonitasoft.engine.core.process.instance.model.SGatewayInstance; +import org.bonitasoft.engine.core.process.instance.model.SProcessInstance; +import org.bonitasoft.engine.core.process.instance.model.SStateCategory; import org.bonitasoft.engine.core.process.instance.model.builder.business.data.SRefBusinessDataInstanceBuilderFactory; import org.bonitasoft.engine.core.process.instance.model.business.data.SRefBusinessDataInstance; import org.bonitasoft.engine.core.process.instance.model.event.SThrowEventInstance; @@ -78,7 +107,6 @@ import org.bonitasoft.engine.execution.event.EventsHandler; import org.bonitasoft.engine.execution.flowmerger.FlowNodeTransitionsWrapper; import org.bonitasoft.engine.execution.handler.SProcessInstanceHandler; -import org.bonitasoft.engine.execution.state.FlowNodeStateManager; import org.bonitasoft.engine.execution.work.BPMWorkFactory; import org.bonitasoft.engine.expression.Expression; import org.bonitasoft.engine.expression.ExpressionService; @@ -120,7 +148,7 @@ public class ProcessExecutorImpl implements ProcessExecutor { private final ProcessDefinitionService processDefinitionService; private final GatewayInstanceService gatewayInstanceService; private final OperationService operationService; - private ProcessResourcesService processResourcesService; + private final ProcessResourcesService processResourcesService; private final ConnectorInstanceService connectorInstanceService; private final TransitionEvaluator transitionEvaluator; private final ContractDataService contractDataService; @@ -129,6 +157,7 @@ public class ProcessExecutorImpl implements ProcessExecutor { private final DocumentHelper documentHelper; private final BPMWorkFactory workFactory; private final BPMArchiverService bpmArchiverService; + private final ProcessStarterVerifier processStarterVerifier; public ProcessExecutorImpl(final ActivityInstanceService activityInstanceService, final ProcessInstanceService processInstanceService, final FlowNodeExecutor flowNodeExecutor, @@ -142,11 +171,11 @@ public ProcessExecutorImpl(final ActivityInstanceService activityInstanceService final EventService eventService, final Map> handlers, final DocumentService documentService, final ContainerRegistry containerRegistry, final BPMInstancesCreator bpmInstancesCreator, - final EventsHandler eventsHandler, final FlowNodeStateManager flowNodeStateManager, + final EventsHandler eventsHandler, final BusinessDataRepository businessDataRepository, final RefBusinessDataService refBusinessDataService, final TransitionEvaluator transitionEvaluator, final ContractDataService contractDataService, BPMWorkFactory workFactory, - BPMArchiverService bpmArchiverService) { + BPMArchiverService bpmArchiverService, final ProcessStarterVerifier processStarterVerifier) { super(); this.activityInstanceService = activityInstanceService; this.processInstanceService = processInstanceService; @@ -169,6 +198,7 @@ public ProcessExecutorImpl(final ActivityInstanceService activityInstanceService this.contractDataService = contractDataService; this.workFactory = workFactory; this.bpmArchiverService = bpmArchiverService; + this.processStarterVerifier = processStarterVerifier; documentHelper = new DocumentHelper(documentService, processDefinitionService, processInstanceService); //FIXME There is responsibility issue the circular dependencies must be fixed next time. eventsHandler.setProcessExecutor(this); @@ -914,8 +944,7 @@ protected SProcessInstance start(final long starterId, final long starterSubstit final List operations, final Map context, final List connectors, final long callerId, final FlowNodeSelector selector, final Map processInputs) - throws SProcessInstanceCreationException, - SContractViolationException { + throws SProcessInstanceCreationException, SContractViolationException { final SProcessDefinition sProcessDefinition = selector.getProcessDefinition(); @@ -933,6 +962,7 @@ protected SProcessInstance start(final long starterId, final long starterSubstit setProcessClassloader(sProcessDefinition); final SProcessInstance sProcessInstance = createProcessInstance(sProcessDefinition, starterId, starterSubstituteId, callerId); + processStarterVerifier.verify(sProcessInstance); final boolean isInitializing = initialize(starterId, sProcessDefinition, sProcessInstance, expressionContextToEvaluateOperations, operations, context, selector.getContainer(), connectors, diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/execution/ProcessStarterVerifier.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/execution/ProcessStarterVerifier.java new file mode 100644 index 00000000000..4a70f186db3 --- /dev/null +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/execution/ProcessStarterVerifier.java @@ -0,0 +1,40 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.engine.execution; + +import org.bonitasoft.engine.core.process.instance.api.exceptions.SProcessInstanceCreationException; +import org.bonitasoft.engine.core.process.instance.model.SProcessInstance; + +/** + * Define rules to be executed before the start of a process, right after its creation. + */ +public interface ProcessStarterVerifier { + + /** + * Verify that a process is ready to be started right after its creation. + * + * @param processInstance the process instance that is going to be started + * @throws SProcessInstanceCreationException if the process is not in a valid state to start + */ + void verify(SProcessInstance processInstance) throws SProcessInstanceCreationException; + + /** + * Get the current number of started process instances. + * + * @return -1 if non relevant in this context + */ + default long getCurrentNumberOfStartedProcessInstances() { + return -1; + } +} diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/execution/ProcessStarterVerifierImpl.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/execution/ProcessStarterVerifierImpl.java new file mode 100644 index 00000000000..b321957663a --- /dev/null +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/execution/ProcessStarterVerifierImpl.java @@ -0,0 +1,216 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.engine.execution; + +import static java.lang.String.format; +import static java.lang.System.currentTimeMillis; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.bonitasoft.engine.core.process.instance.api.ProcessInstanceService; +import org.bonitasoft.engine.core.process.instance.api.exceptions.SProcessInstanceCreationException; +import org.bonitasoft.engine.core.process.instance.model.SProcessInstance; +import org.bonitasoft.engine.platform.PlatformRetriever; +import org.bonitasoft.engine.platform.exception.SPlatformNotFoundException; +import org.bonitasoft.engine.platform.exception.SPlatformUpdateException; +import org.bonitasoft.engine.service.platform.PlatformInformationService; +import org.bonitasoft.engine.transaction.TransactionService; +import org.bonitasoft.platform.setup.SimpleEncryptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; +import org.springframework.stereotype.Component; + +@Component +@ConditionalOnSingleCandidate(ProcessStarterVerifier.class) +@Slf4j +public class ProcessStarterVerifierImpl implements ProcessStarterVerifier { + + public static final int LIMIT = 150; + protected static final int PERIOD_IN_DAYS = 30; + protected static final long PERIOD_IN_MILLIS = PERIOD_IN_DAYS * 24L * 60L * 60L * 1000L; + protected static final List THRESHOLDS_IN_PERCENT = List.of(80, 90); + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + + private final PlatformRetriever platformRetriever; + private final PlatformInformationService platformInformationService; + private final TransactionService transactionService; + private final ProcessInstanceService processInstanceService; + + private final List counters = Collections.synchronizedList(new ArrayList<>()); + + @Autowired + public ProcessStarterVerifierImpl(PlatformRetriever platformRetriever, + PlatformInformationService platformInformationService, + TransactionService transactionService, + ProcessInstanceService processInstanceService) throws Exception { + this.platformRetriever = platformRetriever; + this.platformInformationService = platformInformationService; + this.transactionService = transactionService; + this.processInstanceService = processInstanceService; + counters.addAll(setupCounters(transactionService)); + // clean up old values: + final long oldestValidDate = currentTimeMillis() - PERIOD_IN_MILLIS; + cleanupOldValues(oldestValidDate); + // then check database integrity: + verifyCountersCoherence(counters, oldestValidDate); + } + + List setupCounters(TransactionService transactionService) throws Exception { + return transactionService.executeInTransaction(this::readCounters); + } + + protected List getCounters() { + return Collections.unmodifiableList(counters); + } + + protected void addCounter(long counter) { + synchronized (counters) { + counters.add(counter); + } + } + + @Override + public void verify(SProcessInstance processInstance) throws SProcessInstanceCreationException { + log.debug("Verifying the possibility to create process instance {}", processInstance.getId()); + final long processStartDate = processInstance.getStartDate(); + cleanupOldValues(processStartDate - PERIOD_IN_MILLIS); + log.debug("Found {} cases already started in the last {} days", counters.size(), PERIOD_IN_DAYS); + + if (counters.size() >= LIMIT) { + var nextResetTimestamp = getNextResetTimestamp(counters); + final String nextValidTime = getStringRepresentation(nextResetTimestamp); + throw new SProcessInstanceCreationException( + format("Process start limit (%s cases during last %s days) reached. You are not allowed to start a new process until %s.", + LIMIT, PERIOD_IN_DAYS, nextValidTime), + nextResetTimestamp); + } + try { + synchronized (counters) { + counters.add(processStartDate); + } + final String information = encryptDataBeforeSendingToDatabase(counters); + // store in database: + storeNewValueInDatabase(information); + logCaseLimitProgressIfThresholdReached(); + } catch (IOException | SPlatformNotFoundException | SPlatformUpdateException e) { + log.trace(e.getMessage(), e); + throw new SProcessInstanceCreationException( + format("Unable to start the process instance %s", processInstance.getId()), e); + } + } + + void cleanupOldValues(long olderThanInMilliseconds) { + log.trace("Cleaning up old values for the last {} days", PERIOD_IN_DAYS); + synchronized (counters) { + counters.removeIf(timestamp -> timestamp < olderThanInMilliseconds); + } + } + + void storeNewValueInDatabase(String information) throws SPlatformUpdateException, SPlatformNotFoundException { + platformInformationService.updatePlatformInfo(platformRetriever.getPlatform(), information); + } + + List readCounters() { + try { + String information = platformRetriever.getPlatform().getInformation(); + if (information == null || information.isBlank()) { + throw new IllegalStateException("Invalid database. Please reset it and restart."); + } + return decryptDataFromDatabase(information); + } catch (SPlatformNotFoundException | IOException e) { + throw new IllegalStateException("Cannot read from database table 'platform'", e); + } + } + + @Override + public long getCurrentNumberOfStartedProcessInstances() { + return counters.size(); + } + + String encryptDataBeforeSendingToDatabase(List counters) throws IOException { + return encrypt(OBJECT_MAPPER.writeValueAsBytes(counters)); + } + + List decryptDataFromDatabase(String information) throws IOException { + return OBJECT_MAPPER.readValue(decrypt(information), new TypeReference<>() { + }); + } + + private static String encrypt(byte[] data) { + try { + return SimpleEncryptor.encrypt(data); + } catch (GeneralSecurityException e) { + throw new IllegalStateException("Cannot cipher information", e); + } + } + + private static byte[] decrypt(String information) { + try { + return SimpleEncryptor.decrypt(information); + } catch (GeneralSecurityException e) { + throw new IllegalStateException("Cannot decipher information", e); + } + } + + List fetchLastArchivedProcessInstanceStartDates(Long oldestValidDate) throws Exception { + final List startDates = transactionService.executeInTransaction( + () -> processInstanceService.getLastArchivedProcessInstanceStartDates(oldestValidDate)); + // print the start dates to the log: + log.debug("Last archived process instance start dates: {}", startDates); + return startDates; + } + + public void verifyCountersCoherence(List counters, Long oldestValidDate) throws Exception { + final List lastArchivedProcessInstanceStartDates = fetchLastArchivedProcessInstanceStartDates( + oldestValidDate); + for (Long startDate : lastArchivedProcessInstanceStartDates) { + if (!counters.contains(startDate)) { + throw new IllegalStateException("Invalid database. Please reset it and restart."); + } + } + } + + void logCaseLimitProgressIfThresholdReached() { + var percentBeforeThisNewCase = (float) ((getCounters().size() - 1) * 100) / LIMIT; + var percentWithThisNewCase = (float) ((getCounters().size()) * 100) / LIMIT; + for (Integer threshold : THRESHOLDS_IN_PERCENT) { + if (percentBeforeThisNewCase < threshold && percentWithThisNewCase >= threshold) { + log.warn("You have started {}% of your allowed cases." + + "If you need more volume, please consider subscribing to an Enterprise edition.", + threshold); + } + } + } + + /** + * Returns a timestamp to a human-readable format + */ + private String getStringRepresentation(long timestamp) { + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(timestamp)); + } + + private long getNextResetTimestamp(List timestamps) { + return Collections.min(timestamps) + PERIOD_IN_MILLIS; + } + +} diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/search/descriptor/SearchApplicationDescriptor.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/search/descriptor/SearchApplicationDescriptor.java index 1b6c997f7c1..40b31637f91 100755 --- a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/search/descriptor/SearchApplicationDescriptor.java +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/search/descriptor/SearchApplicationDescriptor.java @@ -33,7 +33,7 @@ public class SearchApplicationDescriptor extends SearchEntityDescriptor { private final Map, Set> allFields; - SearchApplicationDescriptor() { + protected SearchApplicationDescriptor() { keys = new HashMap<>(13); keys.put(ApplicationSearchDescriptor.ID, new FieldDescriptor(SApplication.class, AbstractSApplication.ID)); diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/ServiceAccessor.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/ServiceAccessor.java index ae58dd34df6..c2b541d2a01 100644 --- a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/ServiceAccessor.java +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/ServiceAccessor.java @@ -59,6 +59,7 @@ import org.bonitasoft.engine.execution.FlowNodeExecutor; import org.bonitasoft.engine.execution.ProcessExecutor; import org.bonitasoft.engine.execution.ProcessInstanceInterruptor; +import org.bonitasoft.engine.execution.ProcessStarterVerifier; import org.bonitasoft.engine.execution.archive.BPMArchiverService; import org.bonitasoft.engine.execution.event.EventsHandler; import org.bonitasoft.engine.execution.state.FlowNodeStateManager; @@ -104,6 +105,7 @@ import org.bonitasoft.engine.work.WorkExecutorService; import org.bonitasoft.engine.work.WorkService; import org.springframework.context.ApplicationContext; +import org.springframework.core.env.Environment; /** * @author Matthieu Chaffotte @@ -311,4 +313,8 @@ public interface ServiceAccessor { PlatformRetriever getPlatformRetriever(); InstallationService getInstallationService(); + + ProcessStarterVerifier getProcessStarterVerifier(); + + Environment getSpringEnvironment(); } diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/impl/APIAccessResolverImpl.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/impl/APIAccessResolverImpl.java index a395c736f4b..25b5ab57c6b 100644 --- a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/impl/APIAccessResolverImpl.java +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/impl/APIAccessResolverImpl.java @@ -18,6 +18,8 @@ import org.bonitasoft.engine.api.*; import org.bonitasoft.engine.api.impl.*; +import org.bonitasoft.engine.api.impl.platform.PlatformInformationAPIImpl; +import org.bonitasoft.engine.api.platform.PlatformInformationAPI; import org.bonitasoft.engine.exception.APIImplementationNotFoundException; import org.bonitasoft.engine.service.APIAccessResolver; @@ -45,6 +47,7 @@ public class APIAccessResolverImpl implements APIAccessResolver { apis.put(BusinessDataAPI.class.getName(), new BusinessDataAPIImpl()); apis.put(TemporaryContentAPI.class.getName(), new TemporaryContentAPIImpl()); apis.put(MaintenanceAPI.class.getName(), new MaintenanceAPIImpl()); + apis.put(PlatformInformationAPI.class.getName(), new PlatformInformationAPIImpl()); } @Override diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/impl/SpringBeanAccessor.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/impl/SpringBeanAccessor.java index 20170fbc0ad..15fddbe26f1 100644 --- a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/impl/SpringBeanAccessor.java +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/impl/SpringBeanAccessor.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.util.Properties; import lombok.extern.slf4j.Slf4j; @@ -44,6 +45,17 @@ public class SpringBeanAccessor { private static final String HAZELCAST_CONFIG_FILENAME = "hazelcast.xml"; static final BonitaHomeServer BONITA_HOME_SERVER = BonitaHomeServer.getInstance(); + + private static final String WORK_CORE_POOL_SIZE = "bonita.tenant.work.corePoolSize"; + private static final String WORK_MAX_POOL_SIZE = "bonita.tenant.work.maximumPoolSize"; + private static final String WORK_KEEP_ALIVE_IN_SECONDS = "bonita.tenant.work.keepAliveTimeSeconds"; + private static final String WORK_SQLSERVER_DELAY_ON_MULTIPLE_XA_RESOURCE = "bonita.tenant.work.sqlserver.delayOnMultipleXAResource"; + private static final String WORK_MYSQL_DELAY_ON_MULTIPLE_XA_RESOURCE = "bonita.tenant.work.mysql.delayOnMultipleXAResource"; + private static final String WORK_ORACLE_DELAY_ON_MULTIPLE_XA_RESOURCE = "bonita.tenant.work.oracle.delayOnMultipleXAResource"; + private static final String CONNECTOR_CORE_POOL_SIZE = "bonita.tenant.connector.corePoolSize"; + private static final String CONNECTOR_MAX_POOL_SIZE = "bonita.tenant.connector.maximumPoolSize"; + private static final String CONNECTOR_KEEP_ALIVE_IN_SECONDS = "bonita.tenant.connector.keepAliveTimeSeconds"; + private BonitaSpringContext context; private boolean contextFinishedInitialized = false; @@ -108,6 +120,30 @@ private void configureContext(BonitaSpringContext context) throws IOException { propertySources.addAfter(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, new PropertiesPropertySource("contextProperties", getProperties())); } + warnDeprecatedProperties(propertySources); + } + + protected void warnDeprecatedProperties(MutablePropertySources propertySources) { + warnIfPropertyIsDeprecated(propertySources, WORK_CORE_POOL_SIZE); + warnIfPropertyIsDeprecated(propertySources, WORK_MAX_POOL_SIZE); + warnIfPropertyIsDeprecated(propertySources, WORK_KEEP_ALIVE_IN_SECONDS); + warnIfPropertyIsDeprecated(propertySources, WORK_SQLSERVER_DELAY_ON_MULTIPLE_XA_RESOURCE); + warnIfPropertyIsDeprecated(propertySources, WORK_MYSQL_DELAY_ON_MULTIPLE_XA_RESOURCE); + warnIfPropertyIsDeprecated(propertySources, WORK_ORACLE_DELAY_ON_MULTIPLE_XA_RESOURCE); + warnIfPropertyIsDeprecated(propertySources, CONNECTOR_CORE_POOL_SIZE); + warnIfPropertyIsDeprecated(propertySources, CONNECTOR_MAX_POOL_SIZE); + warnIfPropertyIsDeprecated(propertySources, CONNECTOR_KEEP_ALIVE_IN_SECONDS); + } + + private void warnIfPropertyIsDeprecated(MutablePropertySources propertySources, String property) { + propertySources.stream() + .filter(ps -> ps.containsProperty(property)) + .map(ps -> ps.getProperty(property)) + .filter(Objects::nonNull) + .findFirst() + .ifPresent(value -> log.warn( + "{} property is not supported in community edition anymore. It will be ignored.", + property)); } protected BonitaSpringContext createContext() { diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/impl/SpringServiceAccessor.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/impl/SpringServiceAccessor.java index 8f7916fc3f2..7a55275d0b8 100644 --- a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/impl/SpringServiceAccessor.java +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/impl/SpringServiceAccessor.java @@ -60,6 +60,7 @@ import org.bonitasoft.engine.execution.FlowNodeExecutor; import org.bonitasoft.engine.execution.ProcessExecutor; import org.bonitasoft.engine.execution.ProcessInstanceInterruptor; +import org.bonitasoft.engine.execution.ProcessStarterVerifier; import org.bonitasoft.engine.execution.archive.BPMArchiverService; import org.bonitasoft.engine.execution.event.EventsHandler; import org.bonitasoft.engine.execution.state.FlowNodeStateManager; @@ -113,6 +114,7 @@ import org.bonitasoft.engine.work.WorkService; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.context.ApplicationContext; +import org.springframework.core.env.Environment; public class SpringServiceAccessor implements ServiceAccessor, TenantServiceAccessor, PlatformServiceAccessor, PlatformInitServiceAccessor { @@ -128,6 +130,11 @@ public ParentContainerResolver getParentContainerResolver() { return beanAccessor.getService(ParentContainerResolver.class); } + @Override + public Environment getSpringEnvironment() { + return beanAccessor.getContext().getEnvironment(); + } + @Override public TimeTracker getTimeTracker() { return beanAccessor.getService(TimeTracker.class); @@ -644,4 +651,9 @@ public PlatformRetriever getPlatformRetriever() { public InstallationService getInstallationService() { return beanAccessor.getService(InstallationService.class); } + + @Override + public ProcessStarterVerifier getProcessStarterVerifier() { + return beanAccessor.getService(ProcessStarterVerifier.class); + } } diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/platform/PlatformInformationService.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/platform/PlatformInformationService.java new file mode 100644 index 00000000000..5b0113c0ac8 --- /dev/null +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/platform/PlatformInformationService.java @@ -0,0 +1,34 @@ +/** + * Copyright (C) 2019 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.engine.service.platform; + +import org.bonitasoft.engine.platform.exception.SPlatformUpdateException; +import org.bonitasoft.engine.platform.model.SPlatform; + +/** + * @author Elias Ricken de Medeiros + */ +public interface PlatformInformationService { + + /** + * Updates the platform information + * + * @param platform the platform to be updated + * @param platformInfo the new platform information + * @throws SPlatformUpdateException + * @since 7.1.0 + */ + void updatePlatformInfo(SPlatform platform, String platformInfo) throws SPlatformUpdateException; + +} diff --git a/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/platform/PlatformInformationServiceImpl.java b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/platform/PlatformInformationServiceImpl.java new file mode 100644 index 00000000000..10fcc891cf1 --- /dev/null +++ b/bpm/bonita-core/bonita-process-engine/src/main/java/org/bonitasoft/engine/service/platform/PlatformInformationServiceImpl.java @@ -0,0 +1,51 @@ +/** + * Copyright (C) 2019 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.engine.service.platform; + +import org.bonitasoft.engine.platform.exception.SPlatformUpdateException; +import org.bonitasoft.engine.platform.model.SPlatform; +import org.bonitasoft.engine.services.PersistenceService; +import org.bonitasoft.engine.services.SPersistenceException; +import org.bonitasoft.engine.services.UpdateDescriptor; +import org.springframework.stereotype.Service; + +/** + * Updates the platform information using directly the {@link PersistenceService} + * + * @author Elias Ricken de Medeiros + */ +@Service("platformInformationService") +public class PlatformInformationServiceImpl implements PlatformInformationService { + + private final PersistenceService persistenceService; + + public PlatformInformationServiceImpl(final PersistenceService persistenceService) { + this.persistenceService = persistenceService; + } + + @Override + public void updatePlatformInfo(final SPlatform platform, final String platformInfo) + throws SPlatformUpdateException { + + UpdateDescriptor desc = new UpdateDescriptor(platform); + desc.addField(SPlatform.INFORMATION, platformInfo); + + try { + persistenceService.update(desc); + } catch (SPersistenceException e) { + throw new SPlatformUpdateException(e); + } + } + +} diff --git a/bpm/bonita-core/bonita-process-engine/src/main/resources/bonita-community.xml b/bpm/bonita-core/bonita-process-engine/src/main/resources/bonita-community.xml index 1517e211ddf..297c5da1bdb 100644 --- a/bpm/bonita-core/bonita-process-engine/src/main/resources/bonita-community.xml +++ b/bpm/bonita-core/bonita-process-engine/src/main/resources/bonita-community.xml @@ -1226,12 +1226,12 @@ - +
    - - - - - - - - - - - @@ -1726,7 +1715,6 @@ - @@ -1976,7 +1964,6 @@ - diff --git a/bpm/bonita-core/bonita-process-engine/src/main/resources/bonita-platform-private-community.properties b/bpm/bonita-core/bonita-process-engine/src/main/resources/bonita-platform-private-community.properties index a426e314b74..b0df05e3c1b 100644 --- a/bpm/bonita-core/bonita-process-engine/src/main/resources/bonita-platform-private-community.properties +++ b/bpm/bonita-core/bonita-process-engine/src/main/resources/bonita-platform-private-community.properties @@ -7,28 +7,12 @@ serverApi=org.bonitasoft.engine.api.impl.ServerAPIImpl # Hibernate Dialects h2.hibernate.dialect=org.hibernate.dialect.H2Dialect -mysql.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect -oracle.hibernate.dialect=org.hibernate.dialect.Oracle12cDialect postgres.hibernate.dialect=org.hibernate.dialect.PostgreSQL10Dialect -sqlserver.hibernate.dialect=org.bonitasoft.engine.persistence.SQLServerExtendedDialect # Hibernate Interceptors for journal (runtime database) h2.hibernate.journal.interceptor= -mysql.hibernate.journal.interceptor= -oracle.hibernate.journal.interceptor=org.bonitasoft.engine.persistence.OracleInterceptor postgres.hibernate.journal.interceptor=org.bonitasoft.engine.persistence.PostgresInterceptor -sqlserver.hibernate.journal.interceptor=org.bonitasoft.engine.persistence.SQLServerInterceptor # Quartz properties h2.quartz.connection.jobstoredriver=org.quartz.impl.jdbcjobstore.StdJDBCDelegate -mysql.quartz.connection.jobstoredriver=org.quartz.impl.jdbcjobstore.StdJDBCDelegate -oracle.quartz.connection.jobstoredriver=org.quartz.impl.jdbcjobstore.StdJDBCDelegate postgres.quartz.connection.jobstoredriver=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate -sqlserver.quartz.connection.jobstoredriver=org.quartz.impl.jdbcjobstore.MSSQLDelegate - -# Sql Delimiters -h2.sql.delimiter=; -mysql.sql.delimiter=; -oracle.sql.delimiter=; -postgres.sql.delimiter=; -sqlserver.sql.delimiter=GO diff --git a/bpm/bonita-core/bonita-process-engine/src/main/resources/bonita-tenant-community.properties b/bpm/bonita-core/bonita-process-engine/src/main/resources/bonita-tenant-community.properties index 7284cd099f0..858a36cdd4e 100644 --- a/bpm/bonita-core/bonita-process-engine/src/main/resources/bonita-tenant-community.properties +++ b/bpm/bonita-core/bonita-process-engine/src/main/resources/bonita-tenant-community.properties @@ -22,9 +22,6 @@ bonita.runtime.session.duration=3600000 # Connector executor bonita.tenant.connector.queueCapacity=10000 -bonita.tenant.connector.corePoolSize=10 -bonita.tenant.connector.maximumPoolSize=10 -bonita.tenant.connector.keepAliveTimeSeconds=100 # Produce a warning log when connector took longer to execute than this value bonita.tenant.connector.warnWhenLongerThanMillis=10000 @@ -32,15 +29,8 @@ bonita.tenant.connector.warnWhenLongerThanMillis=10000 # Work service # Time to wait in seconds for all work to terminate when the service is paused or stopped bonita.tenant.work.terminationTimeout=30 -bonita.tenant.work.corePoolSize=10 -bonita.tenant.work.maximumPoolSize=10 -bonita.tenant.work.keepAliveTimeSeconds=60 bonita.tenant.work.queueCapacity=500000 -# Add a delay on work when the transaction that registers the work has multiple XA Resources -# This is an SQL Server specific property to ensure all data commit are visible when the next work is executed. -bonita.tenant.work.sqlserver.delayOnMultipleXAResource=100 - # When a work fails, log only a limited number of frames from the stacktrace bonita.tenant.work.exceptionsNumberOfFrameToLog=3 diff --git a/bpm/bonita-core/bonita-process-engine/src/main/resources/bonita-tenant-private-community.properties b/bpm/bonita-core/bonita-process-engine/src/main/resources/bonita-tenant-private-community.properties deleted file mode 100644 index 9729b4a6206..00000000000 --- a/bpm/bonita-core/bonita-process-engine/src/main/resources/bonita-tenant-private-community.properties +++ /dev/null @@ -1,6 +0,0 @@ -# Hibernate Dialects -h2.hibernate.dialect=org.hibernate.dialect.H2Dialect -mysql.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect -oracle.hibernate.dialect=org.hibernate.dialect.Oracle12cDialect -postgres.hibernate.dialect=org.hibernate.dialect.PostgreSQL10Dialect -sqlserver.hibernate.dialect=org.bonitasoft.engine.persistence.SQLServerExtendedDialect \ No newline at end of file diff --git a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/application/installer/ApplicationArchiveReaderTest.java b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/application/installer/ApplicationArchiveReaderTest.java index 3f3eaa0d580..d18b5b2e095 100644 --- a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/application/installer/ApplicationArchiveReaderTest.java +++ b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/application/installer/ApplicationArchiveReaderTest.java @@ -43,14 +43,14 @@ public class ApplicationArchiveReaderTest { public void should_read_application_archive_with_a_live_application() throws Exception { byte[] zip = zip( file("apps/MyApp.xml", - "")); + "")); ApplicationArchive applicationArchive = applicationArchiveReader.read(asInputStream(zip)); assertThat(applicationArchive.getApplications().size()).isEqualTo(1); assertThat(applicationArchive.getApplications().get(0).getName()).isEqualTo("MyApp.xml"); assertThat(new String(Files.readAllBytes(applicationArchive.getApplications().get(0).toPath()))).contains( - ""); + ""); } diff --git a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/application/installer/ApplicationInstallerTest.java b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/application/installer/ApplicationInstallerTest.java index bfd3977eef3..b2410015052 100644 --- a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/application/installer/ApplicationInstallerTest.java +++ b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/application/installer/ApplicationInstallerTest.java @@ -96,7 +96,7 @@ class ApplicationInstallerTest { @InjectMocks @Spy - private ApplicationInstaller applicationInstaller; + private ApplicationInstallerImpl applicationInstaller; @BeforeEach void before() throws Exception { @@ -412,7 +412,8 @@ void install_should_call_install_configuration_file_on_installation_service() th // when: applicationInstaller.installConfiguration( - new File(ApplicationInstaller.class.getResource("/RequestLoan_conf_with_null_params.bconf").getFile()), + new File(ApplicationInstallerImpl.class.getResource("/RequestLoan_conf_with_null_params.bconf") + .getFile()), executionResult); // then: diff --git a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/application/installer/ApplicationInstallerUpdateTest.java b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/application/installer/ApplicationInstallerUpdateTest.java index 968b2164b3c..7731fafa487 100644 --- a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/application/installer/ApplicationInstallerUpdateTest.java +++ b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/application/installer/ApplicationInstallerUpdateTest.java @@ -81,7 +81,7 @@ public class ApplicationInstallerUpdateTest { @InjectMocks @Spy - private ApplicationInstaller applicationInstaller; + private ApplicationInstallerImpl applicationInstaller; @Before public void before() throws Exception { diff --git a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/application/installer/CustomOrDefaultApplicationInstallerConfigTest.java b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/application/installer/CustomOrDefaultApplicationInstallerConfigTest.java index 71c34d4352f..62c9b2671bf 100644 --- a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/application/installer/CustomOrDefaultApplicationInstallerConfigTest.java +++ b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/application/installer/CustomOrDefaultApplicationInstallerConfigTest.java @@ -45,7 +45,7 @@ static class TextConfiguration { @Bean public CustomOrDefaultApplicationInstaller installer() { - return new CustomOrDefaultApplicationInstaller(mock(ApplicationInstaller.class), + return new CustomOrDefaultApplicationInstaller(mock(ApplicationInstallerImpl.class), mock(DefaultLivingApplicationImporter.class), mock(MandatoryLivingApplicationImporter.class), mock(TenantServicesManager.class), mock(ApplicationArchiveReader.class), mock(PlatformService.class)); diff --git a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/application/installer/CustomOrDefaultApplicationInstallerTest.java b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/application/installer/CustomOrDefaultApplicationInstallerTest.java index 316772b1e7e..bca808dc674 100644 --- a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/application/installer/CustomOrDefaultApplicationInstallerTest.java +++ b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/application/installer/CustomOrDefaultApplicationInstallerTest.java @@ -53,7 +53,7 @@ class CustomOrDefaultApplicationInstallerTest { ArgumentCaptor> callableCaptor; @Mock - private ApplicationInstaller applicationInstaller; + private ApplicationInstallerImpl applicationInstaller; @Mock DefaultLivingApplicationImporter defaultLivingApplicationImporter; @Mock diff --git a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/converter/ApplicationModelConverterTest.java b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/converter/ApplicationModelConverterTest.java index 1c971bafb60..cd17252d138 100644 --- a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/converter/ApplicationModelConverterTest.java +++ b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/converter/ApplicationModelConverterTest.java @@ -215,7 +215,7 @@ public void toApplication_must_map_all_server_fields() throws Exception { sApp.setInternalProfile(internalProfileAll.getProfileName()); //when - final Application application = converter.toApplication(sApp); + final Application application = (Application) converter.toApplication(sApp); //then assertThat(application).isNotNull(); @@ -249,7 +249,7 @@ public void toApplication_must_set_false_when_application_icon_mime_type_is_null state); //when - final Application application = converter.toApplication(sApp); + final Application application = (Application) converter.toApplication(sApp); //then assertThat(application.hasIcon()).isFalse(); @@ -266,7 +266,7 @@ public void toApplicationList_should_call_toApplication_for_each_element_in_the_ CREATOR_ID, SApplicationState.DEACTIVATED.name()); //when - final List applications = converter.toApplication(Arrays. asList(sApp1, sApp2)); + final List applications = converter.toApplication(Arrays. asList(sApp1, sApp2)); //then assertThat(applications).extracting("token").containsExactly(APP_NAME, APP_NAME2); diff --git a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/livingapplication/LivingApplicationAPIDelegateTest.java b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/livingapplication/LivingApplicationAPIDelegateTest.java index 251551fae37..d2af91475de 100755 --- a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/livingapplication/LivingApplicationAPIDelegateTest.java +++ b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/livingapplication/LivingApplicationAPIDelegateTest.java @@ -14,6 +14,7 @@ package org.bonitasoft.engine.api.impl.livingapplication; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.*; @@ -24,10 +25,15 @@ import org.bonitasoft.engine.api.impl.transaction.application.SearchApplications; import org.bonitasoft.engine.business.application.Application; import org.bonitasoft.engine.business.application.ApplicationCreator; +import org.bonitasoft.engine.business.application.ApplicationLink; +import org.bonitasoft.engine.business.application.ApplicationLinkCreator; +import org.bonitasoft.engine.business.application.ApplicationLinkUpdater; import org.bonitasoft.engine.business.application.ApplicationNotFoundException; import org.bonitasoft.engine.business.application.ApplicationService; import org.bonitasoft.engine.business.application.ApplicationUpdater; +import org.bonitasoft.engine.business.application.IApplication; import org.bonitasoft.engine.business.application.impl.ApplicationImpl; +import org.bonitasoft.engine.business.application.impl.ApplicationLinkImpl; import org.bonitasoft.engine.business.application.importer.validator.ApplicationTokenValidator; import org.bonitasoft.engine.business.application.importer.validator.ValidationStatus; import org.bonitasoft.engine.business.application.model.SApplication; @@ -65,13 +71,13 @@ public class LivingApplicationAPIDelegateTest { private ApplicationModelConverter converter; @Mock - private SearchApplications searchApplications; + private SearchApplications searchApplications; @Mock private ApplicationService applicationService; @Mock - private SearchResult appSearchResult; + private SearchResult appSearchResult; @Mock ApplicationTokenValidator validator; @@ -128,6 +134,26 @@ public void createApplication_should_call_applicationService_createApplication_a assertThat(createdApplication).isEqualTo(application); } + @Test + public void createApplicationLink_should_call_applicationService_createApplication_and_return_created_application() + throws Exception { + //given + final ApplicationLinkCreator creator = new ApplicationLinkCreator(APP_TOKEN, APP_DISP_NAME, VERSION); + creator.setDescription(DESCRIPTION); + final SApplicationWithIcon sApp = buildDefaultApplicationWithMetadata(); + sApp.setDescription(DESCRIPTION); + final ApplicationLinkImpl applicationLink = new ApplicationLinkImpl(APP_TOKEN, VERSION, DESCRIPTION); + given(converter.buildSApplication(creator, LOGGED_USER_ID)).willReturn(sApp); + given(converter.toApplication(sApp)).willReturn(applicationLink); + given(applicationService.createApplication(sApp)).willReturn(sApp); + + //when + final ApplicationLink createdApplication = delegate.createApplicationLink(creator); + + //then + assertThat(createdApplication).isEqualTo(applicationLink); + } + private SApplication buildDefaultApplication() { return new SApplication(APP_TOKEN, APP_DISP_NAME, VERSION, System.currentTimeMillis(), LOGGED_USER_ID, SApplicationState.DEACTIVATED.name()); @@ -248,7 +274,7 @@ public void getApplication_should_return_the_application_returned_by_application given(converter.toApplication(sApp)).willReturn(application); //when - final Application retriedApp = delegate.getApplication(APPLICATION_ID); + final IApplication retriedApp = delegate.getIApplication(APPLICATION_ID); //then assertThat(retriedApp).isEqualTo(application); @@ -262,7 +288,7 @@ public void getApplication_should_throw_RetrieveException_when_applicationServic given(applicationService.getApplication(APPLICATION_ID)).willThrow(new SBonitaReadException("")); //when - delegate.getApplication(APPLICATION_ID); + delegate.getIApplication(APPLICATION_ID); //then exception } @@ -274,7 +300,7 @@ public void getApplication_should_throw_ApplicationNotFoundException_when_applic given(applicationService.getApplication(APPLICATION_ID)).willThrow(new SObjectNotFoundException()); //when - delegate.getApplication(APPLICATION_ID); + delegate.getIApplication(APPLICATION_ID); //then exception } @@ -288,7 +314,7 @@ public void getApplicationByToken_should_return_the_application_returned_by_appl given(converter.toApplication(sApp)).willReturn(application); //when - final Application retriedApp = delegate.getApplicationByToken(APP_TOKEN); + final IApplication retriedApp = delegate.getIApplicationByToken(APP_TOKEN); //then assertThat(retriedApp).isEqualTo(application); @@ -302,7 +328,7 @@ public void getApplicationByToken_should_throw_RetrieveException_when_applicatio given(applicationService.getApplicationByToken(APP_TOKEN)).willThrow(new SBonitaReadException("")); //when - delegate.getApplicationByToken(APP_TOKEN); + delegate.getIApplicationByToken(APP_TOKEN); //then exception } @@ -314,7 +340,7 @@ public void getApplicationByToken_should_throw_ApplicationNotFoundException_when given(applicationService.getApplicationByToken(APP_TOKEN)).willReturn(null); //when - delegate.getApplicationByToken(APP_TOKEN); + delegate.getIApplicationByToken(APP_TOKEN); //then exception } @@ -339,6 +365,43 @@ public void updateApplication_should_return_result_of_applicationservice_updateA assertThat(updatedApplication).isEqualTo(application); } + @Test + public void updateApplicationLink_should_return_result_of_applicationservice_updateApplication() throws Exception { + //given + final SApplicationWithIcon sApplicationWithIcon = mock(SApplicationWithIcon.class); + final ApplicationLink applicationLink = mock(ApplicationLink.class); + final ApplicationLinkUpdater updater = new ApplicationLinkUpdater(); + updater.setToken("newToken"); + final EntityUpdateDescriptor updateDescriptor = new EntityUpdateDescriptor(); + given(converter.toApplicationUpdateDescriptor(updater, LOGGED_USER_ID)).willReturn(updateDescriptor); + given(applicationService.updateApplication(APPLICATION_ID, updateDescriptor)) + .willReturn(sApplicationWithIcon); + given(converter.toApplication(sApplicationWithIcon)).willReturn(applicationLink); + + //when + final ApplicationLink updatedApplication = delegate.updateApplicationLink(APPLICATION_ID, updater); + + //then + assertThat(updatedApplication).isEqualTo(applicationLink); + } + + @Test + public void updateApplicationLink_should_not_return_when_using_ApplicationUpdater() throws Exception { + //given + final SApplicationWithIcon sApplicationWithIcon = mock(SApplicationWithIcon.class); + final ApplicationLink applicationLink = mock(ApplicationLink.class); + final ApplicationUpdater updater = new ApplicationUpdater(); + updater.setToken("newToken"); + final EntityUpdateDescriptor updateDescriptor = new EntityUpdateDescriptor(); + given(converter.toApplicationUpdateDescriptor(updater, LOGGED_USER_ID)).willReturn(updateDescriptor); + given(applicationService.updateApplication(APPLICATION_ID, updateDescriptor)) + .willReturn(sApplicationWithIcon); + given(converter.toApplication(sApplicationWithIcon)).willReturn(applicationLink); + + //when/ then + assertThrows(UpdateException.class, () -> delegate.updateApplication(APPLICATION_ID, updater)); + } + @Test public void updateApplication_should_return_result_of_applicationservice_getApplication_when_updater_is_empty() throws Exception { @@ -457,7 +520,7 @@ public void searchApplications_should_return_the_result_of_searchApplications_ge given(searchApplications.getResult()).willReturn(appSearchResult); //when - final SearchResult retrievedSearchResult = delegate.searchApplications(searchApplications); + final SearchResult retrievedSearchResult = delegate.searchIApplications(searchApplications); //then assertThat(retrievedSearchResult).isEqualTo(appSearchResult); @@ -471,7 +534,7 @@ public void searchApplications_should_throw_SearchException_when_searchApplicati doThrow(new SBonitaReadException("")).when(searchApplications).execute(); //when - delegate.searchApplications(searchApplications); + delegate.searchIApplications(searchApplications); //then exception } diff --git a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/platform/PlatformInformationAPIImplTest.java b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/platform/PlatformInformationAPIImplTest.java new file mode 100644 index 00000000000..d5e7322c5e1 --- /dev/null +++ b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/platform/PlatformInformationAPIImplTest.java @@ -0,0 +1,54 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.engine.api.impl.platform; + +import static java.lang.String.valueOf; +import static org.assertj.core.api.Assertions.assertThat; +import static org.bonitasoft.engine.execution.ProcessStarterVerifierImpl.LIMIT; +import static org.mockito.Mockito.doReturn; + +import java.util.Map; + +import org.bonitasoft.engine.execution.ProcessStarterVerifier; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class PlatformInformationAPIImplTest { + + @Mock + private ProcessStarterVerifier processStarterVerifier; + + @InjectMocks + private PlatformInformationAPIImpl platformInformationAPI; + + @Test + void platformInformationAPI_should_return_case_counters_info() { + //given + doReturn(120L).when(processStarterVerifier).getCurrentNumberOfStartedProcessInstances(); + + //when + final Map platformInformation = platformInformationAPI.getPlatformInformation(); + + //then + assertThat(platformInformation).containsAllEntriesOf(Map.of( + "edition", "Community", + "caseCounter", "120", + "caseCounterLimit", valueOf(LIMIT), + "enablePromotionMessages", "true")); + } +} diff --git a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/transaction/application/SearchApplicationsOfUsersTest.java b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/transaction/application/SearchApplicationsOfUsersTest.java index afdf5e2e299..b8eabe22cf5 100644 --- a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/transaction/application/SearchApplicationsOfUsersTest.java +++ b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/transaction/application/SearchApplicationsOfUsersTest.java @@ -24,6 +24,7 @@ import org.bonitasoft.engine.api.impl.converter.ApplicationModelConverter; import org.bonitasoft.engine.business.application.Application; import org.bonitasoft.engine.business.application.ApplicationService; +import org.bonitasoft.engine.business.application.IApplication; import org.bonitasoft.engine.business.application.model.SApplication; import org.bonitasoft.engine.persistence.QueryOptions; import org.bonitasoft.engine.persistence.SBonitaReadException; @@ -56,12 +57,12 @@ public class SearchApplicationsOfUsersTest { @Mock private ApplicationModelConverter convertor; - private SearchApplicationsOfUser searchApplicationsOfUser; + private SearchApplicationsOfUser searchApplicationsOfUser; @Before public void before() { - searchApplicationsOfUser = new SearchApplicationsOfUser(userId, applicationService, descriptor, options, - convertor); + searchApplicationsOfUser = SearchApplicationsOfUser.defaultSearchApplicationsOfUser(userId, applicationService, + descriptor, options, convertor); } @Test @@ -115,7 +116,7 @@ public void convetToClientObjects_should_return_result_of_convertor_toApplicatio given(convertor.toApplication(sApplications)).willReturn(Arrays.asList(app)); //when - final List applications = searchApplicationsOfUser.convertToClientObjects(sApplications); + final List applications = searchApplicationsOfUser.convertToClientObjects(sApplications); //then assertThat(applications).containsExactly(app); diff --git a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/transaction/application/SearchApplicationsTest.java b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/transaction/application/SearchApplicationsTest.java index 0f2d68867a0..c263f7ddc56 100755 --- a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/transaction/application/SearchApplicationsTest.java +++ b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/api/impl/transaction/application/SearchApplicationsTest.java @@ -24,14 +24,15 @@ import org.bonitasoft.engine.api.impl.converter.ApplicationModelConverter; import org.bonitasoft.engine.business.application.Application; import org.bonitasoft.engine.business.application.ApplicationService; +import org.bonitasoft.engine.business.application.IApplication; import org.bonitasoft.engine.business.application.model.SApplication; import org.bonitasoft.engine.persistence.QueryOptions; import org.bonitasoft.engine.persistence.SBonitaReadException; import org.bonitasoft.engine.search.SearchOptions; import org.bonitasoft.engine.search.descriptor.SearchEntityDescriptor; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -54,8 +55,13 @@ public class SearchApplicationsTest { @Mock private ApplicationModelConverter convertor; - @InjectMocks - private SearchApplications searchApplications; + private SearchApplications searchApplications; + + @Before + public void initSearchApplications() { + searchApplications = SearchApplications.defaultSearchApplications(applicationService, descriptor, options, + convertor); + } @Test public void executeCount_should_return_result_of_applicationService_getNumberOfApplications() throws Exception { @@ -107,7 +113,7 @@ public void convetToClientObjects_should_return_result_of_convertor_toApplicatio given(convertor.toApplication(sApplications)).willReturn(Arrays.asList(app)); //when - final List applications = searchApplications.convertToClientObjects(sApplications); + final List applications = searchApplications.convertToClientObjects(sApplications); //then assertThat(applications).containsExactly(app); diff --git a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/business/application/converter/ApplicationToNodeConverterTest.java b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/business/application/converter/ApplicationToNodeConverterTest.java index c05d9a4111a..94c7861ba07 100644 --- a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/business/application/converter/ApplicationToNodeConverterTest.java +++ b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/business/application/converter/ApplicationToNodeConverterTest.java @@ -29,6 +29,8 @@ import org.bonitasoft.engine.business.application.ApplicationService; import org.bonitasoft.engine.business.application.model.SApplication; import org.bonitasoft.engine.business.application.model.SApplicationPage; +import org.bonitasoft.engine.business.application.xml.AbstractApplicationNode; +import org.bonitasoft.engine.business.application.xml.ApplicationLinkNode; import org.bonitasoft.engine.business.application.xml.ApplicationMenuNode; import org.bonitasoft.engine.business.application.xml.ApplicationNode; import org.bonitasoft.engine.business.application.xml.ApplicationPageNode; @@ -68,6 +70,22 @@ public class ApplicationToNodeConverterTest { @InjectMocks private ApplicationToNodeConverter converter; + @Test + public void toNode_should_return_application_link() throws Exception { + //given + final SApplication application = new SApplication("app", "my app", "1.0", new Date().getTime(), 10L, + "enabled"); + application.setLink(true); + + //when + final AbstractApplicationNode applicationNode = converter.toNode(application); + + //then + assertThat(applicationNode).isNotNull(); + assertThat(applicationNode).isInstanceOf(ApplicationLinkNode.class); + + } + @Test public void toNode_should_return_convert_all_string_fields() throws Exception { //given @@ -78,7 +96,7 @@ public void toNode_should_return_convert_all_string_fields() throws Exception { application.setIconPath("/icon.jpg"); //when - final ApplicationNode applicationNode = converter.toNode(application); + final ApplicationNode applicationNode = (ApplicationNode) converter.toNode(application); //then assertThat(applicationNode).isNotNull(); @@ -104,7 +122,7 @@ public void toNode_should_replace_profile_id_by_profile_name() throws Exception given(profileService.getProfile(7L)).willReturn(profile); //when - final ApplicationNode applicationNode = converter.toNode(application); + final ApplicationNode applicationNode = (ApplicationNode) converter.toNode(application); //then assertThat(applicationNode).isNotNull(); @@ -136,7 +154,7 @@ public void toNode_should_replaceHomePageId_by_application_page_token() throws E given(applicationService.getApplicationPage(8L)).willReturn(homePage); //when - final ApplicationNode applicationNode = converter.toNode(application); + final ApplicationNode applicationNode = (ApplicationNode) converter.toNode(application); //then assertThat(applicationNode).isNotNull(); @@ -168,7 +186,7 @@ public void toNode_should_replaceLayoutId_by_page_name() throws Exception { given(pageService.getPage(9L)).willReturn(layout); //when - final ApplicationNode applicationNode = converter.toNode(application); + final ApplicationNode applicationNode = (ApplicationNode) converter.toNode(application); //then assertThat(applicationNode).isNotNull(); @@ -186,7 +204,7 @@ public void toNode_should_replaceThemeId_by_page_name() throws Exception { given(pageService.getPage(20L)).willReturn(layout); //when - final ApplicationNode applicationNode = converter.toNode(application); + final ApplicationNode applicationNode = (ApplicationNode) converter.toNode(application); //then assertThat(applicationNode).isNotNull(); @@ -247,7 +265,7 @@ public void toNodeShouldAddConvertedPages() throws Exception { .willReturn(Collections.emptyList()); //when - final ApplicationNode applicationNode = converter.toNode(application); + final ApplicationNode applicationNode = (ApplicationNode) converter.toNode(application); //then assertThat(applicationNode.getApplicationPages().size()).isEqualTo(1); diff --git a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/business/application/converter/NodeToApplicationConverterTest.java b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/business/application/converter/NodeToApplicationConverterTest.java index 4573e7b47c1..6cfe9f75af9 100644 --- a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/business/application/converter/NodeToApplicationConverterTest.java +++ b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/business/application/converter/NodeToApplicationConverterTest.java @@ -14,7 +14,9 @@ package org.bonitasoft.engine.business.application.converter; import static org.assertj.core.api.Assertions.assertThat; -import static org.bonitasoft.engine.business.application.InternalProfiles.*; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.bonitasoft.engine.business.application.InternalProfiles.INTERNAL_PROFILE_ALL; +import static org.bonitasoft.engine.business.application.InternalProfiles.INTERNAL_PROFILE_SUPER_ADMIN; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; @@ -27,18 +29,17 @@ import org.bonitasoft.engine.business.application.importer.ImportResult; import org.bonitasoft.engine.business.application.importer.validator.ApplicationImportValidator; import org.bonitasoft.engine.business.application.model.SApplicationWithIcon; +import org.bonitasoft.engine.business.application.xml.AbstractApplicationNode; +import org.bonitasoft.engine.business.application.xml.ApplicationLinkNode; import org.bonitasoft.engine.business.application.xml.ApplicationNode; import org.bonitasoft.engine.exception.ImportException; import org.bonitasoft.engine.page.PageService; import org.bonitasoft.engine.page.SPage; -import org.bonitasoft.engine.persistence.SBonitaReadException; import org.bonitasoft.engine.profile.ProfileService; import org.bonitasoft.engine.profile.exception.profile.SProfileNotFoundException; import org.bonitasoft.engine.profile.model.SProfile; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; @@ -63,13 +64,10 @@ public class NodeToApplicationConverterTest { public static final long DEFAULT_THEME_ID = 102; - private static String ICON_MIME_TYPE = "iconMimeType"; + private static final String ICON_MIME_TYPE = "iconMimeType"; private static final byte[] ICON_CONTENT = "iconContent".getBytes(StandardCharsets.UTF_8); - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Mock ApplicationImportValidator validator; @@ -85,8 +83,13 @@ public void setUp() throws Exception { given(pageService.getPageByName(ApplicationService.DEFAULT_THEME_NAME)).willReturn(defaultTheme); } + private ImportResult convertToSApplication(final AbstractApplicationNode applicationNode, final long createdBy) + throws Exception { + return converter.toSApplication(applicationNode, null, null, createdBy, true); + } + @Test - public void toSApplication_should_set_internalField_when_applicable() throws ImportException, SBonitaReadException { + public void toSApplication_should_set_internalField_when_applicable() throws Exception { //given final ApplicationNode node1 = new ApplicationNode(); final ApplicationNode node2 = new ApplicationNode(); @@ -95,8 +98,8 @@ public void toSApplication_should_set_internalField_when_applicable() throws Imp long createdBy = 1L; //when - final ImportResult importResult1 = converter.toSApplication(node1, ICON_CONTENT, ICON_MIME_TYPE, createdBy); - final ImportResult importResult2 = converter.toSApplication(node2, ICON_CONTENT, ICON_MIME_TYPE, createdBy); + final ImportResult importResult1 = convertToSApplication(node1, createdBy); + final ImportResult importResult2 = convertToSApplication(node2, createdBy); final SApplicationWithIcon application1 = importResult1.getApplication(); final SApplicationWithIcon application2 = importResult2.getApplication(); @@ -125,10 +128,13 @@ public void toSApplication_should_return_ImportResult_with_no_errors_and_applica final SProfile profile = mock(SProfile.class); given(profile.getId()).willReturn(profileId); given(profileService.getProfileByName("admin")).willReturn(profile); + final long before = System.currentTimeMillis(); //when long createdBy = 1L; - final ImportResult importResult = converter.toSApplication(node, ICON_CONTENT, ICON_MIME_TYPE, createdBy); + boolean editable = false; + final ImportResult importResult = converter.toSApplication(node, ICON_CONTENT, ICON_MIME_TYPE, createdBy, + editable); //then assertThat(importResult).isNotNull(); @@ -146,11 +152,66 @@ public void toSApplication_should_return_ImportResult_with_no_errors_and_applica assertThat(application.getIconContent()).isEqualTo(ICON_CONTENT); assertThat(application.getIconMimeType()).isEqualTo(ICON_MIME_TYPE); assertThat(application.getInternalProfile()).isNull(); + assertThat(application.isEditable()).isEqualTo(editable); + assertThat(application.isLink()).isFalse(); + + // also check auto fields + final long after = System.currentTimeMillis(); + assertThat(application.getUpdatedBy()).isEqualTo(createdBy); + assertThat(application.getCreationDate()).isBetween(before, after); + assertThat(application.getLastUpdateDate()).isEqualTo(application.getCreationDate()); + final ImportStatus importStatus = importResult.getImportStatus(); assertThat(importStatus.getName()).isEqualTo("app"); assertThat(importStatus.getStatus()).isEqualTo(ImportStatus.Status.ADDED); assertThat(importStatus.getErrors()).isEmpty(); + } + + @Test + public void toSApplication_should_return_ImportResult_with_no_errors_and_application_link_with_correct_fields() + throws Exception { + //given + final ApplicationLinkNode node = new ApplicationLinkNode(); + node.setDisplayName("My app"); + node.setDescription("This is my app"); + node.setVersion("1.0"); + node.setToken("app"); + node.setIconPath("/icon.jpg"); + node.setProfile("admin"); + node.setState("ENABLED"); + + long profileId = 8L; + final SProfile profile = mock(SProfile.class); + given(profile.getId()).willReturn(profileId); + given(profileService.getProfileByName("admin")).willReturn(profile); + + //when + long createdBy = 1L; + final ImportResult importResult = convertToSApplication(node, createdBy); + + //then + assertThat(importResult).isNotNull(); + final SApplicationWithIcon application = importResult.getApplication(); + assertThat(application.getDisplayName()).isEqualTo("My app"); + assertThat(application.getDescription()).isEqualTo("This is my app"); + assertThat(application.getHomePageId()).isNull(); + assertThat(application.getVersion()).isEqualTo("1.0"); + assertThat(application.getToken()).isEqualTo("app"); + assertThat(application.getIconPath()).isEqualTo("/icon.jpg"); + assertThat(application.getProfileId()).isEqualTo(profileId); + assertThat(application.getState()).isEqualTo("ENABLED"); + assertThat(application.getCreatedBy()).isEqualTo(createdBy); + assertThat(application.getIconContent()).isNull(); + assertThat(application.getIconMimeType()).isNull(); + assertThat(application.getInternalProfile()).isNull(); + assertThat(application.isEditable()).isTrue(); + assertThat(application.isLink()).isTrue(); + + final ImportStatus importStatus = importResult.getImportStatus(); + assertThat(importStatus.getName()).isEqualTo("app"); + assertThat(importStatus.getStatus()).isEqualTo(ImportStatus.Status.ADDED); + assertThat(importStatus.getErrors()).isEmpty(); } @Test @@ -167,7 +228,7 @@ public void toSApplication_should_use_layout_defined_in_ApplicationNode() throws //when long createdBy = 1L; - final ImportResult importResult = converter.toSApplication(node, createdBy); + final ImportResult importResult = convertToSApplication(node, createdBy); //then assertThat(importResult).isNotNull(); @@ -196,7 +257,7 @@ public void toSApplication_should_use_default_layout_when_layout_is_not_defined_ //when long createdBy = 1L; - final ImportResult importResult = converter.toSApplication(node, createdBy); + final ImportResult importResult = convertToSApplication(node, createdBy); //then assertThat(importResult).isNotNull(); @@ -222,15 +283,10 @@ public void toSApplication_should_throw_importException_when_neither_specified_l given(pageService.getPageByName(notAvailableLayout)).willReturn(null); - //then - expectedException.expect(ImportException.class); - expectedException.expectMessage( - String.format("Unable to import application with token '%s' because the layout '%s' was not found.", - token, notAvailableLayout)); - - //when - converter.toSApplication(node, 1L); - + //when - then exception + assertThatExceptionOfType(ImportException.class).isThrownBy(() -> convertToSApplication(node, 1L)) + .withMessage("Unable to import application with token '%s' because the layout '%s' was not found.", + token, notAvailableLayout); } @Test @@ -247,7 +303,7 @@ public void toSApplication_should_use_theme_defined_in_ApplicationNode() throws //when long createdBy = 1L; - final ImportResult importResult = converter.toSApplication(node, createdBy); + final ImportResult importResult = convertToSApplication(node, createdBy); //then assertThat(importResult).isNotNull(); @@ -269,7 +325,7 @@ public void toSApplication_should_use_default_theme_when_layout_is_not_defined_i node.setToken("app"); long createdBy = 1L; - final ImportResult importResult = converter.toSApplication(node, createdBy); + final ImportResult importResult = convertToSApplication(node, createdBy); //then assertThat(importResult).isNotNull(); @@ -293,15 +349,10 @@ public void toSApplication_should_throw_ImportException_when_neither_specified_t given(pageService.getPageByName("notAvailable")).willReturn(null); - //then - expectedException.expect(ImportException.class); - expectedException.expectMessage( - String.format("Unable to import application with token '%s' because the theme '%s' was not found.", - "app", "notAvailable", ApplicationService.DEFAULT_THEME_NAME)); - - //when - converter.toSApplication(node, 1L); - + //when - then exception + assertThatExceptionOfType(ImportException.class).isThrownBy(() -> convertToSApplication(node, 1L)) + .withMessage("Unable to import application with token '%s' because the theme '%s' was not found.", + "app", "notAvailable"); } @Test @@ -313,7 +364,7 @@ public void toSApplication_should_return_application_with_null_profile_id_when_n node.setToken("TokenName"); // token can never be null in the XML //when - final ImportResult importResult = converter.toSApplication(node, 1L); + final ImportResult importResult = convertToSApplication(node, 1L); //then assertThat(importResult).isNotNull(); @@ -332,7 +383,7 @@ public void toSApplication_should_return_Import_result_with_errors_when_profile_ given(profileService.getProfileByName("admin")).willThrow(new SProfileNotFoundException("")); //when - final ImportResult importResult = converter.toSApplication(node, 1L); + final ImportResult importResult = convertToSApplication(node, 1L); //then assertThat(importResult.getApplication().getProfileId()).isNull(); @@ -343,30 +394,29 @@ public void toSApplication_should_return_Import_result_with_errors_when_profile_ assertThat(importStatus.getErrors()).containsExactly(new ImportError("admin", ImportError.Type.PROFILE)); } - @Test(expected = ImportException.class) + @Test public void toSApplication_should_throw_ImportException_when_layout_is_not_found() throws Exception { //given final ApplicationNode node = buildApplicationNode("app", "1.0"); given(pageService.getPageByName(ApplicationService.DEFAULT_LAYOUT_NAME)).willReturn(null); - //when - converter.toSApplication(node, 1L); - - //then exception + //when - then exception + assertThatExceptionOfType(ImportException.class).isThrownBy(() -> convertToSApplication(node, 1L)) + .withMessage("Unable to import application with token '%s' because the layout '%s' was not found.", + "app", ApplicationService.DEFAULT_LAYOUT_NAME); } - @Test(expected = ImportException.class) + @Test public void toSApplication_should_throw_ImportException_when_theme_is_not_found() throws Exception { //given final ApplicationNode node = buildApplicationNode("app", "1.0"); given(pageService.getPageByName(ApplicationService.DEFAULT_THEME_NAME)).willReturn(null); - //when - converter.toSApplication(node, 1L); - - //then exception + assertThatExceptionOfType(ImportException.class).isThrownBy(() -> convertToSApplication(node, 1L)) + .withMessage("Unable to import application with token '%s' because the theme '%s' was not found.", + "app", ApplicationService.DEFAULT_THEME_NAME); } private ApplicationNode buildApplicationNode(final String token, final String version) { @@ -383,13 +433,9 @@ public void toSApplication_should_throw_ImportException_when_application_token_i doThrow(new ImportException("invalid token")).when(validator).validate("invalid"); ApplicationNode applicationNode = buildApplicationNode("invalid", "1.0"); - //then - expectedException.expect(ImportException.class); - expectedException.expectMessage("invalid token"); - - //when - converter.toSApplication(applicationNode, 1L); - + //when - then exception + assertThatExceptionOfType(ImportException.class).isThrownBy(() -> convertToSApplication(applicationNode, 1L)) + .withMessage("invalid token"); } } diff --git a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/business/application/exporter/ApplicationContainerExporterTest.java b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/business/application/exporter/ApplicationContainerExporterTest.java index 4a471a65fdb..f7f73450253 100755 --- a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/business/application/exporter/ApplicationContainerExporterTest.java +++ b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/business/application/exporter/ApplicationContainerExporterTest.java @@ -29,6 +29,6 @@ public void exportApplications_should_call_marshall() throws Exception { //then assertThat(new String(bytes)).isEqualTo("\n" + - "\n"); + "\n"); } } diff --git a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/business/application/importer/ApplicationImporterTest.java b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/business/application/importer/ApplicationImporterTest.java index 768a3af6d5a..f04ae361732 100755 --- a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/business/application/importer/ApplicationImporterTest.java +++ b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/business/application/importer/ApplicationImporterTest.java @@ -14,6 +14,7 @@ package org.bonitasoft.engine.business.application.importer; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; @@ -31,6 +32,7 @@ import org.bonitasoft.engine.business.application.model.SApplication; import org.bonitasoft.engine.business.application.model.SApplicationPage; import org.bonitasoft.engine.business.application.model.SApplicationWithIcon; +import org.bonitasoft.engine.business.application.xml.ApplicationLinkNode; import org.bonitasoft.engine.business.application.xml.ApplicationMenuNode; import org.bonitasoft.engine.business.application.xml.ApplicationNode; import org.bonitasoft.engine.business.application.xml.ApplicationNodeBuilder; @@ -40,6 +42,7 @@ import org.bonitasoft.engine.exception.AlreadyExistsException; import org.bonitasoft.engine.exception.ImportException; import org.bonitasoft.engine.recorder.model.EntityUpdateDescriptor; +import org.bonitasoft.engine.session.SessionService; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -81,7 +84,8 @@ public void importApplication_should_create_application_import_pages_and_menus_a throws Exception { //given long createdBy = 5L; - SApplicationWithIcon app = new SApplicationWithIcon("app", "app", "1.0", 1L, createdBy, "state", true); + boolean editable = false; + SApplicationWithIcon app = new SApplicationWithIcon("app", "app", "1.0", 1L, createdBy, "state", editable); app.setId(1); given(importResult.getApplication()).willReturn(app); given(importResult.getImportStatus()).willReturn(new ImportStatus(app.getToken())); @@ -100,8 +104,9 @@ public void importApplication_should_create_application_import_pages_and_menus_a applicationNode.setHomePage(homePage.getToken()); applicationNode.setToken("app"); - given(nodeToApplicationConverter.toSApplication(applicationNode, ICON_CONTENT, ICON_MIME_TYPE, createdBy)) - .willReturn(importResult); + given(nodeToApplicationConverter.toSApplication(applicationNode, ICON_CONTENT, ICON_MIME_TYPE, createdBy, + editable)) + .willReturn(importResult); long homePageId = 222L; SApplicationPage applicationPage = new SApplicationPage(app.getId(), homePageId, "home"); @@ -121,15 +126,14 @@ public void importApplication_should_create_application_import_pages_and_menus_a given(applicationService.createApplication(app)).willReturn(app); //when - ImportStatus retrievedStatus = applicationImporter.importApplication(applicationNode, false, createdBy, - ICON_CONTENT, - ICON_MIME_TYPE, true, strategy); + ImportStatus retrievedStatus = applicationImporter.importApplication(applicationNode, editable, createdBy, + ICON_CONTENT, ICON_MIME_TYPE, true, strategy); //then //create application assertThat(retrievedStatus.getStatus()).isEqualTo(ImportStatus.Status.ADDED); - verify(applicationService, times(1)).createApplication(app); - assertThat(app.isEditable()).isEqualTo(false); + verify(applicationService).createApplication(app); + assertThat(app.isEditable()).isFalse(); verifyNoInteractions(strategy); //add pages @@ -141,7 +145,6 @@ public void importApplication_should_create_application_import_pages_and_menus_a //set home page verify(applicationService).updateApplication(eq(app), argThat(desc -> desc.getFields().get(AbstractSApplication.HOME_PAGE_ID).equals(homePageId))); - } @Test @@ -149,7 +152,8 @@ public void importApplication_should_not_create_application_when_no_application_ throws Exception { //given long createdBy = 5L; - SApplicationWithIcon app = new SApplicationWithIcon("app", "app", "1.0", 1L, createdBy, "state", true); + boolean editable = false; + SApplicationWithIcon app = new SApplicationWithIcon("app", "app", "1.0", 1L, createdBy, "state", editable); app.setId(1); given(importResult.getApplication()).willReturn(app); given(importResult.getImportStatus()).willReturn(new ImportStatus(app.getToken())); @@ -168,21 +172,21 @@ public void importApplication_should_not_create_application_when_no_application_ applicationNode.setHomePage(homePage.getToken()); applicationNode.setToken("app"); - given(nodeToApplicationConverter.toSApplication(applicationNode, ICON_CONTENT, ICON_MIME_TYPE, createdBy)) - .willReturn(importResult); + given(nodeToApplicationConverter.toSApplication(applicationNode, ICON_CONTENT, ICON_MIME_TYPE, createdBy, + editable)) + .willReturn(importResult); long homePageId = 222L; //when - ImportStatus retrievedStatus = applicationImporter.importApplication(applicationNode, false, createdBy, - ICON_CONTENT, - ICON_MIME_TYPE, false, strategy); + ImportStatus retrievedStatus = applicationImporter.importApplication(applicationNode, editable, createdBy, + ICON_CONTENT, ICON_MIME_TYPE, false, strategy); //then //create application assertThat(retrievedStatus.getStatus()).isEqualTo(ImportStatus.Status.SKIPPED); verify(applicationService, never()).createApplication(app); - assertThat(app.isEditable()).isEqualTo(false); + assertThat(app.isEditable()).isFalse(); verifyNoInteractions(strategy); //add pages @@ -193,13 +197,13 @@ public void importApplication_should_not_create_application_when_no_application_ //set home page verify(applicationService, never()).updateApplication(eq(app), argThat(desc -> desc.getFields().get(AbstractSApplication.HOME_PAGE_ID).equals(homePageId))); - } @Test public void importApplication_should_not_add_error_when_error_already_exists() throws Exception { //given long createdBy = 5L; + boolean editable = true; SApplicationWithIcon app = mock(SApplicationWithIcon.class); ImportResult importResult = mock(ImportResult.class); @@ -214,20 +218,19 @@ public void importApplication_should_not_add_error_when_error_already_exists() t ApplicationNode applicationNode = new ApplicationNode(); applicationNode.addApplicationPage(pageNode1); - given(nodeToApplicationConverter.toSApplication(applicationNode, ICON_CONTENT, ICON_MIME_TYPE, createdBy)) - .willReturn(importResult); + given(nodeToApplicationConverter.toSApplication(applicationNode, ICON_CONTENT, ICON_MIME_TYPE, createdBy, + editable)) + .willReturn(importResult); given(applicationService.createApplication(app)).willReturn(app); //when - ImportStatus retrievedStatus = applicationImporter.importApplication(applicationNode, true, createdBy, - ICON_CONTENT, - ICON_MIME_TYPE, true, strategy); + ImportStatus retrievedStatus = applicationImporter.importApplication(applicationNode, editable, createdBy, + ICON_CONTENT, ICON_MIME_TYPE, true, strategy); //then assertThat(retrievedStatus).isEqualTo(importResult.getImportStatus()); assertThat(retrievedStatus.getErrors()).containsExactly(errorPage); - } @Test @@ -235,6 +238,7 @@ public void importApplication_should_not_set_home_page_when_applicationNode_does throws Exception { //given long createdBy = 5L; + boolean editable = true; SApplicationWithIcon app = mock(SApplicationWithIcon.class); ImportResult importResult = mock(ImportResult.class); @@ -244,12 +248,13 @@ public void importApplication_should_not_set_home_page_when_applicationNode_does ApplicationNode applicationNode = new ApplicationNode(); applicationNode.setToken("app"); - given(nodeToApplicationConverter.toSApplication(applicationNode, ICON_CONTENT, ICON_MIME_TYPE, createdBy)) - .willReturn(importResult); + given(nodeToApplicationConverter.toSApplication(applicationNode, ICON_CONTENT, ICON_MIME_TYPE, createdBy, + editable)) + .willReturn(importResult); given(applicationService.createApplication(app)).willReturn(app); //when - applicationImporter.importApplication(applicationNode, true, createdBy, ICON_CONTENT, + applicationImporter.importApplication(applicationNode, editable, createdBy, ICON_CONTENT, ICON_MIME_TYPE, true, strategy); //then @@ -262,6 +267,7 @@ public void importApplication_should_not_set_home_page_when_applicationNode_does public void importApplication_should_add_error_when_home_page_is_not_found() throws Exception { //given long createdBy = 5L; + boolean editable = true; SApplicationWithIcon app = mock(SApplicationWithIcon.class); ImportResult importResult = mock(ImportResult.class); @@ -273,21 +279,22 @@ public void importApplication_should_add_error_when_home_page_is_not_found() thr applicationNode.setToken("app"); applicationNode.setHomePage("home"); - given(nodeToApplicationConverter.toSApplication(applicationNode, ICON_CONTENT, ICON_MIME_TYPE, createdBy)) - .willReturn(importResult); + given(nodeToApplicationConverter.toSApplication(applicationNode, ICON_CONTENT, ICON_MIME_TYPE, createdBy, + editable)) + .willReturn(importResult); given(applicationService.createApplication(app)).willReturn(app); given(applicationService.getApplicationPage("app", "home")).willThrow(new SObjectNotFoundException("")); //when - applicationImporter.importApplication(applicationNode, true, createdBy, ICON_CONTENT, + applicationImporter.importApplication(applicationNode, editable, createdBy, ICON_CONTENT, ICON_MIME_TYPE, true, strategy); //then //set home page verify(applicationService, never()).updateApplication(any(SApplicationWithIcon.class), any(EntityUpdateDescriptor.class)); - verify(importStatus, times(1)) + verify(importStatus) .addErrorsIfNotExists(List.of(new ImportError("home", ImportError.Type.APPLICATION_PAGE))); } @@ -295,6 +302,7 @@ public void importApplication_should_add_error_when_home_page_is_not_found() thr public void importApplication_should_skip_when_strategy_return_skip() throws Exception { //given long createdBy = 5L; + boolean editable = true; SApplicationWithIcon appToBeImported = mock(SApplicationWithIcon.class); given(appToBeImported.getToken()).willReturn("application"); @@ -303,12 +311,13 @@ public void importApplication_should_skip_when_strategy_return_skip() throws Exc SApplication appInConflict = mock(SApplication.class); ApplicationNode applicationNode = mock(ApplicationNode.class); - given(nodeToApplicationConverter.toSApplication(applicationNode, ICON_CONTENT, ICON_MIME_TYPE, createdBy)) - .willReturn(importResult); + given(nodeToApplicationConverter.toSApplication(applicationNode, ICON_CONTENT, ICON_MIME_TYPE, createdBy, + editable)) + .willReturn(importResult); given(applicationService.getApplicationByToken("application")).willReturn(appInConflict); given(strategy.whenApplicationExists(any(), any())).willReturn(ApplicationImportStrategy.ImportStrategy.SKIP); //when - ImportStatus importStatus = applicationImporter.importApplication(applicationNode, true, createdBy, + ImportStatus importStatus = applicationImporter.importApplication(applicationNode, editable, createdBy, ICON_CONTENT, ICON_MIME_TYPE, true, strategy); //then @@ -321,6 +330,7 @@ public void importApplication_should_skip_when_strategy_return_skip() throws Exc public void importApplication_replace_application_when_strategy_is_replace_duplicate() throws Exception { //given long createdBy = 5L; + boolean editable = true; SApplicationWithIcon appToBeImported = mock(SApplicationWithIcon.class); given(appToBeImported.getToken()).willReturn("application"); @@ -329,28 +339,30 @@ public void importApplication_replace_application_when_strategy_is_replace_dupli SApplication appInConflict = mock(SApplication.class); ApplicationNode applicationNode = mock(ApplicationNode.class); - given(nodeToApplicationConverter.toSApplication(applicationNode, ICON_CONTENT, ICON_MIME_TYPE, createdBy)) - .willReturn(importResult); + given(nodeToApplicationConverter.toSApplication(applicationNode, ICON_CONTENT, ICON_MIME_TYPE, createdBy, + editable)) + .willReturn(importResult); given(applicationService.getApplicationByToken("application")).willReturn(appInConflict); //when - ImportStatus importStatus = applicationImporter.importApplication(applicationNode, true, createdBy, + ImportStatus importStatus = applicationImporter.importApplication(applicationNode, editable, createdBy, ICON_CONTENT, ICON_MIME_TYPE, true, new ReplaceDuplicateApplicationImportStrategy()); //then - verify(applicationService, times(1)).forceDeleteApplication(appInConflict); - verify(applicationService, times(1)).createApplication(appToBeImported); - verify(applicationService, times(1)).createApplication(appToBeImported); - verify(applicationService, times(1)).createApplication(appToBeImported); + verify(applicationService).forceDeleteApplication(appInConflict); + verify(applicationService).createApplication(appToBeImported); + verify(applicationService).createApplication(appToBeImported); + verify(applicationService).createApplication(appToBeImported); assertThat(importStatus.getStatus()).isEqualTo(ImportStatus.Status.REPLACED); } - @Test(expected = AlreadyExistsException.class) + @Test public void importApplication_should_throw_alreadyExistsException_when_strategy_FailOnDuplicateApplicationImportStrategy() throws Exception { //given long createdBy = 5L; + boolean editable = true; SApplicationWithIcon appToBeImported = mock(SApplicationWithIcon.class); given(appToBeImported.getToken()).willReturn("application"); @@ -362,18 +374,19 @@ public void importApplication_should_throw_alreadyExistsException_when_strategy_ SApplication appInConflict = mock(SApplication.class); ApplicationNode applicationNode = mock(ApplicationNode.class); - given(nodeToApplicationConverter.toSApplication(applicationNode, ICON_CONTENT, ICON_MIME_TYPE, createdBy)) - .willReturn(importResult); + given(nodeToApplicationConverter.toSApplication(applicationNode, ICON_CONTENT, ICON_MIME_TYPE, createdBy, + editable)) + .willReturn(importResult); given(applicationService.getApplicationByToken("application")).willReturn(appInConflict); - //when - applicationImporter.importApplication(applicationNode, true, createdBy, ICON_CONTENT, ICON_MIME_TYPE, - true, new FailOnDuplicateApplicationImportStrategy()); - - //then exception + //when - then exception + assertThatExceptionOfType(AlreadyExistsException.class) + .isThrownBy(() -> applicationImporter + .importApplication(applicationNode, editable, createdBy, ICON_CONTENT, ICON_MIME_TYPE, true, + new FailOnDuplicateApplicationImportStrategy())); } - @Test(expected = ImportException.class) + @Test public void importApplication_should_throw_ExecutionException_when_application_service_throws_exception() throws Exception { //given @@ -384,19 +397,58 @@ public void importApplication_should_throw_ExecutionException_when_application_s given(importResult.getImportStatus()).willReturn(importStatus); long createdBy = 5L; + boolean editable = true; given(importResult.getApplication()).willReturn(app1); ApplicationNode applicationNode = mock(ApplicationNode.class); - given(nodeToApplicationConverter.toSApplication(applicationNode, ICON_CONTENT, ICON_MIME_TYPE, createdBy)) - .willReturn(importResult); + given(nodeToApplicationConverter.toSApplication(applicationNode, ICON_CONTENT, ICON_MIME_TYPE, createdBy, + editable)) + .willReturn(importResult); given(applicationService.createApplication(app1)).willThrow(new SObjectCreationException("")); + //when - then exception + assertThatExceptionOfType(ImportException.class).isThrownBy(() -> applicationImporter + .importApplication(applicationNode, editable, createdBy, ICON_CONTENT, ICON_MIME_TYPE, true, strategy)); + } + + @Test + public void importApplicationLink_should_create_application_link_with_no_menus_and_no_pages_and_no_home_page() + throws Exception { + //given + long createdBy = SessionService.SYSTEM_ID; + boolean editable = true; + SApplicationWithIcon app = new SApplicationWithIcon("app", "app", "1.0", 1L, createdBy, "state", editable); + app.setId(1); + app.setLink(true); + given(importResult.getApplication()).willReturn(app); + given(importResult.getImportStatus()).willReturn(new ImportStatus(app.getToken())); + + ApplicationLinkNode applicationLinkNode = new ApplicationLinkNode(); + applicationLinkNode.setToken("app"); + + given(nodeToApplicationConverter.toSApplication(applicationLinkNode, null, null, createdBy, editable)) + .willReturn(importResult); + + given(applicationService.createApplication(app)).willReturn(app); + //when - applicationImporter.importApplication(applicationNode, true, createdBy, ICON_CONTENT, ICON_MIME_TYPE, true, - strategy); + ImportStatus retrievedStatus = applicationImporter.importApplication(applicationLinkNode, editable, + createdBy, null, null, true, strategy); + + //then + //create application + assertThat(retrievedStatus.getStatus()).isEqualTo(ImportStatus.Status.ADDED); + assertThat(retrievedStatus.getErrors()).isEmpty(); + verify(applicationService).createApplication(app); + verifyNoInteractions(strategy); - //then exception + //no pages added + verify(applicationPageImporter, never()).importApplicationPages(any(), any()); + //no menus added + verify(applicationMenuImporter, never()).importApplicationMenus(any(), any()); + //no home page set + verify(applicationService, never()).updateApplication(any(), any()); } } diff --git a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/execution/ProcessExecutorImplTest.java b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/execution/ProcessExecutorImplTest.java index 79b34881098..d9558018918 100644 --- a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/execution/ProcessExecutorImplTest.java +++ b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/execution/ProcessExecutorImplTest.java @@ -173,6 +173,9 @@ public class ProcessExecutorImplTest { @Mock private SFlowElementContainerDefinition processContainer; + @Mock + private ProcessStarterVerifier processStarterVerifier; + @InjectMocks private ProcessExecutorImpl processExecutorImpl; @@ -244,6 +247,7 @@ public void startProcessWithOperationsAndContext() throws Exception { when(mockedProcessExecutorImpl.createProcessInstance(sProcessDefinition, starterId, starterSubstituteId, -1)) .thenReturn(sProcessInstance); when(mockedProcessExecutorImpl.startElements(eq(sProcessInstance), eq(selector))).thenReturn(sProcessInstance); + doNothing().when(processStarterVerifier).verify(sProcessInstance); // Let's call it for real: doCallRealMethod().when(mockedProcessExecutorImpl).start(starterId, starterSubstituteId, operations, context, @@ -284,8 +288,8 @@ public void startProcessWithOperationsAndContextAndExpressionContextAndConnector final SProcessDefinitionDeployInfo sProcessDefinitionDeployInfo = mock(SProcessDefinitionDeployInfo.class); when(mockedProcessExecutorImpl.startElements(sProcessInstance, selector)).thenReturn(sProcessInstance); when(mockedProcessExecutorImpl.createProcessInstance(sProcessDefinition, starterId, starterSubstituteId, - subProcessDefinitionId)).thenReturn( - sProcessInstance); + subProcessDefinitionId)).thenReturn(sProcessInstance); + doNothing().when(processStarterVerifier).verify(sProcessInstance); final Map processInputs = new HashMap<>(0); @@ -334,8 +338,8 @@ public void startProcessWithOperationsAndContextAndExpressionContextAndConnector doReturn(sProcessDefinitionDeployInfo).when(processDefinitionService).getProcessDeploymentInfo(anyLong()); when(mockedProcessExecutorImpl.startElements(eq(sProcessInstance), eq(selector))).thenReturn(sProcessInstance); when(mockedProcessExecutorImpl.createProcessInstance(sProcessDefinition, starterId, starterSubstituteId, 1L)) - .thenReturn( - sProcessInstance); + .thenReturn(sProcessInstance); + doNothing().when(processStarterVerifier).verify(sProcessInstance); final Map processInputs = new HashMap<>(0); doNothing().when(mockedProcessExecutorImpl).validateContractInputs(processInputs, sProcessDefinition); diff --git a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/execution/ProcessStarterVerifierImplTest.java b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/execution/ProcessStarterVerifierImplTest.java new file mode 100644 index 00000000000..c6593c1c023 --- /dev/null +++ b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/execution/ProcessStarterVerifierImplTest.java @@ -0,0 +1,237 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.engine.execution; + +import static com.github.stefanbirkner.systemlambda.SystemLambda.tapSystemOut; +import static java.lang.System.currentTimeMillis; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.bonitasoft.engine.execution.ProcessStarterVerifierImpl.LIMIT; +import static org.bonitasoft.engine.execution.ProcessStarterVerifierImpl.PERIOD_IN_MILLIS; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.bonitasoft.engine.core.process.instance.api.ProcessInstanceService; +import org.bonitasoft.engine.core.process.instance.api.exceptions.SProcessInstanceCreationException; +import org.bonitasoft.engine.core.process.instance.model.SProcessInstance; +import org.bonitasoft.engine.platform.PlatformRetriever; +import org.bonitasoft.engine.platform.model.SPlatform; +import org.bonitasoft.engine.service.platform.PlatformInformationService; +import org.bonitasoft.engine.transaction.TransactionService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class ProcessStarterVerifierImplTest { + + @Mock + private PlatformRetriever platformRetriever; + @Mock + private PlatformInformationService platformInformationService; + @Mock + private TransactionService transactionService; + @Mock + private ProcessInstanceService processInstanceService; + + private ProcessStarterVerifierImpl processStarterVerifier; + + @BeforeEach + public void initMocks() throws Exception { + doReturn(new ArrayList<>()).when(transactionService).executeInTransaction(any()); + processStarterVerifier = spy(new ProcessStarterVerifierImpl(platformRetriever, platformInformationService, + transactionService, processInstanceService)); + } + + @Test + void should_be_able_to_decrypt_encrypted_value() throws Exception { + //given + final long currentTime = currentTimeMillis(); + final var originalValue = List.of(currentTime, currentTime + 1000L, currentTime + 2000L); + + //when + final List computedValue = processStarterVerifier + .decryptDataFromDatabase(processStarterVerifier.encryptDataBeforeSendingToDatabase(originalValue)); + + //then + assertThat(computedValue).isEqualTo(originalValue); + } + + @Test + void verify_should_not_remove_still_valid_values_from_counters() throws Exception { + //given + final long validTimestamp = currentTimeMillis() - PERIOD_IN_MILLIS + 86400000L; // plus 1 day + processStarterVerifier.addCounter(validTimestamp); + doNothing().when(processStarterVerifier).storeNewValueInDatabase(anyString()); + + //when + processStarterVerifier.verify(new SProcessInstance()); + + //then + assertThat(processStarterVerifier.getCounters()).size().isEqualTo(2); + assertThat(processStarterVerifier.getCounters()).contains(validTimestamp); + } + + @Test + void verify_should_remove_old_values_from_counters() throws Exception { + //given + final long obsoleteValue = currentTimeMillis() - PERIOD_IN_MILLIS - 86400000L; // minus 1 day + processStarterVerifier.addCounter(obsoleteValue); + doNothing().when(processStarterVerifier).storeNewValueInDatabase(anyString()); + + //when + processStarterVerifier.verify(new SProcessInstance()); + + //then + assertThat(processStarterVerifier.getCounters()).size().isEqualTo(1); + assertThat(processStarterVerifier.getCounters()).doesNotContain(obsoleteValue); + } + + @Test + void verify_should_throw_exception_if_limit_is_reached() throws Exception { + //given + for (int i = 0; i < LIMIT; i++) { + processStarterVerifier.addCounter(currentTimeMillis()); + } + final SProcessInstance processInstance = mock(SProcessInstance.class); + doReturn(currentTimeMillis() + 1000L).when(processInstance).getStartDate(); + + //when - then + assertThatExceptionOfType(SProcessInstanceCreationException.class) + .isThrownBy(() -> processStarterVerifier.verify(processInstance)) + .withMessageContaining("Process start limit"); + assertThat(processStarterVerifier.getCounters()).size().isEqualTo(LIMIT); + verify(processStarterVerifier, never()).storeNewValueInDatabase(anyString()); + } + + @Test + void should_log_when_80_percent_is_reached() throws Exception { + var counters = mock(List.class); + doReturn(LIMIT * 80 / 100).when(counters).size(); + doReturn(counters).when(processStarterVerifier).getCounters(); + + // when + final String log = tapSystemOut(() -> processStarterVerifier.logCaseLimitProgressIfThresholdReached()); + + // then + assertThat(log).containsPattern("WARN.*80%"); + } + + @Test + void should_log_when_90_percent_is_reached() throws Exception { + var counters = mock(List.class); + doReturn(LIMIT * 90 / 100).when(counters).size(); + doReturn(counters).when(processStarterVerifier).getCounters(); + + // when + final String log = tapSystemOut(() -> processStarterVerifier.logCaseLimitProgressIfThresholdReached()); + + // then + assertThat(log) + .containsPattern("WARN.*90%") + .doesNotContain("80%"); + } + + @Test + void should_not_log_when_80_percent_has_already_been_reached() throws Exception { + var counters = mock(List.class); + doReturn(121).when(counters).size(); + doReturn(counters).when(processStarterVerifier).getCounters(); + + // when + final String log = tapSystemOut(() -> processStarterVerifier.logCaseLimitProgressIfThresholdReached()); + + // then + assertThat(log).isBlank(); + } + + @Test + void readCounters_should_fail_if_counters_are_not_set() throws Exception { + // given + final SPlatform platform = new SPlatform(); + platform.setInformation(""); + doReturn(platform).when(platformRetriever).getPlatform(); + + // when - then + assertThatExceptionOfType(IllegalStateException.class) + .isThrownBy(() -> processStarterVerifier.readCounters()); + } + + @Test + void readCounters_should_fail_if_counters_cannot_be_decrypted_from_database() throws Exception { + // given + final SPlatform platform = new SPlatform(); + final String encryptedValue = "encrypted value"; + platform.setInformation(encryptedValue); + doReturn(platform).when(platformRetriever).getPlatform(); + doThrow(new IOException("Cannot decipher information")).when(processStarterVerifier) + .decryptDataFromDatabase(encryptedValue); + + // when - then + assertThatExceptionOfType(IllegalStateException.class) + .isThrownBy(() -> processStarterVerifier.readCounters()); + } + + @Test + void readCounters_should_succeed_if_counters_can_be_decrypted_from_database() throws Exception { + // given + final SPlatform platform = new SPlatform(); + final String encryptedValue = "encrypted value"; + platform.setInformation(encryptedValue); + doReturn(platform).when(platformRetriever).getPlatform(); + final List countersFromDatabase = List.of(currentTimeMillis()); + doReturn(countersFromDatabase).when(processStarterVerifier).decryptDataFromDatabase(encryptedValue); + + // when + final List counters = processStarterVerifier.readCounters(); + + // then + assertThat(counters).isEqualTo(countersFromDatabase); + } + + @Test + void verify_should_pass_if_all_counters_found_in_archives_are_found_in_counters() throws Exception { + // given + final long shouldBeThereTimestamp = currentTimeMillis(); + final long oldestValidDate = 1212000002999L; + doReturn(List.of(shouldBeThereTimestamp)).when(processStarterVerifier) + .fetchLastArchivedProcessInstanceStartDates(oldestValidDate); + + // when - then + assertDoesNotThrow(() -> processStarterVerifier + .verifyCountersCoherence(List.of(shouldBeThereTimestamp, 1111252531354L), oldestValidDate)); + + } + + @Test + void verify_should_fail_if_counters_do_not_contains_data_found_in_archives() throws Exception { + // given + final Long oldestValidDate = currentTimeMillis(); + doReturn(List.of(currentTimeMillis())).when(processStarterVerifier) + .fetchLastArchivedProcessInstanceStartDates(oldestValidDate); + + // when - then + assertThrows(IllegalStateException.class, + () -> processStarterVerifier.verifyCountersCoherence(List.of(), oldestValidDate)); + } + +} diff --git a/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/service/platform/PlatformInformationServiceImplTest.java b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/service/platform/PlatformInformationServiceImplTest.java new file mode 100644 index 00000000000..e54a68d7618 --- /dev/null +++ b/bpm/bonita-core/bonita-process-engine/src/test/java/org/bonitasoft/engine/service/platform/PlatformInformationServiceImplTest.java @@ -0,0 +1,77 @@ +/** + * Copyright (C) 2019 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.engine.service.platform; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import org.bonitasoft.engine.platform.exception.SPlatformUpdateException; +import org.bonitasoft.engine.platform.model.SPlatform; +import org.bonitasoft.engine.services.PersistenceService; +import org.bonitasoft.engine.services.SPersistenceException; +import org.bonitasoft.engine.services.UpdateDescriptor; +import org.hamcrest.core.IsEqual; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class PlatformInformationServiceImplTest { + + @Mock + private PersistenceService persistenceService; + + @InjectMocks + private PlatformInformationServiceImpl platformInformationService; + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Test + public void updatePlatformInfo() throws Exception { + //given + SPlatform platform = mock(SPlatform.class); + + //when + platformInformationService.updatePlatformInfo(platform, "info"); + + //then + ArgumentCaptor upDescCaptor = ArgumentCaptor.forClass(UpdateDescriptor.class); + verify(persistenceService).update(upDescCaptor.capture()); + UpdateDescriptor descriptor = upDescCaptor.getValue(); + assertThat(descriptor.getFields()).containsEntry(SPlatform.INFORMATION, "info"); + assertThat(descriptor.getEntity()).isEqualTo(platform); + } + + @Test + public void updatePlatformInfo_should_throw_exception_when_persistence_service_throws_exception() throws Exception { + //given + SPlatform platform = mock(SPlatform.class); + SPersistenceException toBeThrown = new SPersistenceException("exception"); + doThrow(toBeThrown).when(persistenceService).update(any(UpdateDescriptor.class)); + + //then + expectedException.expect(SPlatformUpdateException.class); + expectedException.expectCause(new IsEqual(toBeThrown)); + + //when + platformInformationService.updatePlatformInfo(platform, "info"); + } +} diff --git a/bpm/bonita-core/bonita-process-engine/src/test/resources/customer-application-v2.zip b/bpm/bonita-core/bonita-process-engine/src/test/resources/customer-application-v2.zip index e1cf1ed2373..c890a23b6f8 100644 Binary files a/bpm/bonita-core/bonita-process-engine/src/test/resources/customer-application-v2.zip and b/bpm/bonita-core/bonita-process-engine/src/test/resources/customer-application-v2.zip differ diff --git a/bpm/bonita-core/bonita-process-engine/src/test/resources/customer-application.zip b/bpm/bonita-core/bonita-process-engine/src/test/resources/customer-application.zip index e33aebf0f79..e0470568ec7 100644 Binary files a/bpm/bonita-core/bonita-process-engine/src/test/resources/customer-application.zip and b/bpm/bonita-core/bonita-process-engine/src/test/resources/customer-application.zip differ diff --git a/bpm/bonita-core/bonita-process-engine/src/test/resources/org/bonitasoft/web/application/app_to_import3.zip b/bpm/bonita-core/bonita-process-engine/src/test/resources/org/bonitasoft/web/application/app_to_import3.zip index ef602d642b4..8b48a743a4f 100644 Binary files a/bpm/bonita-core/bonita-process-engine/src/test/resources/org/bonitasoft/web/application/app_to_import3.zip and b/bpm/bonita-core/bonita-process-engine/src/test/resources/org/bonitasoft/web/application/app_to_import3.zip differ diff --git a/bpm/bonita-core/bonita-process-engine/src/test/resources/org/bonitasoft/web/application/final/app_to_import1.zip b/bpm/bonita-core/bonita-process-engine/src/test/resources/org/bonitasoft/web/application/final/app_to_import1.zip index 15698dec827..3494a43c57a 100644 Binary files a/bpm/bonita-core/bonita-process-engine/src/test/resources/org/bonitasoft/web/application/final/app_to_import1.zip and b/bpm/bonita-core/bonita-process-engine/src/test/resources/org/bonitasoft/web/application/final/app_to_import1.zip differ diff --git a/bpm/bonita-core/bonita-process-engine/src/test/resources/org/bonitasoft/web/application/final/app_to_import2.zip b/bpm/bonita-core/bonita-process-engine/src/test/resources/org/bonitasoft/web/application/final/app_to_import2.zip index 352d0376190..2be9a944734 100644 Binary files a/bpm/bonita-core/bonita-process-engine/src/test/resources/org/bonitasoft/web/application/final/app_to_import2.zip and b/bpm/bonita-core/bonita-process-engine/src/test/resources/org/bonitasoft/web/application/final/app_to_import2.zip differ diff --git a/bpm/bonita-core/bonita-process-instance/build.gradle b/bpm/bonita-core/bonita-process-instance/build.gradle index d4b0f005f19..2d34607b38b 100644 --- a/bpm/bonita-core/bonita-process-instance/build.gradle +++ b/bpm/bonita-core/bonita-process-instance/build.gradle @@ -23,7 +23,6 @@ dependencies { api project(':bpm:bonita-core:bonita-contract-data') api 'org.bonitasoft.engine:bonita-connector-model' - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.mockitoCore testImplementation libs.systemRules diff --git a/bpm/bonita-core/bonita-process-instance/src/main/java/org/bonitasoft/engine/core/process/instance/api/ProcessInstanceService.java b/bpm/bonita-core/bonita-process-instance/src/main/java/org/bonitasoft/engine/core/process/instance/api/ProcessInstanceService.java index 363795f9f21..803388b12c6 100644 --- a/bpm/bonita-core/bonita-process-instance/src/main/java/org/bonitasoft/engine/core/process/instance/api/ProcessInstanceService.java +++ b/bpm/bonita-core/bonita-process-instance/src/main/java/org/bonitasoft/engine/core/process/instance/api/ProcessInstanceService.java @@ -396,6 +396,15 @@ long getNumberOfOpenProcessInstancesInvolvingUsersManagedBy(long managerUserId, List searchOpenProcessInstancesInvolvingUsersManagedBy(long managerUserId, QueryOptions queryOptions) throws SBonitaReadException; + /** + * Get the list of all archived process instance start dates since the given date + * + * @param sinceDateInMillis the date since when we want to get the list of start dates (in milliseconds) + * @return the list of all archived process instance start dates, expressed in millis since EPOCH. + * @throws SProcessInstanceReadException if an exception occurs while reading the process instances + */ + List getLastArchivedProcessInstanceStartDates(long sinceDateInMillis) throws SProcessInstanceReadException; + /** * Get the list of sourceObjectIds for archived process instances children of process instance identified by * rootProcessIntanceId diff --git a/bpm/bonita-core/bonita-process-instance/src/main/java/org/bonitasoft/engine/core/process/instance/api/exceptions/SProcessInstanceCreationException.java b/bpm/bonita-core/bonita-process-instance/src/main/java/org/bonitasoft/engine/core/process/instance/api/exceptions/SProcessInstanceCreationException.java index b72d6123835..8d5238dd325 100644 --- a/bpm/bonita-core/bonita-process-instance/src/main/java/org/bonitasoft/engine/core/process/instance/api/exceptions/SProcessInstanceCreationException.java +++ b/bpm/bonita-core/bonita-process-instance/src/main/java/org/bonitasoft/engine/core/process/instance/api/exceptions/SProcessInstanceCreationException.java @@ -13,6 +13,7 @@ **/ package org.bonitasoft.engine.core.process.instance.api.exceptions; +import lombok.Getter; import org.bonitasoft.engine.commons.exceptions.SBonitaException; import org.bonitasoft.engine.core.process.definition.model.SProcessDefinition; @@ -23,21 +24,26 @@ public class SProcessInstanceCreationException extends SBonitaException { private static final long serialVersionUID = 7581906795549409593L; + @Getter + private long retryAfter = -1L; + public SProcessInstanceCreationException(final Throwable cause) { super(cause); } - public SProcessInstanceCreationException(final String message, final SBonitaException e) { - super(message, e); + public SProcessInstanceCreationException(final String message, final Throwable cause) { + super(message, cause); } - /** - * @param string - */ public SProcessInstanceCreationException(final String message) { super(message); } + public SProcessInstanceCreationException(final String message, final long retryAfter) { + super(message); + this.retryAfter = retryAfter; + } + /** * @param sDefinition * The process definition to add on context diff --git a/bpm/bonita-core/bonita-process-instance/src/main/java/org/bonitasoft/engine/core/process/instance/impl/ProcessInstanceServiceImpl.java b/bpm/bonita-core/bonita-process-instance/src/main/java/org/bonitasoft/engine/core/process/instance/impl/ProcessInstanceServiceImpl.java index be2ff9e6c4e..f0f3988aa4a 100644 --- a/bpm/bonita-core/bonita-process-instance/src/main/java/org/bonitasoft/engine/core/process/instance/impl/ProcessInstanceServiceImpl.java +++ b/bpm/bonita-core/bonita-process-instance/src/main/java/org/bonitasoft/engine/core/process/instance/impl/ProcessInstanceServiceImpl.java @@ -862,6 +862,21 @@ public List getArchivedProcessInstancesInAllStates(final List } } + @Override + public List getLastArchivedProcessInstanceStartDates(final long sinceDateInMillis) + throws SProcessInstanceReadException { + final ReadPersistenceService persistenceService = archiveService.getDefinitiveArchiveReadPersistenceService(); + try { + final Map parameters = Collections.singletonMap("sinceDateInMillis", sinceDateInMillis); + final SelectListDescriptor saProcessInstances = new SelectListDescriptor<>( + "getLastArchivedProcessInstanceStartDates", parameters, SAProcessInstance.class, + QueryOptions.countQueryOptions()); + return persistenceService.selectList(saProcessInstances); + } catch (final SBonitaReadException e) { + throw new SProcessInstanceReadException(e); + } + } + protected Set getStateIdsFromStates(final ProcessInstanceState... states) { if (states.length < 1) { throw new IllegalArgumentException( diff --git a/bpm/bonita-core/bonita-process-instance/src/main/resources/org/bonitasoft/engine/core/process/instance/model/impl/hibernate/archived.process.instance.queries.hbm.xml b/bpm/bonita-core/bonita-process-instance/src/main/resources/org/bonitasoft/engine/core/process/instance/model/impl/hibernate/archived.process.instance.queries.hbm.xml index 48989a0bd47..e461d9af24e 100644 --- a/bpm/bonita-core/bonita-process-instance/src/main/resources/org/bonitasoft/engine/core/process/instance/model/impl/hibernate/archived.process.instance.queries.hbm.xml +++ b/bpm/bonita-core/bonita-process-instance/src/main/resources/org/bonitasoft/engine/core/process/instance/model/impl/hibernate/archived.process.instance.queries.hbm.xml @@ -413,6 +413,13 @@ WHERE ap.sourceObjectId IN (:sourceObjectIds) + + SELECT DISTINCT ap.startDate + FROM org.bonitasoft.engine.core.process.instance.model.archive.SAProcessInstance AS ap + WHERE ap.stateId = 0 + AND ap.startDate >= :sinceDateInMillis + + SELECT ap FROM org.bonitasoft.engine.core.process.instance.model.archive.SAProcessInstance AS ap diff --git a/bpm/bonita-core/bonita-user-filter/build.gradle b/bpm/bonita-core/bonita-user-filter/build.gradle index ca4a8fd1f12..3ba2fef340f 100644 --- a/bpm/bonita-core/bonita-user-filter/build.gradle +++ b/bpm/bonita-core/bonita-user-filter/build.gradle @@ -11,7 +11,6 @@ dependencies { api project(':bpm:bonita-core:bonita-process-instance') api project(':bpm:bonita-core:bonita-home-server') api project(':services:bonita-commons') - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.mockitoCore } diff --git a/bpm/bonita-external/build.gradle b/bpm/bonita-external/build.gradle index 0c6c96bb295..7db54caf78f 100644 --- a/bpm/bonita-external/build.gradle +++ b/bpm/bonita-external/build.gradle @@ -4,6 +4,5 @@ dependencies { api project(':bpm:bonita-core:bonita-process-engine') api project(':services:bonita-command') api project(':bpm:bonita-core:bonita-process-definition') - testImplementation libs.junit4 testImplementation libs.mockitoCore } diff --git a/bpm/bonita-synchro-repository/bonita-synchro-register/build.gradle b/bpm/bonita-synchro-repository/bonita-synchro-register/build.gradle index c88bc1cd6e3..c92f23bbe78 100644 --- a/bpm/bonita-synchro-repository/bonita-synchro-register/build.gradle +++ b/bpm/bonita-synchro-repository/bonita-synchro-register/build.gradle @@ -4,6 +4,8 @@ dependencies { api project(':bpm:bonita-core:bonita-process-engine') api project(':bpm:bonita-synchro-repository:bonita-synchro-service-impl') api project(':services:bonita-commons') + annotationProcessor(libs.lombok) + compileOnly(libs.lombok) compileOnly libs.jakartaJmsApi compileOnly libs.activemqClient } diff --git a/bpm/bonita-synchro-repository/bonita-synchro-service-impl/src/main/java/org/bonitasoft/engine/synchro/AbstractSynchroService.java b/bpm/bonita-synchro-repository/bonita-synchro-service-impl/src/main/java/org/bonitasoft/engine/synchro/AbstractSynchroService.java index 1ce41ef9dfd..467b2f8d478 100644 --- a/bpm/bonita-synchro-repository/bonita-synchro-service-impl/src/main/java/org/bonitasoft/engine/synchro/AbstractSynchroService.java +++ b/bpm/bonita-synchro-repository/bonita-synchro-service-impl/src/main/java/org/bonitasoft/engine/synchro/AbstractSynchroService.java @@ -111,8 +111,6 @@ protected Serializable getFiredAndRemoveIt(final Map expec List firedEvents = cacheService.getKeys(SYNCHRO_SERVICE_CACHE); for (Map firedEvent : (List>) firedEvents) { if (matchedAtLeastAllExpectedEntries(expectedEvent, firedEvent)) { - // Serializable id = (Serializable) cacheService.get(SYNCHRO_SERVICE_CACHE, firedEvent); - // System.out.println("id=" + id); cacheService.remove(SYNCHRO_SERVICE_CACHE, firedEvent); return firedEvent.get("id"); } diff --git a/bpm/bonita-synchro-repository/bonita-synchro-service-impl/src/main/java/org/bonitasoft/engine/synchro/SynchroServiceImpl.java b/bpm/bonita-synchro-repository/bonita-synchro-service-impl/src/main/java/org/bonitasoft/engine/synchro/SynchroServiceImpl.java index da4ebece7b1..630ae42019e 100644 --- a/bpm/bonita-synchro-repository/bonita-synchro-service-impl/src/main/java/org/bonitasoft/engine/synchro/SynchroServiceImpl.java +++ b/bpm/bonita-synchro-repository/bonita-synchro-service-impl/src/main/java/org/bonitasoft/engine/synchro/SynchroServiceImpl.java @@ -34,7 +34,7 @@ */ public class SynchroServiceImpl extends AbstractSynchroService { - private Logger logger = LoggerFactory.getLogger(SynchroServiceImpl.class); + private final Logger logger = LoggerFactory.getLogger(SynchroServiceImpl.class); private final Map, String> waiters; private final Map eventKeyAndIdMap; @@ -49,9 +49,9 @@ public class SynchroServiceImpl extends AbstractSynchroService { */ private SynchroServiceImpl(final int initialCapacity, final CacheService cacheService) { super(cacheService); - waiters = new HashMap, String>(initialCapacity); - eventKeyAndIdMap = new HashMap(initialCapacity); - eventSemaphores = new HashMap(); + waiters = new HashMap<>(initialCapacity); + eventKeyAndIdMap = new HashMap<>(initialCapacity); + eventSemaphores = new HashMap<>(); } private static final class SynchroServiceImplReentrantLock extends ReentrantLock { @@ -89,7 +89,7 @@ protected void releaseWaiter(final String semaphoreKey) { @Override public Serializable waitForEvent(final Map event, final long timeout) throws InterruptedException, TimeoutException { - Serializable id = null; + Serializable id; String semaphoreKey = null; Semaphore semaphore = null; getServiceLock().lock(); @@ -122,7 +122,7 @@ public Serializable waitForEvent(final Map event, final lo private String getSemaphoreKey(final Map event) { final StringBuilder sb = new StringBuilder(); - final TreeMap orderedMap = new TreeMap(event); + final TreeMap orderedMap = new TreeMap<>(event); boolean first = true; for (final Map.Entry entry : orderedMap.entrySet()) { if (!first) { diff --git a/bpm/bonita-web-extensions/build.gradle b/bpm/bonita-web-extensions/build.gradle index cad45478333..bf5f87ef450 100644 --- a/bpm/bonita-web-extensions/build.gradle +++ b/bpm/bonita-web-extensions/build.gradle @@ -4,7 +4,6 @@ dependencies { api(libs.javaxServletApi) api(project(":bpm:bonita-client")) api(project(":bpm:bonita-common")) - testImplementation libs.junit4 testImplementation libs.assertj } diff --git a/bpm/bonita-web-server/build.gradle b/bpm/bonita-web-server/build.gradle index 1de54f512ca..571a000a049 100644 --- a/bpm/bonita-web-server/build.gradle +++ b/bpm/bonita-web-server/build.gradle @@ -28,6 +28,7 @@ dependencies { implementation(libs.restletJackson) { exclude(group: "org.codehaus.woodstox", module: "woodstox-core-asl") exclude(group: "org.codehaus.woodstox", module: "stax2-api") + exclude(group: "org.yaml", module: "snakeyaml") } implementation libs.woodstoxCore implementation libs.groovyCore @@ -48,16 +49,13 @@ dependencies { testImplementation libs.logback testImplementation libs.springTest testImplementation libs.systemRules - testImplementation libs.mockitoJunitJupiter + testImplementation libs.mockitoCore testImplementation libs.hamcrest - testImplementation libs.junit4 - testImplementation libs.junit5api - testRuntimeOnly libs.junitJupiterEngine - testRuntimeOnly libs.junitVintageEngine + testImplementation libs.mockitoJunitJupiter } configurations { - all { + configureEach { // Specify woodstox version to override the version pulled by jackson-dataformat-xml (transitive dep of restlet) resolutionStrategy.force libs.woodstoxCore // Specify Guava version to override the version pulled by owasp-java-html-sanitizer @@ -91,19 +89,16 @@ tasks.named("build") { dependsOn tasks.named("buildZip") } -tasks.named("test") { - dependsOn tasks.named("testsJar") - useJUnitPlatform { - includeEngines 'junit-jupiter', 'junit-vintage' - } -} - tasks.register('testsJar', Jar) { dependsOn testClasses archiveClassifier = 'tests' from(sourceSets.test.output) } +test { + dependsOn tasks.named("testsJar") +} + artifacts { tests testsJar } diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/filter/RedirectFilter.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/filter/RedirectFilter.java new file mode 100644 index 00000000000..deb94a29e73 --- /dev/null +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/filter/RedirectFilter.java @@ -0,0 +1,55 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.console.common.server.filter; + +import java.io.IOException; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.bonitasoft.console.common.server.auth.AuthenticationManager; + +/** + * Filter that redirects to a URL specified as a parameter in the request. + * The URL must be relative to the current domain. + * + * @author Haroun EL ALAMI + */ +@Slf4j +public class RedirectFilter implements Filter { + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + + final HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; + final HttpServletResponse httpResponse = (HttpServletResponse) servletResponse; + + String redirectUrl = httpRequest.getParameter(AuthenticationManager.REDIRECT_URL); + if (StringUtils.isNoneBlank(redirectUrl)) { + // avoid redirecting to a different domain + if (!redirectUrl.contains("//")) { + httpResponse.sendRedirect(redirectUrl); + return; + } + // If the redirectUrl is not valid + log.warn("Invalid redirect URL: {}", redirectUrl); + } + + filterChain.doFilter(servletRequest, servletResponse); + } +} diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/login/filter/AuthenticationFilter.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/login/filter/AuthenticationFilter.java index 4d620e4eab9..aa711499790 100644 --- a/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/login/filter/AuthenticationFilter.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/login/filter/AuthenticationFilter.java @@ -25,6 +25,7 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import org.apache.commons.lang3.StringUtils; import org.bonitasoft.console.common.server.auth.AuthenticationManager; import org.bonitasoft.console.common.server.auth.AuthenticationManagerFactory; import org.bonitasoft.console.common.server.auth.AuthenticationManagerNotFoundException; @@ -259,7 +260,10 @@ protected AuthenticationManager getAuthenticationManager() throws ServletExcepti } protected RedirectUrl makeRedirectUrl(final HttpServletRequestAccessor httpRequest) { - final RedirectUrlBuilder builder = new RedirectUrlBuilder(httpRequest.getRequestedUri()); + // if the request has a redirection URL, we use it, otherwise we use the requested URI + boolean hasRedirectionURL = StringUtils.isNotBlank(httpRequest.getRedirectUrl()); + final RedirectUrlBuilder builder = new RedirectUrlBuilder( + hasRedirectionURL ? httpRequest.getRedirectUrl() : httpRequest.getRequestedUri()); builder.appendParameters(httpRequest.getParameterMap()); return builder.build(); } diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/login/filter/RestAPIAuthorizationFilter.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/login/filter/RestAPIAuthorizationFilter.java index efd89e6e59f..46c72fcfe8a 100644 --- a/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/login/filter/RestAPIAuthorizationFilter.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/login/filter/RestAPIAuthorizationFilter.java @@ -86,7 +86,7 @@ public void proceedWithFiltering(ServletRequest request, ServletResponse respons } } catch (final InvalidSessionException e) { if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Invalid Bonita engine session.", e.getMessage()); + LOGGER.debug("Invalid Bonita engine session: {}", e.getMessage()); } SessionUtil.sessionLogout(httpServletRequest.getSession()); ((HttpServletResponse) response).setStatus(HttpServletResponse.SC_UNAUTHORIZED); diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/page/CustomPageAuthorizationsHelper.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/page/CustomPageAuthorizationsHelper.java index 145095f2dad..9542228558d 100644 --- a/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/page/CustomPageAuthorizationsHelper.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/page/CustomPageAuthorizationsHelper.java @@ -15,9 +15,9 @@ import org.bonitasoft.engine.api.ApplicationAPI; import org.bonitasoft.engine.api.PageAPI; -import org.bonitasoft.engine.business.application.Application; import org.bonitasoft.engine.business.application.ApplicationPageSearchDescriptor; import org.bonitasoft.engine.business.application.ApplicationSearchDescriptor; +import org.bonitasoft.engine.business.application.IApplication; import org.bonitasoft.engine.exception.BonitaException; import org.bonitasoft.engine.search.SearchOptionsBuilder; import org.bonitasoft.engine.search.SearchResult; @@ -62,8 +62,9 @@ public boolean isPageAuthorized(final String applicationToken, final String page } private Long getApplicationId(String applicationToken) throws BonitaException { - SearchResult applicationSResult = applicationAPI.searchApplications(new SearchOptionsBuilder(0, 1) - .filter(ApplicationSearchDescriptor.TOKEN, applicationToken).done()); + SearchResult applicationSResult = applicationAPI + .searchIApplications(new SearchOptionsBuilder(0, 1) + .filter(ApplicationSearchDescriptor.TOKEN, applicationToken).done()); if (applicationSResult.getResult().isEmpty()) { return null; diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/page/PageDownloadServlet.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/page/PageDownloadServlet.java index 37d9144fdcc..2123caecd2d 100644 --- a/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/page/PageDownloadServlet.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/page/PageDownloadServlet.java @@ -105,7 +105,7 @@ protected void doGet(final HttpServletRequest request, final HttpServletResponse LOGGER.error(e.getMessage(), e); } try { - out.write("An exception occured. Please contact an administrator".getBytes()); + out.write("An exception occurred. Please contact an administrator".getBytes()); } catch (final IOException e1) { throw new ServletException(e1); } diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/servlet/ErrorPageServlet.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/servlet/ErrorPageServlet.java index 057575157bf..28a7d491bc1 100644 --- a/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/servlet/ErrorPageServlet.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/console/common/server/servlet/ErrorPageServlet.java @@ -87,7 +87,7 @@ protected void doGet(final HttpServletRequest request, final HttpServletResponse if (LOGGER.isErrorEnabled()) { LOGGER.error("Error while trying to get the error page.", e); } - output.println("An Error occured."); + output.println("An Error occurred."); } } writeFormatedResponse(output, errorCode, contextPath); @@ -124,7 +124,7 @@ protected void writeFormatedResponse(PrintWriter output, String errorCode, Strin if (LOGGER.isErrorEnabled()) { LOGGER.error("Error while trying to display the error page.", e); } - output.println("An Error occured."); + output.println("An Error occurred."); } } diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/livingapps/ApplicationModelFactory.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/livingapps/ApplicationModelFactory.java index 590f43e395d..baa5bbf6f96 100644 --- a/bpm/bonita-web-server/src/main/java/org/bonitasoft/livingapps/ApplicationModelFactory.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/livingapps/ApplicationModelFactory.java @@ -18,6 +18,7 @@ import org.bonitasoft.engine.api.ProfileAPI; import org.bonitasoft.engine.business.application.Application; import org.bonitasoft.engine.business.application.ApplicationSearchDescriptor; +import org.bonitasoft.engine.business.application.IApplication; import org.bonitasoft.engine.exception.SearchException; import org.bonitasoft.engine.search.SearchOptionsBuilder; import org.bonitasoft.engine.search.SearchResult; @@ -40,7 +41,7 @@ public ApplicationModelFactory(final ApplicationAPI applicationApi, final PageAP public ApplicationModel createApplicationModel(final String name) throws CreationException { try { - final SearchResult result = applicationApi.searchApplications( + final SearchResult result = applicationApi.searchIApplications( new SearchOptionsBuilder(0, 1) .filter(ApplicationSearchDescriptor.TOKEN, name) .done()); @@ -48,12 +49,18 @@ public ApplicationModel createApplicationModel(final String name) throws Creatio if (result.getCount() == 0) { throw new CreationException("No application found with name " + name); } + // find a legacy application + var legacyApplication = result.getResult().stream().filter(Application.class::isInstance) + .map(Application.class::cast).findFirst(); + if (legacyApplication.isEmpty()) { + throw new CreationException("Only application links were found with name " + name); + } return new ApplicationModel( applicationApi, customPageApi, profileApi, - result.getResult().get(0), + legacyApplication.get(), new MenuFactory(applicationApi)); } catch (final SearchException e) { throw new CreationException("Error while searching for the application " + name, e); diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/ModelFactory.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/ModelFactory.java index 6f8f1ecbda7..460ec7403ec 100644 --- a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/ModelFactory.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/ModelFactory.java @@ -13,7 +13,10 @@ **/ package org.bonitasoft.web.rest.model; +import org.bonitasoft.web.rest.model.application.AbstractApplicationDefinition; +import org.bonitasoft.web.rest.model.application.AbstractApplicationItem; import org.bonitasoft.web.rest.model.application.ApplicationDefinition; +import org.bonitasoft.web.rest.model.application.ApplicationLinkDefinition; import org.bonitasoft.web.rest.model.applicationmenu.ApplicationMenuDefinition; import org.bonitasoft.web.rest.model.applicationpage.ApplicationPageDefinition; import org.bonitasoft.web.rest.model.bpm.cases.ArchivedCaseDefinition; @@ -190,7 +193,11 @@ else if (PageDefinition.TOKEN.equals(token)) { return new PageDefinition(); } //Applications - else if (ApplicationDefinition.TOKEN.equals(token)) { + else if (AbstractApplicationDefinition.TOKEN.equals(token)) { + return new AbstractApplicationDefinition(); + } else if (ApplicationLinkDefinition.TOKEN.equals(token)) { + return new ApplicationLinkDefinition(); + } else if (ApplicationDefinition.TOKEN.equals(token)) { return new ApplicationDefinition(); } else if (ApplicationPageDefinition.TOKEN.equals(token)) { return new ApplicationPageDefinition(); diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/application/AbstractApplicationDefinition.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/application/AbstractApplicationDefinition.java new file mode 100644 index 00000000000..66d9e9ef894 --- /dev/null +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/application/AbstractApplicationDefinition.java @@ -0,0 +1,119 @@ +/** + * Copyright (C) 2022 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.web.rest.model.application; + +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import java.util.function.Supplier; + +import org.bonitasoft.web.toolkit.client.common.TreeIndexed; +import org.bonitasoft.web.toolkit.client.common.TreeLeaf; +import org.bonitasoft.web.toolkit.client.data.item.Definitions; +import org.bonitasoft.web.toolkit.client.data.item.DiscriminatedItemDefinitionHelper; +import org.bonitasoft.web.toolkit.client.data.item.ItemDefinition; +import org.bonitasoft.web.toolkit.client.data.item.attribute.ItemAttribute; +import org.bonitasoft.web.toolkit.client.data.item.attribute.ValidationError; +import org.bonitasoft.web.toolkit.client.data.item.attribute.ValidationException; +import org.bonitasoft.web.toolkit.client.data.item.attribute.validator.FileIsImageOrServletPathValidator; + +/** + * Item definition for a Bonita Living Application for the REST API (either legacy or link). + */ +public class AbstractApplicationDefinition extends ItemDefinition { + + public static final String TOKEN = "abstractApplication"; + + @Override + protected String defineToken() { + return TOKEN; + } + + @Override + protected String defineAPIUrl() { + return "../API/living/application"; + } + + @Override + protected void defineAttributes() { + createAttribute(AbstractApplicationItem.ATTRIBUTE_ID, ItemAttribute.TYPE.ITEM_ID); + createAttribute(AbstractApplicationItem.ATTRIBUTE_LINK, ItemAttribute.TYPE.BOOLEAN); + createAttribute(AbstractApplicationItem.ATTRIBUTE_TOKEN, ItemAttribute.TYPE.STRING); + createAttribute(AbstractApplicationItem.ATTRIBUTE_DISPLAY_NAME, ItemAttribute.TYPE.STRING); + createAttribute(AbstractApplicationItem.ATTRIBUTE_PROFILE_ID, ItemAttribute.TYPE.ITEM_ID); + createAttribute(AbstractApplicationItem.ATTRIBUTE_VERSION, ItemAttribute.TYPE.STRING); + createAttribute(AbstractApplicationItem.ATTRIBUTE_DESCRIPTION, ItemAttribute.TYPE.TEXT); + createAttribute(AbstractApplicationItem.ATTRIBUTE_ICON, ItemAttribute.TYPE.STRING) + .addValidator(new FileIsImageOrServletPathValidator(ApplicationItem.ICON_PATH_API_PREFIX)); + createAttribute(AbstractApplicationItem.ATTRIBUTE_CREATION_DATE, ItemAttribute.TYPE.STRING); + createAttribute(AbstractApplicationItem.ATTRIBUTE_CREATED_BY, ItemAttribute.TYPE.ITEM_ID); + createAttribute(AbstractApplicationItem.ATTRIBUTE_LAST_UPDATE_DATE, ItemAttribute.TYPE.STRING); + createAttribute(AbstractApplicationItem.ATTRIBUTE_UPDATED_BY, ItemAttribute.TYPE.ITEM_ID); + createAttribute(AbstractApplicationItem.ATTRIBUTE_STATE, ItemAttribute.TYPE.STRING); + createAttribute(AbstractApplicationItem.ATTRIBUTE_VISIBILITY, ItemAttribute.TYPE.STRING); + createAttribute(ApplicationItem.ATTRIBUTE_EDITABLE, ItemAttribute.TYPE.BOOLEAN); + } + + @Override + protected void definePrimaryKeys() { + setPrimaryKeys(AbstractApplicationItem.ATTRIBUTE_ID); + } + + public static AbstractApplicationDefinition get() { + return (AbstractApplicationDefinition) Definitions.get(TOKEN); + } + + @Override + protected ITEM _createItem() { + // this must not be called by deprecated PUT and POST methods which need to discriminate on "link". + throw new ValidationException(Collections.singletonList( + new ValidationError("link", "%attribute% is mandatory to discriminate the application type"))); + } + + @Override + public Optional> getDiscriminatedHelper() { + if (AbstractApplicationDefinition.class.equals(getClass())) { + return Optional.of(new DiscriminatedItemDefinitionHelper() { + + @Override + @SuppressWarnings("unchecked") + public Supplier findItemCreator(Map attributes) { + // We need the "link" attribute to discriminate between legacy application and application link. + boolean isLink = attributes != null + && Boolean.parseBoolean(attributes.get(AbstractApplicationItem.ATTRIBUTE_LINK)); + return isLink ? () -> (ITEM) ApplicationLinkDefinition.get()._createItem() + : () -> (ITEM) ApplicationDefinition.get()._createItem(); + } + + @Override + public Supplier findItemCreator(TreeIndexed tree) { + // We need the "link" attribute to discriminate between legacy application and application link. + boolean isLink; + if (tree != null && tree.get(AbstractApplicationItem.ATTRIBUTE_LINK)instanceof TreeLeaf v) { + isLink = Optional.ofNullable(v.getValue()).map(Object::toString).map(Boolean::parseBoolean) + .orElse(Boolean.FALSE); + } else { + isLink = false; + } + return isLink ? () -> (ITEM) ApplicationLinkDefinition.get()._createItem() + : () -> (ITEM) ApplicationDefinition.get()._createItem(); + } + }); + } else { + // subclasses do not need the helper and use a concrete implementation + return Optional.empty(); + } + } + +} diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/application/AbstractApplicationItem.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/application/AbstractApplicationItem.java new file mode 100644 index 00000000000..593a7a94155 --- /dev/null +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/application/AbstractApplicationItem.java @@ -0,0 +1,206 @@ +/** + * Copyright (C) 2022 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.web.rest.model.application; + +import org.bonitasoft.web.toolkit.client.data.APIID; +import org.bonitasoft.web.toolkit.client.data.item.IItem; +import org.bonitasoft.web.toolkit.client.data.item.Item; +import org.bonitasoft.web.toolkit.client.data.item.template.ItemHasIcon; +import org.bonitasoft.web.toolkit.client.data.item.template.ItemHasUniqueId; + +/** + * Contains the meta information of a Bonita Living Application for the REST API. + */ +public abstract class AbstractApplicationItem extends Item implements ItemHasUniqueId, ItemHasIcon { + + /** + * This attributes is used to distinguish application links from legacy + * applications. It can be used for search, filter or ordering. + */ + public static final String ATTRIBUTE_LINK = "link"; + + public static final String ATTRIBUTE_TOKEN = "token"; + + public static final String ATTRIBUTE_DISPLAY_NAME = "displayName"; + + public static final String ATTRIBUTE_VERSION = "version"; + + public static final String ATTRIBUTE_DESCRIPTION = "description"; + + public static final String ATTRIBUTE_CREATION_DATE = "creationDate"; + + public static final String ATTRIBUTE_CREATED_BY = "createdBy"; + + public static final String ATTRIBUTE_LAST_UPDATE_DATE = "lastUpdateDate"; + + public static final String ATTRIBUTE_UPDATED_BY = "updatedBy"; + + public static final String ATTRIBUTE_STATE = "state"; + + public static final String ATTRIBUTE_PROFILE_ID = "profileId"; + + public static final String ATTRIBUTE_VISIBILITY = "visibility"; + + public static final String ATTRIBUTE_EDITABLE = "editable"; + + public static final String FILTER_USER_ID = "userId"; + + public static final String ICON_PATH_API_PREFIX = "../API/applicationIcon/"; + + public AbstractApplicationItem() { + super(); + setAttribute(ATTRIBUTE_LINK, isLink()); + } + + public AbstractApplicationItem(final IItem item) { + super(item); + setAttribute(ATTRIBUTE_LINK, isLink()); + } + + @Override + public ApplicationDefinition getItemDefinition() { + return ApplicationDefinition.get(); + } + + @Override + public void setId(final String id) { + setId(APIID.makeAPIID(id)); + } + + @Override + public void setId(final Long id) { + setId(APIID.makeAPIID(id)); + } + + /* + * #isLink should be implemented by subclasses with a static result depending on the application nature. + */ + public abstract boolean isLink(); + + public String getToken() { + return getAttributeValue(ATTRIBUTE_TOKEN); + } + + public void setToken(final String token) { + setAttribute(ATTRIBUTE_TOKEN, token); + } + + public String getDisplayName() { + return getAttributeValue(ATTRIBUTE_DISPLAY_NAME); + } + + public void setDisplayName(final String name) { + setAttribute(ATTRIBUTE_DISPLAY_NAME, name); + } + + public String getVersion() { + return getAttributeValue(ATTRIBUTE_VERSION); + } + + public void setVersion(final String version) { + setAttribute(ATTRIBUTE_VERSION, version); + } + + public String getDescription() { + return getAttributeValue(ATTRIBUTE_DESCRIPTION); + } + + public void setDescription(final String description) { + setAttribute(ATTRIBUTE_DESCRIPTION, description); + } + + @Override + public String getIcon() { + return getAttributeValue(ATTRIBUTE_ICON); + } + + @Override + public void setIcon(String icon) { + setAttribute(ATTRIBUTE_ICON, icon); + } + + public String getCreationDate() { + return getAttributeValue(ATTRIBUTE_CREATION_DATE); + } + + public void setCreationDate(final String creationDate) { + setAttribute(ATTRIBUTE_CREATION_DATE, creationDate); + } + + public long getCreatedBy() { + return getAttributeValueAsLong(ATTRIBUTE_CREATED_BY); + } + + public void setCreatedBy(final long createdBy) { + setAttribute(ATTRIBUTE_CREATED_BY, createdBy); + } + + public String getLastUpdateDate() { + return getAttributeValue(ATTRIBUTE_LAST_UPDATE_DATE); + } + + public void setLastUpdateDate(final String lastUpdateDate) { + setAttribute(ATTRIBUTE_LAST_UPDATE_DATE, lastUpdateDate); + } + + public long getUpdatedBy() { + return getAttributeValueAsLong(ATTRIBUTE_UPDATED_BY); + } + + public void setUpdatedBy(final long updatedBy) { + setAttribute(ATTRIBUTE_UPDATED_BY, updatedBy); + } + + public String getState() { + return getAttributeValue(ATTRIBUTE_STATE); + } + + public void setState(final String state) { + setAttribute(ATTRIBUTE_STATE, state); + } + + public APIID getProfileId() { + return getAttributeValueAsAPIID(ATTRIBUTE_PROFILE_ID); + } + + public void setProfileId(final Long profileId) { + setAttribute(ATTRIBUTE_PROFILE_ID, profileId); + } + + public APIID getUserId() { + return getAttributeValueAsAPIID(FILTER_USER_ID); + } + + public void setUserId(final String userId) { + setAttribute(FILTER_USER_ID, userId); + } + + public String getVisibility() { + return getAttributeValue(ATTRIBUTE_VISIBILITY); + } + + /** FIXME Use Enum instead of String after removing GWT permutations */ + public void setVisibility(final String visibility) { + setAttribute(ATTRIBUTE_VISIBILITY, visibility); + } + + public boolean isEditable() { + return Boolean.parseBoolean(getAttributeValue(ATTRIBUTE_EDITABLE)); + } + + public void setEditable(final boolean isEditable) { + setAttribute(ATTRIBUTE_EDITABLE, String.valueOf(isEditable)); + } + +} diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/application/ApplicationDefinition.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/application/ApplicationDefinition.java index 1fb70a5258b..14904dfa54a 100755 --- a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/application/ApplicationDefinition.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/application/ApplicationDefinition.java @@ -14,14 +14,12 @@ package org.bonitasoft.web.rest.model.application; import org.bonitasoft.web.toolkit.client.data.item.Definitions; -import org.bonitasoft.web.toolkit.client.data.item.ItemDefinition; import org.bonitasoft.web.toolkit.client.data.item.attribute.ItemAttribute; -import org.bonitasoft.web.toolkit.client.data.item.attribute.validator.FileIsImageOrServletPathValidator; /** - * @author Elias Ricken de Medeiros + * Item definition for a Legacy Bonita Living Application for the REST API. */ -public class ApplicationDefinition extends ItemDefinition { +public class ApplicationDefinition extends AbstractApplicationDefinition { public static final String TOKEN = "application"; @@ -30,36 +28,12 @@ protected String defineToken() { return TOKEN; } - @Override - protected String defineAPIUrl() { - return "../API/living/application"; - } - @Override protected void defineAttributes() { - createAttribute(ApplicationItem.ATTRIBUTE_ID, ItemAttribute.TYPE.ITEM_ID); - createAttribute(ApplicationItem.ATTRIBUTE_TOKEN, ItemAttribute.TYPE.STRING); - createAttribute(ApplicationItem.ATTRIBUTE_DISPLAY_NAME, ItemAttribute.TYPE.STRING); - createAttribute(ApplicationItem.ATTRIBUTE_PROFILE_ID, ItemAttribute.TYPE.ITEM_ID); + super.defineAttributes(); createAttribute(ApplicationItem.ATTRIBUTE_HOME_PAGE_ID, ItemAttribute.TYPE.ITEM_ID); createAttribute(ApplicationItem.ATTRIBUTE_LAYOUT_ID, ItemAttribute.TYPE.ITEM_ID); createAttribute(ApplicationItem.ATTRIBUTE_THEME_ID, ItemAttribute.TYPE.ITEM_ID); - createAttribute(ApplicationItem.ATTRIBUTE_VERSION, ItemAttribute.TYPE.STRING); - createAttribute(ApplicationItem.ATTRIBUTE_DESCRIPTION, ItemAttribute.TYPE.TEXT); - createAttribute(ApplicationItem.ATTRIBUTE_ICON, ItemAttribute.TYPE.STRING) - .addValidator(new FileIsImageOrServletPathValidator(ApplicationItem.ICON_PATH_API_PREFIX)); - createAttribute(ApplicationItem.ATTRIBUTE_CREATION_DATE, ItemAttribute.TYPE.STRING); - createAttribute(ApplicationItem.ATTRIBUTE_CREATED_BY, ItemAttribute.TYPE.ITEM_ID); - createAttribute(ApplicationItem.ATTRIBUTE_LAST_UPDATE_DATE, ItemAttribute.TYPE.STRING); - createAttribute(ApplicationItem.ATTRIBUTE_UPDATED_BY, ItemAttribute.TYPE.ITEM_ID); - createAttribute(ApplicationItem.ATTRIBUTE_STATE, ItemAttribute.TYPE.STRING); - createAttribute(ApplicationItem.ATTRIBUTE_VISIBILITY, ItemAttribute.TYPE.STRING); - createAttribute(ApplicationItem.ATTRIBUTE_EDITABLE, ItemAttribute.TYPE.BOOLEAN); - } - - @Override - protected void definePrimaryKeys() { - setPrimaryKeys(ApplicationItem.ATTRIBUTE_ID); } @Override diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/application/ApplicationItem.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/application/ApplicationItem.java index 80095c0fb89..c20a51757a0 100755 --- a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/application/ApplicationItem.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/application/ApplicationItem.java @@ -16,22 +16,13 @@ import org.bonitasoft.web.rest.model.portal.page.PageItem; import org.bonitasoft.web.toolkit.client.data.APIID; import org.bonitasoft.web.toolkit.client.data.item.IItem; -import org.bonitasoft.web.toolkit.client.data.item.Item; import org.bonitasoft.web.toolkit.client.data.item.template.ItemHasIcon; import org.bonitasoft.web.toolkit.client.data.item.template.ItemHasUniqueId; /** - * @author Elias Ricken de Medeiros + * Contains the meta information of a legacy Bonita Living Application for the REST API. */ -public class ApplicationItem extends Item implements ItemHasUniqueId, ItemHasIcon { - - public static final String ATTRIBUTE_TOKEN = "token"; - - public static final String ATTRIBUTE_DISPLAY_NAME = "displayName"; - - public static final String ATTRIBUTE_VERSION = "version"; - - public static final String ATTRIBUTE_DESCRIPTION = "description"; +public class ApplicationItem extends AbstractApplicationItem implements ItemHasUniqueId, ItemHasIcon { /** * @deprecated since 7.13.0, see {@link #getIconPath()} & {@link #setIconPath(String)} @@ -39,32 +30,12 @@ public class ApplicationItem extends Item implements ItemHasUniqueId, ItemHasIco @Deprecated(since = "7.13.0") public static final String ATTRIBUTE_ICON_PATH = "iconPath"; - public static final String ATTRIBUTE_CREATION_DATE = "creationDate"; - - public static final String ATTRIBUTE_CREATED_BY = "createdBy"; - - public static final String ATTRIBUTE_LAST_UPDATE_DATE = "lastUpdateDate"; - - public static final String ATTRIBUTE_UPDATED_BY = "updatedBy"; - - public static final String ATTRIBUTE_STATE = "state"; - - public static final String ATTRIBUTE_PROFILE_ID = "profileId"; - public static final String ATTRIBUTE_HOME_PAGE_ID = "homePageId"; public static final String ATTRIBUTE_LAYOUT_ID = "layoutId"; public static final String ATTRIBUTE_THEME_ID = "themeId"; - public static final String ATTRIBUTE_VISIBILITY = "visibility"; - - public static final String ATTRIBUTE_EDITABLE = "editable"; - - public static final String FILTER_USER_ID = "userId"; - - public static final String ICON_PATH_API_PREFIX = "../API/applicationIcon/"; - public ApplicationItem() { super(); } @@ -74,50 +45,8 @@ public ApplicationItem(final IItem item) { } @Override - public ApplicationDefinition getItemDefinition() { - return ApplicationDefinition.get(); - } - - @Override - public void setId(final String id) { - setId(APIID.makeAPIID(id)); - } - - @Override - public void setId(final Long id) { - setId(APIID.makeAPIID(id)); - } - - public String getToken() { - return getAttributeValue(ATTRIBUTE_TOKEN); - } - - public void setToken(final String token) { - setAttribute(ATTRIBUTE_TOKEN, token); - } - - public String getDisplayName() { - return getAttributeValue(ATTRIBUTE_DISPLAY_NAME); - } - - public void setDisplayName(final String name) { - setAttribute(ATTRIBUTE_DISPLAY_NAME, name); - } - - public String getVersion() { - return getAttributeValue(ATTRIBUTE_VERSION); - } - - public void setVersion(final String version) { - setAttribute(ATTRIBUTE_VERSION, version); - } - - public String getDescription() { - return getAttributeValue(ATTRIBUTE_DESCRIPTION); - } - - public void setDescription(final String description) { - setAttribute(ATTRIBUTE_DESCRIPTION, description); + public boolean isLink() { + return false; } /** @@ -136,64 +65,6 @@ public void setIconPath(final String iconPath) { setAttribute(ATTRIBUTE_ICON_PATH, iconPath); } - @Override - public String getIcon() { - return getAttributeValue(ATTRIBUTE_ICON); - } - - @Override - public void setIcon(String icon) { - setAttribute(ATTRIBUTE_ICON, icon); - } - - public String getCreationDate() { - return getAttributeValue(ATTRIBUTE_CREATION_DATE); - } - - public void setCreationDate(final String creationDate) { - setAttribute(ATTRIBUTE_CREATION_DATE, creationDate); - } - - public long getCreatedBy() { - return getAttributeValueAsLong(ATTRIBUTE_CREATED_BY); - } - - public void setCreatedBy(final long createdBy) { - setAttribute(ATTRIBUTE_CREATED_BY, createdBy); - } - - public String getLastUpdateDate() { - return getAttributeValue(ATTRIBUTE_LAST_UPDATE_DATE); - } - - public void setLastUpdateDate(final String lastUpdateDate) { - setAttribute(ATTRIBUTE_LAST_UPDATE_DATE, lastUpdateDate); - } - - public long getUpdatedBy() { - return getAttributeValueAsLong(ATTRIBUTE_UPDATED_BY); - } - - public void setUpdatedBy(final long updatedBy) { - setAttribute(ATTRIBUTE_UPDATED_BY, updatedBy); - } - - public String getState() { - return getAttributeValue(ATTRIBUTE_STATE); - } - - public void setState(final String state) { - setAttribute(ATTRIBUTE_STATE, state); - } - - public APIID getProfileId() { - return getAttributeValueAsAPIID(ATTRIBUTE_PROFILE_ID); - } - - public void setProfileId(final Long profileId) { - setAttribute(ATTRIBUTE_PROFILE_ID, profileId); - } - public APIID getHomePageId() { return getAttributeValueAsAPIID(ATTRIBUTE_HOME_PAGE_ID); } @@ -218,31 +89,6 @@ public void setThemeId(final Long themeId) { setAttribute(ATTRIBUTE_THEME_ID, themeId); } - public APIID getUserId() { - return getAttributeValueAsAPIID(FILTER_USER_ID); - } - - public void setUserId(final String userId) { - setAttribute(FILTER_USER_ID, userId); - } - - public String getVisibility() { - return getAttributeValue(ATTRIBUTE_VISIBILITY); - } - - /** FIXME Use Enum instead of String after removing GWT permutations */ - public void setVisibility(final String visibility) { - setAttribute(ATTRIBUTE_VISIBILITY, visibility); - } - - public boolean isEditable() { - return Boolean.parseBoolean(getAttributeValue(ATTRIBUTE_EDITABLE)); - } - - public void setEditable(final boolean isEditable) { - setAttribute(ATTRIBUTE_EDITABLE, String.valueOf(isEditable)); - } - public PageItem getLayout() { return (PageItem) getDeploy(ATTRIBUTE_LAYOUT_ID); } diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/application/ApplicationLinkDefinition.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/application/ApplicationLinkDefinition.java new file mode 100644 index 00000000000..7e284c0afe5 --- /dev/null +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/application/ApplicationLinkDefinition.java @@ -0,0 +1,39 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.web.rest.model.application; + +import org.bonitasoft.web.toolkit.client.data.item.Definitions; + +/** + * Item definition for an Bonita Living Application Link for the REST API. + */ +public class ApplicationLinkDefinition extends AbstractApplicationDefinition { + + public static final String TOKEN = "applicationLink"; + + @Override + protected String defineToken() { + return TOKEN; + } + + @Override + protected ApplicationLinkItem _createItem() { + return new ApplicationLinkItem(); + } + + public static ApplicationLinkDefinition get() { + return (ApplicationLinkDefinition) Definitions.get(TOKEN); + } + +} diff --git a/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/SQLServerExtendedDialect.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/application/ApplicationLinkItem.java similarity index 53% rename from services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/SQLServerExtendedDialect.java rename to bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/application/ApplicationLinkItem.java index 6d682ef78a1..e1ae63ac995 100644 --- a/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/SQLServerExtendedDialect.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/model/application/ApplicationLinkItem.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2017 Bonitasoft S.A. + * Copyright (C) 2024 Bonitasoft S.A. * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble * This library is free software; you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Foundation @@ -11,24 +11,28 @@ * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301, USA. **/ -package org.bonitasoft.engine.persistence; +package org.bonitasoft.web.rest.model.application; -import java.sql.Types; - -import org.hibernate.dialect.SQLServer2012Dialect; +import org.bonitasoft.web.toolkit.client.data.item.IItem; +import org.bonitasoft.web.toolkit.client.data.item.template.ItemHasIcon; +import org.bonitasoft.web.toolkit.client.data.item.template.ItemHasUniqueId; /** - * @author Emmanuel Duchastenier + * Contains the meta information of a Bonita Living Application Link for the REST API. */ -public class SQLServerExtendedDialect extends SQLServer2012Dialect { +public class ApplicationLinkItem extends AbstractApplicationItem implements ItemHasUniqueId, ItemHasIcon { - public SQLServerExtendedDialect() { + public ApplicationLinkItem() { super(); - registerColumnType(Types.CHAR, "nchar(1)"); - registerColumnType(Types.VARCHAR, "nvarchar($l)"); - registerColumnType(Types.VARCHAR, 8000, "nvarchar($l)"); - registerColumnType(Types.LONGVARCHAR, "nvarchar($l)"); - registerColumnType(Types.CLOB, "ntext"); + } + + public ApplicationLinkItem(final IItem item) { + super(item); + } + + @Override + public boolean isLink() { + return true; } } diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/api/AbstractRESTController.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/api/AbstractRESTController.java index 363830b6767..3dd84dad83e 100644 --- a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/api/AbstractRESTController.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/api/AbstractRESTController.java @@ -28,9 +28,9 @@ public abstract class AbstractRESTController { public APISession getApiSession(HttpSession session) { APISession apiSession = (APISession) session.getAttribute(SessionUtil.API_SESSION_PARAM_KEY); if (apiSession == null) { - throw new ResponseStatusException( - HttpStatus.UNAUTHORIZED, "Not authenticated"); + throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Not authenticated"); } return apiSession; } + } diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/api/application/APIApplication.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/api/application/APIApplication.java index e38837774b0..d03fb92205a 100644 --- a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/api/application/APIApplication.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/api/application/APIApplication.java @@ -16,7 +16,8 @@ import java.util.List; import java.util.Map; -import org.bonitasoft.web.rest.model.application.ApplicationDefinition; +import org.bonitasoft.web.rest.model.application.AbstractApplicationDefinition; +import org.bonitasoft.web.rest.model.application.AbstractApplicationItem; import org.bonitasoft.web.rest.model.application.ApplicationItem; import org.bonitasoft.web.rest.server.api.ConsoleAPI; import org.bonitasoft.web.rest.server.api.applicationpage.APIApplicationDataStoreFactory; @@ -35,11 +36,16 @@ import org.bonitasoft.web.toolkit.client.data.item.ItemDefinition; /** + * Defines the REST API for applications. + *

    Since 10.2.0 some types have changed in this interface. + * Yet, these are not breaking changes as the json conversion does not change when using only legacy applications. + * This class is not intended to be used as a Java API.

    + * * @author Julien Mege */ -public class APIApplication extends ConsoleAPI - implements APIHasAdd, APIHasSearch, - APIHasGet, APIHasUpdate, APIHasDelete { +public class APIApplication extends ConsoleAPI + implements APIHasAdd, APIHasSearch, + APIHasGet, APIHasUpdate, APIHasDelete { private final ApplicationDataStoreCreator creator; @@ -56,7 +62,7 @@ public APIApplication(final ApplicationDataStoreCreator creator, */ @Override @Deprecated(since = "9.0.0") - public ApplicationItem add(final ApplicationItem item) { + public AbstractApplicationItem add(final AbstractApplicationItem item) { return creator.create(getEngineSession()).add(item); } @@ -65,12 +71,12 @@ public ApplicationItem add(final ApplicationItem item) { */ @Override @Deprecated(since = "9.0.0") - public ApplicationItem update(final APIID id, final Map attributes) { + public AbstractApplicationItem update(final APIID id, final Map attributes) { return creator.create(getEngineSession()).update(id, attributes); } @Override - public ApplicationItem get(final APIID id) { + public AbstractApplicationItem get(final APIID id) { return creator.create(getEngineSession()).get(id); } @@ -80,7 +86,8 @@ public void delete(final List ids) { } @Override - public ItemSearchResult search(final int page, final int resultsByPage, final String search, + public ItemSearchResult search(final int page, final int resultsByPage, + final String search, final String orders, final Map filters) { return creator.create(getEngineSession()).search(page, resultsByPage, search, orders, filters); @@ -88,27 +95,30 @@ public ItemSearchResult search(final int page, final int result @Override public String defineDefaultSearchOrder() { - return ApplicationItem.ATTRIBUTE_DISPLAY_NAME; + return AbstractApplicationItem.ATTRIBUTE_DISPLAY_NAME; } + @SuppressWarnings("unchecked") @Override - protected ItemDefinition defineItemDefinition() { - return ApplicationDefinition.get(); + protected ItemDefinition defineItemDefinition() { + return (ItemDefinition) AbstractApplicationDefinition.get(); } @Override - protected void fillDeploys(final ApplicationItem item, final List deploys) { + protected void fillDeploys(final AbstractApplicationItem item, final List deploys) { addDeployer(new UserDeployer( - new UserDatastore(getEngineSession()), ApplicationItem.ATTRIBUTE_CREATED_BY)); + new UserDatastore(getEngineSession()), AbstractApplicationItem.ATTRIBUTE_CREATED_BY)); addDeployer(new UserDeployer( - new UserDatastore(getEngineSession()), ApplicationItem.ATTRIBUTE_UPDATED_BY)); - addDeployer(getDeployerFactory().createProfileDeployer(ApplicationItem.ATTRIBUTE_PROFILE_ID)); - addDeployer(new PageDeployer( - applicationDataStoreFactory.createPageDataStore(getEngineSession()), - ApplicationItem.ATTRIBUTE_LAYOUT_ID)); - addDeployer(new PageDeployer( - applicationDataStoreFactory.createPageDataStore(getEngineSession()), - ApplicationItem.ATTRIBUTE_THEME_ID)); + new UserDatastore(getEngineSession()), AbstractApplicationItem.ATTRIBUTE_UPDATED_BY)); + addDeployer(getDeployerFactory().createProfileDeployer(AbstractApplicationItem.ATTRIBUTE_PROFILE_ID)); + if (item instanceof ApplicationItem) { + addDeployer(new PageDeployer( + applicationDataStoreFactory.createPageDataStore(getEngineSession()), + ApplicationItem.ATTRIBUTE_LAYOUT_ID)); + addDeployer(new PageDeployer( + applicationDataStoreFactory.createPageDataStore(getEngineSession()), + ApplicationItem.ATTRIBUTE_THEME_ID)); + } super.fillDeploys(item, deploys); } diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/api/bpm/process/ProcessInstantiationResource.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/api/bpm/process/ProcessInstantiationResource.java index 7f4dfb45c01..d065b890ee5 100644 --- a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/api/bpm/process/ProcessInstantiationResource.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/api/bpm/process/ProcessInstantiationResource.java @@ -15,6 +15,7 @@ import java.io.FileNotFoundException; import java.io.Serializable; +import java.util.Date; import java.util.Map; import com.fasterxml.jackson.databind.node.JsonNodeFactory; @@ -29,6 +30,8 @@ import org.bonitasoft.engine.bpm.process.ProcessExecutionException; import org.bonitasoft.web.rest.server.api.resource.CommonResource; import org.bonitasoft.web.toolkit.client.common.exception.api.APIException; +import org.restlet.Response; +import org.restlet.data.Status; import org.restlet.resource.Post; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -83,7 +86,17 @@ public String instantiateProcess(final Map inputs) } catch (ProcessExecutionException e) { String errorMessage = "Unable to start the process with ID " + processDefinitionId; if (LOGGER.isErrorEnabled()) { - LOGGER.error(errorMessage + " Error: " + e.getMessage()); + LOGGER.error("{}. Caused by: {}", errorMessage, e.getMessage()); + } + if (e.getRetryAfter() != -1L) { + // Return a 429 status code with Retry-After header to indicate the client + // that he should retry later in case of case creation limit reached + Response response = getResponse(); + response.setRetryAfter(new Date(e.getRetryAfter())); + var status = new Status(Status.CLIENT_ERROR_TOO_MANY_REQUESTS, "Case creation limit reached.", + errorMessage); + response.setStatus(status); + return null; } //Avoid throwing original exception that may contain sensitive information unwanted in the HTTP response throw new ProcessExecutionException(errorMessage + " (consult the logs for more information)."); diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/api/deployer/ApplicationDeployer.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/api/deployer/ApplicationDeployer.java index 185aba8c8c3..0cf8e6f64ae 100644 --- a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/api/deployer/ApplicationDeployer.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/api/deployer/ApplicationDeployer.java @@ -13,7 +13,7 @@ **/ package org.bonitasoft.web.rest.server.api.deployer; -import org.bonitasoft.web.rest.model.application.ApplicationItem; +import org.bonitasoft.web.rest.model.application.AbstractApplicationItem; import org.bonitasoft.web.rest.server.framework.Deployer; import org.bonitasoft.web.rest.server.framework.api.DatastoreHasGet; import org.bonitasoft.web.toolkit.client.data.item.IItem; @@ -23,11 +23,11 @@ */ public class ApplicationDeployer implements Deployer { - private final DatastoreHasGet getter; + private final DatastoreHasGet getter; private final String attribute; - public ApplicationDeployer(final DatastoreHasGet getter, final String attribute) { + public ApplicationDeployer(final DatastoreHasGet getter, final String attribute) { this.getter = getter; this.attribute = attribute; } diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/api/platform/SystemInformationController.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/api/platform/SystemInformationController.java new file mode 100644 index 00000000000..5f044a26646 --- /dev/null +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/api/platform/SystemInformationController.java @@ -0,0 +1,54 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.web.rest.server.api.platform; + +import java.util.Map; + +import javax.servlet.http.HttpSession; + +import lombok.extern.slf4j.Slf4j; +import org.bonitasoft.engine.api.TenantAPIAccessor; +import org.bonitasoft.engine.api.platform.PlatformInformationAPI; +import org.bonitasoft.engine.exception.BonitaException; +import org.bonitasoft.engine.exception.BonitaHomeNotSetException; +import org.bonitasoft.engine.exception.ServerAPIException; +import org.bonitasoft.engine.exception.UnknownAPITypeException; +import org.bonitasoft.engine.session.APISession; +import org.bonitasoft.web.rest.server.api.AbstractRESTController; +import org.bonitasoft.web.toolkit.client.common.exception.api.APIException; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequestMapping("/API/system/information") +public class SystemInformationController extends AbstractRESTController { + + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + public Map getPlatformInfo(HttpSession session) { + try { + return getPlatformInformationAPI(getApiSession(session)).getPlatformInformation(); + } catch (final BonitaException e) { + throw new APIException(e); + } + } + + protected PlatformInformationAPI getPlatformInformationAPI(APISession apiSession) + throws BonitaHomeNotSetException, ServerAPIException, UnknownAPITypeException { + return TenantAPIAccessor.getPlatformInformationAPI(apiSession); + } + +} diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationDataStore.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationDataStore.java index 6915d93ce24..a613effbc76 100644 --- a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationDataStore.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationDataStore.java @@ -21,16 +21,22 @@ import org.bonitasoft.engine.api.PageAPI; import org.bonitasoft.engine.business.application.Application; import org.bonitasoft.engine.business.application.ApplicationCreator; +import org.bonitasoft.engine.business.application.ApplicationLink; +import org.bonitasoft.engine.business.application.ApplicationLinkCreator; +import org.bonitasoft.engine.business.application.ApplicationLinkUpdater; import org.bonitasoft.engine.business.application.ApplicationNotFoundException; import org.bonitasoft.engine.business.application.ApplicationPage; import org.bonitasoft.engine.business.application.ApplicationUpdater; +import org.bonitasoft.engine.business.application.IApplication; import org.bonitasoft.engine.exception.BonitaException; import org.bonitasoft.engine.exception.SearchException; import org.bonitasoft.engine.page.Page; import org.bonitasoft.engine.search.SearchResult; import org.bonitasoft.engine.session.APISession; +import org.bonitasoft.web.rest.model.application.AbstractApplicationItem; import org.bonitasoft.web.rest.model.application.ApplicationDefinition; import org.bonitasoft.web.rest.model.application.ApplicationItem; +import org.bonitasoft.web.rest.model.application.ApplicationLinkItem; import org.bonitasoft.web.rest.server.datastore.CommonDatastore; import org.bonitasoft.web.rest.server.datastore.filter.Filters; import org.bonitasoft.web.rest.server.datastore.utils.SearchOptionsCreator; @@ -48,10 +54,10 @@ /** * @author Elias Ricken de Medeiros */ -public class ApplicationDataStore extends CommonDatastore - implements DatastoreHasAdd, - DatastoreHasUpdate, - DatastoreHasGet, DatastoreHasSearch, DatastoreHasDelete { +public class ApplicationDataStore extends CommonDatastore + implements DatastoreHasAdd, + DatastoreHasUpdate, + DatastoreHasGet, DatastoreHasSearch, DatastoreHasDelete { private final ApplicationAPI applicationAPI; private final ApplicationItemConverter converter; @@ -82,9 +88,9 @@ public void delete(final List ids) { } @Override - public ApplicationItem get(final APIID id) { + public AbstractApplicationItem get(final APIID id) { try { - final Application application = applicationAPI.getApplication(id.toLong()); + final IApplication application = applicationAPI.getIApplication(id.toLong()); return converter.toApplicationItem(application); } catch (final BonitaException e) { throw new APIException(e); @@ -96,6 +102,21 @@ public ApplicationItem get(final APIID id) { */ @Override @Deprecated(since = "9.0.0") + public AbstractApplicationItem add(final AbstractApplicationItem item) { + if (item instanceof ApplicationItem legacy) { + return add(legacy); + } else if (item instanceof ApplicationLinkItem link) { + return add(link); + } else { + // should not occur anyway + throw new APIException("Unknown application type."); + } + } + + /** + * @deprecated as of 9.0.0, Applications should be created at startup. + */ + @Deprecated(since = "9.0.0") public ApplicationItem add(final ApplicationItem item) { try { @@ -107,7 +128,35 @@ public ApplicationItem add(final ApplicationItem item) { final ApplicationPage appHomePage = applicationAPI.createApplicationPage(application.getId(), homePageDef.getId(), "home"); applicationAPI.setApplicationHomePage(application.getId(), appHomePage.getId()); - return converter.toApplicationItem(application); + var converted = converter.toApplicationItem(application); + if (converted instanceof ApplicationItem res) { + return res; + } else { + // should not occur anyway + throw new APIException("Use dedicated API for application links."); + } + } catch (final BonitaException e) { + throw new APIException(e); + } + } + + /** + * @deprecated as of 9.0.0, Applications should be created at startup. + */ + @Deprecated(since = "9.0.0") + public ApplicationLinkItem add(final ApplicationLinkItem item) { + + try { + final ApplicationLinkCreator creator = converter.toApplicationLinkCreator(item); + + final ApplicationLink application = applicationAPI.createApplicationLink(creator); + var converted = converter.toApplicationItem(application); + if (converted instanceof ApplicationLinkItem res) { + return res; + } else { + // should not occur anyway + throw new APIException("Use dedicated API for legacy applications."); + } } catch (final BonitaException e) { throw new APIException(e); } @@ -118,25 +167,37 @@ public ApplicationItem add(final ApplicationItem item) { */ @Override @Deprecated(since = "9.0.0") - public ApplicationItem update(final APIID id, final Map attributes) { + public AbstractApplicationItem update(final APIID id, final Map attributes) { try { - final ApplicationUpdater applicationUpdater = converter.toApplicationUpdater(attributes); - final Application application = applicationAPI.updateApplication(id.toLong(), applicationUpdater); - return converter.toApplicationItem(application); + // no way to know the application type without getting it first + IApplication app = applicationAPI.getIApplication(id.toLong()); + if (app instanceof Application) { + final ApplicationUpdater applicationUpdater = converter.toApplicationUpdater(attributes); + final Application application = applicationAPI.updateApplication(id.toLong(), applicationUpdater); + return converter.toApplicationItem(application); + } else if (app instanceof ApplicationLink) { + final ApplicationLinkUpdater applicationUpdater = converter.toApplicationLinkUpdater(attributes); + final ApplicationLink link = applicationAPI.updateApplicationLink(id.toLong(), applicationUpdater); + return converter.toApplicationItem(link); + } else { + // should not occur anyway + throw new APIException("Unknown application type."); + } } catch (final BonitaException e) { throw new APIException(e); } } @Override - public ItemSearchResult search(final int page, final int resultsByPage, final String search, + public ItemSearchResult search(final int page, final int resultsByPage, + final String search, final String orders, final Map filters) { // Build search final SearchOptionsCreator creator = makeSearchOptionCreator(page, resultsByPage, search, orders, filters); // Run search depending on filters passed - SearchResult searchResult; + SearchResult searchResult; try { searchResult = runSearch(creator); @@ -157,8 +218,8 @@ protected SearchOptionsCreator makeSearchOptionCreator(final int page, final int new ApplicationFilterCreator(getSearchDescriptorConverter()))); } - protected SearchResult runSearch(final SearchOptionsCreator creator) throws SearchException { - return applicationAPI.searchApplications(creator.create()); + protected SearchResult runSearch(final SearchOptionsCreator creator) throws SearchException { + return applicationAPI.searchIApplications(creator.create()); } protected ApplicationSearchDescriptorConverter getSearchDescriptorConverter() { @@ -166,7 +227,7 @@ protected ApplicationSearchDescriptorConverter getSearchDescriptorConverter() { } @Override - protected ApplicationItem convertEngineToConsoleItem(final Application item) { + protected AbstractApplicationItem convertEngineToConsoleItem(final IApplication item) { return new ApplicationItemConverter(new BonitaHomeFolderAccessor()).toApplicationItem(item); } diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationDataStoreCreator.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationDataStoreCreator.java index 08c2f607de8..31198cc018f 100644 --- a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationDataStoreCreator.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationDataStoreCreator.java @@ -18,6 +18,9 @@ import org.bonitasoft.engine.api.PageAPI; import org.bonitasoft.engine.api.TenantAPIAccessor; import org.bonitasoft.engine.exception.BonitaException; +import org.bonitasoft.engine.exception.BonitaHomeNotSetException; +import org.bonitasoft.engine.exception.ServerAPIException; +import org.bonitasoft.engine.exception.UnknownAPITypeException; import org.bonitasoft.engine.session.APISession; import org.bonitasoft.web.toolkit.client.common.exception.api.APIException; @@ -30,14 +33,24 @@ public ApplicationDataStore create(final APISession session) { ApplicationAPI applicationAPI; PageAPI pageAPI; try { - applicationAPI = TenantAPIAccessor.getLivingApplicationAPI(session); - pageAPI = TenantAPIAccessor.getCustomPageAPI(session); + applicationAPI = getLivingApplicationAPI(session); + pageAPI = getCustomPageAPI(session); return new ApplicationDataStore(session, applicationAPI, pageAPI, getApplicationConverter()); } catch (final BonitaException e) { throw new APIException(e); } } + protected PageAPI getCustomPageAPI(APISession session) + throws BonitaHomeNotSetException, ServerAPIException, UnknownAPITypeException { + return TenantAPIAccessor.getCustomPageAPI(session); + } + + protected ApplicationAPI getLivingApplicationAPI(APISession session) + throws BonitaHomeNotSetException, ServerAPIException, UnknownAPITypeException { + return TenantAPIAccessor.getLivingApplicationAPI(session); + } + protected ApplicationItemConverter getApplicationConverter() { return new ApplicationItemConverter(new BonitaHomeFolderAccessor()); } diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationItemConverter.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationItemConverter.java index 752a8aaeeee..313ec71a0be 100644 --- a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationItemConverter.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationItemConverter.java @@ -19,8 +19,13 @@ import org.bonitasoft.console.common.server.utils.IconDescriptor; import org.bonitasoft.engine.business.application.Application; import org.bonitasoft.engine.business.application.ApplicationCreator; +import org.bonitasoft.engine.business.application.ApplicationLinkCreator; +import org.bonitasoft.engine.business.application.ApplicationLinkUpdater; import org.bonitasoft.engine.business.application.ApplicationUpdater; +import org.bonitasoft.engine.business.application.IApplication; +import org.bonitasoft.web.rest.model.application.AbstractApplicationItem; import org.bonitasoft.web.rest.model.application.ApplicationItem; +import org.bonitasoft.web.rest.model.application.ApplicationLinkItem; import org.bonitasoft.web.toolkit.client.common.util.MapUtil; import org.bonitasoft.web.toolkit.client.data.item.template.ItemHasIcon; @@ -35,8 +40,31 @@ public ApplicationItemConverter(BonitaHomeFolderAccessor bonitaHomeFolderAccesso this.bonitaHomeFolderAccessor = bonitaHomeFolderAccessor; } - public ApplicationItem toApplicationItem(final Application application) { - final ApplicationItem item = new ApplicationItem(); + public AbstractApplicationItem toApplicationItem(final IApplication application) { + final AbstractApplicationItem item; + + if (application instanceof Application legacy) { + var legacyItem = new ApplicationItem(); + item = legacyItem; + if (legacy.getHomePageId() != null) { + legacyItem.setHomePageId(legacy.getHomePageId()); + } else { + legacyItem.setHomePageId(-1L); + } + if (legacy.getLayoutId() != null) { + legacyItem.setLayoutId(legacy.getLayoutId()); + } else { + legacyItem.setLayoutId(-1L); + } + if (legacy.getThemeId() != null) { + legacyItem.setThemeId(legacy.getThemeId()); + } else { + legacyItem.setThemeId(-1L); + } + } else { + item = new ApplicationLinkItem(); + } + item.setId(application.getId()); item.setToken(application.getToken()); item.setDisplayName(application.getDisplayName()); @@ -56,25 +84,14 @@ public ApplicationItem toApplicationItem(final Application application) { } else { item.setProfileId(-1L); } - if (application.getHomePageId() != null) { - item.setHomePageId(application.getHomePageId()); - } else { - item.setHomePageId(-1L); - } - if (application.getLayoutId() != null) { - item.setLayoutId(application.getLayoutId()); - } else { - item.setLayoutId(-1L); - } - if (application.getThemeId() != null) { - item.setThemeId(application.getThemeId()); - } else { - item.setThemeId(-1L); - } return item; } + /** + * @deprecated ApplicationCreator should no longer be used. Since 9.0.0, Applications should be created at startup. + */ + @Deprecated(since = "10.2.0") public ApplicationCreator toApplicationCreator(final ApplicationItem appItem) { final ApplicationCreator creator = new ApplicationCreator(appItem.getToken(), appItem.getDisplayName(), appItem.getVersion()); @@ -83,6 +100,23 @@ public ApplicationCreator toApplicationCreator(final ApplicationItem appItem) { return creator; } + /** + * @deprecated ApplicationCreator should no longer be used. Since 9.0.0, Applications should be created at startup. + */ + @Deprecated(since = "10.2.0") + public ApplicationLinkCreator toApplicationLinkCreator(final ApplicationLinkItem appLinkItem) { + final ApplicationLinkCreator creator = new ApplicationLinkCreator(appLinkItem.getToken(), + appLinkItem.getDisplayName(), + appLinkItem.getVersion()); + creator.setDescription(appLinkItem.getDescription()); + creator.setProfileId(appLinkItem.getProfileId().toLong()); + return creator; + } + + /** + * @deprecated ApplicationUpdater should no longer be used. Since 9.0.0, Applications should be created at startup. + */ + @Deprecated(since = "10.2.0") public ApplicationUpdater toApplicationUpdater(final Map attributes) { final ApplicationUpdater applicationUpdater = getApplicationUpdater(); @@ -123,8 +157,57 @@ public ApplicationUpdater toApplicationUpdater(final Map attribu } + /** + * @deprecated ApplicationUpdater should no longer be used. Since 9.0.0, Applications should be created at startup. + */ + @Deprecated(since = "10.2.0") + public ApplicationLinkUpdater toApplicationLinkUpdater(final Map attributes) { + final ApplicationLinkUpdater applicationUpdater = getApplicationLinkUpdater(); + + if (attributes.containsKey(ApplicationItem.ATTRIBUTE_TOKEN)) { + applicationUpdater.setToken(attributes.get(ApplicationItem.ATTRIBUTE_TOKEN)); + } + if (attributes.containsKey(ApplicationItem.ATTRIBUTE_DISPLAY_NAME)) { + applicationUpdater.setDisplayName(attributes.get(ApplicationItem.ATTRIBUTE_DISPLAY_NAME)); + } + if (attributes.containsKey(ApplicationItem.ATTRIBUTE_DESCRIPTION)) { + applicationUpdater.setDescription(attributes.get(ApplicationItem.ATTRIBUTE_DESCRIPTION)); + } + if (attributes.containsKey(ApplicationItem.ATTRIBUTE_PROFILE_ID)) { + applicationUpdater.setProfileId(Long.parseLong(attributes.get(ApplicationItem.ATTRIBUTE_PROFILE_ID))); + } + + if (attributes.containsKey(ApplicationItem.ATTRIBUTE_STATE)) { + applicationUpdater.setState(attributes.get(ApplicationItem.ATTRIBUTE_STATE)); + } + if (attributes.containsKey(ApplicationItem.ATTRIBUTE_VERSION)) { + applicationUpdater.setVersion(attributes.get(ApplicationItem.ATTRIBUTE_VERSION)); + } + if (!MapUtil.isBlank(attributes, ItemHasIcon.ATTRIBUTE_ICON) + && !attributes.get(ItemHasIcon.ATTRIBUTE_ICON).startsWith(ApplicationItem.ICON_PATH_API_PREFIX)) { + IconDescriptor iconDescriptor = bonitaHomeFolderAccessor + .getIconFromFileSystem(attributes.get(ItemHasIcon.ATTRIBUTE_ICON)); + applicationUpdater.setIcon(iconDescriptor.getFilename(), iconDescriptor.getContent()); + } + + return applicationUpdater; + + } + + /** + * @deprecated ApplicationUpdater should no longer be used. Since 9.0.0, Applications should be created at startup. + */ + @Deprecated(since = "10.2.0") protected ApplicationUpdater getApplicationUpdater() { return new ApplicationUpdater(); } + /** + * @deprecated ApplicationUpdater should no longer be used. Since 9.0.0, Applications should be created at startup. + */ + @Deprecated(since = "10.2.0") + protected ApplicationLinkUpdater getApplicationLinkUpdater() { + return new ApplicationLinkUpdater(); + } + } diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationSearchDescriptorConverter.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationSearchDescriptorConverter.java index bdccfe7dc44..9e09d6f5e79 100644 --- a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationSearchDescriptorConverter.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationSearchDescriptorConverter.java @@ -13,11 +13,11 @@ **/ package org.bonitasoft.web.rest.server.datastore.application; -import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.bonitasoft.engine.business.application.ApplicationSearchDescriptor; +import org.bonitasoft.web.rest.model.application.AbstractApplicationItem; import org.bonitasoft.web.rest.model.application.ApplicationItem; import org.bonitasoft.web.rest.server.datastore.converter.AttributeConverter; import org.bonitasoft.web.toolkit.client.common.util.MapUtil; @@ -27,25 +27,30 @@ public class ApplicationSearchDescriptorConverter implements AttributeConverter private final Map mapping; + private final Map valueTypeMapping = new HashMap<>(); + public ApplicationSearchDescriptorConverter() { mapping = createMapping(); } private Map createMapping() { final Map mapping = new HashMap<>(); - mapping.put(ApplicationItem.ATTRIBUTE_ID, ApplicationSearchDescriptor.ID); - mapping.put(ApplicationItem.ATTRIBUTE_TOKEN, ApplicationSearchDescriptor.TOKEN); - mapping.put(ApplicationItem.ATTRIBUTE_DISPLAY_NAME, ApplicationSearchDescriptor.DISPLAY_NAME); - mapping.put(ApplicationItem.ATTRIBUTE_STATE, ApplicationSearchDescriptor.STATE); - mapping.put(ApplicationItem.ATTRIBUTE_CREATED_BY, ApplicationSearchDescriptor.CREATED_BY); - mapping.put(ApplicationItem.ATTRIBUTE_CREATION_DATE, ApplicationSearchDescriptor.CREATION_DATE); - mapping.put(ApplicationItem.ATTRIBUTE_LAST_UPDATE_DATE, ApplicationSearchDescriptor.LAST_UPDATE_DATE); - mapping.put(ApplicationItem.ATTRIBUTE_UPDATED_BY, ApplicationSearchDescriptor.UPDATED_BY); - mapping.put(ApplicationItem.ATTRIBUTE_VERSION, ApplicationSearchDescriptor.VERSION); - mapping.put(ApplicationItem.ATTRIBUTE_PROFILE_ID, ApplicationSearchDescriptor.PROFILE_ID); + mapping.put(AbstractApplicationItem.ATTRIBUTE_ID, ApplicationSearchDescriptor.ID); + mapping.put(AbstractApplicationItem.ATTRIBUTE_LINK, ApplicationSearchDescriptor.LINK); + valueTypeMapping.put(AbstractApplicationItem.ATTRIBUTE_LINK, ItemAttribute.TYPE.BOOLEAN); + mapping.put(AbstractApplicationItem.ATTRIBUTE_TOKEN, ApplicationSearchDescriptor.TOKEN); + mapping.put(AbstractApplicationItem.ATTRIBUTE_DISPLAY_NAME, ApplicationSearchDescriptor.DISPLAY_NAME); + mapping.put(AbstractApplicationItem.ATTRIBUTE_STATE, ApplicationSearchDescriptor.STATE); + mapping.put(AbstractApplicationItem.ATTRIBUTE_CREATED_BY, ApplicationSearchDescriptor.CREATED_BY); + mapping.put(AbstractApplicationItem.ATTRIBUTE_CREATION_DATE, ApplicationSearchDescriptor.CREATION_DATE); + mapping.put(AbstractApplicationItem.ATTRIBUTE_LAST_UPDATE_DATE, ApplicationSearchDescriptor.LAST_UPDATE_DATE); + mapping.put(AbstractApplicationItem.ATTRIBUTE_UPDATED_BY, ApplicationSearchDescriptor.UPDATED_BY); + mapping.put(AbstractApplicationItem.ATTRIBUTE_VERSION, ApplicationSearchDescriptor.VERSION); + mapping.put(AbstractApplicationItem.ATTRIBUTE_PROFILE_ID, ApplicationSearchDescriptor.PROFILE_ID); + mapping.put(AbstractApplicationItem.FILTER_USER_ID, ApplicationSearchDescriptor.USER_ID); + mapping.put(ApplicationItem.ATTRIBUTE_LAYOUT_ID, ApplicationSearchDescriptor.LAYOUT_ID); mapping.put(ApplicationItem.ATTRIBUTE_THEME_ID, ApplicationSearchDescriptor.THEME_ID); - mapping.put(ApplicationItem.FILTER_USER_ID, ApplicationSearchDescriptor.USER_ID); return mapping; } @@ -57,7 +62,7 @@ public String convert(final String attribute) { @Override public Map getValueTypeMapping() { - return Collections.emptyMap(); + return valueTypeMapping; } } diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/engineclient/CaseEngineClient.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/engineclient/CaseEngineClient.java index dff3404bb81..b5995db99b2 100644 --- a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/engineclient/CaseEngineClient.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/rest/server/engineclient/CaseEngineClient.java @@ -27,6 +27,7 @@ import org.bonitasoft.engine.search.SearchOptionsBuilder; import org.bonitasoft.web.toolkit.client.common.exception.api.APIException; import org.bonitasoft.web.toolkit.client.common.exception.api.APINotFoundException; +import org.bonitasoft.web.toolkit.client.common.exception.api.APITooManyRequestException; import org.bonitasoft.web.toolkit.client.common.i18n.T_; import org.bonitasoft.web.toolkit.client.common.texttemplate.Arg; @@ -70,8 +71,14 @@ public ProcessInstance start(final long userId, final long processId, final Map< new T_("Can't start process, process %processId% is not enabled", new Arg("processId", processId)), e); } catch (final ProcessExecutionException e) { + if (e.getRetryAfter() != -1L) { + throw new APITooManyRequestException( + new T_("Error occurred when starting process %processId%. Case creation limit reached.", + new Arg("processId", processId)), + e.getRetryAfter()); + } throw new APIException( - new T_("Error occured when starting process %processId%", new Arg("processId", processId)), e); + new T_("Error occurred when starting process %processId%", new Arg("processId", processId)), e); } catch (final UserNotFoundException e) { throw new APIException( new T_("Can't start process %processId%, user %userId% not found", new Arg("processId", processId), diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/toolkit/client/common/exception/api/APITooManyRequestException.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/toolkit/client/common/exception/api/APITooManyRequestException.java new file mode 100644 index 00000000000..97b8ab38660 --- /dev/null +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/toolkit/client/common/exception/api/APITooManyRequestException.java @@ -0,0 +1,35 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.web.toolkit.client.common.exception.api; + +import lombok.Getter; +import org.bonitasoft.web.toolkit.client.common.i18n.T_; + +public class APITooManyRequestException extends APIException { + + private static final long serialVersionUID = 1820639344042666872L; + @Getter + private long retryAfter = -1L; + + public APITooManyRequestException(final T_ message, long retryAfter) { + super(message); + this.retryAfter = retryAfter; + setStatusCode(429); + } + + @Override + protected String defaultMessage() { + return getApi() + "#" + getResource() + ": Case creation limit reached."; + } +} diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/toolkit/client/common/json/JSonItemReader.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/toolkit/client/common/json/JSonItemReader.java index 8dc8078400b..5fe82b04bcb 100644 --- a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/toolkit/client/common/json/JSonItemReader.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/toolkit/client/common/json/JSonItemReader.java @@ -16,6 +16,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; import org.bonitasoft.web.toolkit.client.common.AbstractTreeNode; import org.bonitasoft.web.toolkit.client.common.Tree; @@ -117,7 +118,9 @@ private static E parseItem(final TreeIndexed tree, */ private static E parseItem(final TreeIndexed tree, final ItemDefinition itemDefinition, final boolean applyValidators) { - final E item = itemDefinition.createItem(); + final Optional discriminatedItem = itemDefinition.getDiscriminatedHelper() + .map(h -> h.findItemCreator(tree).get()); + final E item = discriminatedItem.orElseGet(itemDefinition::createItem); item.setApplyValidators(applyValidators); diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/toolkit/client/data/item/DiscriminatedItemDefinitionHelper.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/toolkit/client/data/item/DiscriminatedItemDefinitionHelper.java new file mode 100644 index 00000000000..381d4b9c655 --- /dev/null +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/toolkit/client/data/item/DiscriminatedItemDefinitionHelper.java @@ -0,0 +1,51 @@ +/** + * Copyright (C) 2022 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.web.toolkit.client.data.item; + +import java.util.Map; +import java.util.function.Supplier; + +import org.bonitasoft.web.rest.model.application.AbstractApplicationDefinition; +import org.bonitasoft.web.toolkit.client.common.TreeIndexed; + +/** + * This helps Items definitions which needs an attribute value to determine their concrete implementation. + * + * @see ItemDefinition#getDiscriminatedHelper() + * @see AbstractApplicationDefinition#getDiscriminatedHelper() for an example + * @param the {@link IItem} which is defined, same as in {@link ItemDefinition} + */ +public interface DiscriminatedItemDefinitionHelper { + + /** + * Find the appropriate creator with attributes to discriminate + * + * @param attributes the attributes for creation, one of which should be used to discriminate + * @return the item creator + */ + public Supplier findItemCreator(final Map attributes); + + /** + * Find the appropriate creator with properties tree to discriminate + * + * @param tree the tree of properties, one of which should be used to discriminate + * @return the item creator + */ + /* + * We could delegate to the attributes method with a default implementation, + * but it wouldn't be as effective as getting the direct value. + */ + public Supplier findItemCreator(final TreeIndexed tree); + +} diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/toolkit/client/data/item/ItemDefinition.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/toolkit/client/data/item/ItemDefinition.java index 434406cb7af..0c020e01e33 100644 --- a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/toolkit/client/data/item/ItemDefinition.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/toolkit/client/data/item/ItemDefinition.java @@ -19,6 +19,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import org.bonitasoft.web.toolkit.client.data.APIID; import org.bonitasoft.web.toolkit.client.data.item.attribute.ItemAttribute; @@ -231,6 +232,15 @@ public final Map> getValidators() { // AUTOMATICALY INSTANCIATE ITEM AND ITEM DEPENDENT TOOLS // /////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * This helps Items definitions which needs an attribute value to determine their concrete implementation. + * + * @return helper for discriminating and find the concrete implementation + */ + public Optional> getDiscriminatedHelper() { + return Optional.empty(); + } + /** * This function create a new empty Item * @@ -248,7 +258,8 @@ public final E createItem() { } public final E createItem(final Map attributes) throws ValidationException { - final E item = _createItem(); + final Optional discriminatedItem = getDiscriminatedHelper().map(h -> h.findItemCreator(attributes).get()); + final E item = discriminatedItem.orElseGet(this::_createItem); if (attributes != null) { item.setAttributes(attributes); diff --git a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/toolkit/server/servlet/ToolkitHttpServlet.java b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/toolkit/server/servlet/ToolkitHttpServlet.java index 07275b39d29..3b83e647f36 100644 --- a/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/toolkit/server/servlet/ToolkitHttpServlet.java +++ b/bpm/bonita-web-server/src/main/java/org/bonitasoft/web/toolkit/server/servlet/ToolkitHttpServlet.java @@ -15,6 +15,11 @@ import java.io.IOException; import java.io.PrintWriter; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Locale; +import java.util.Map; import javax.servlet.ServletException; import javax.servlet.ServletRequest; @@ -26,7 +31,14 @@ import org.bonitasoft.console.common.server.utils.LocaleUtils; import org.bonitasoft.web.rest.server.framework.json.JSonSimpleDeserializer; import org.bonitasoft.web.toolkit.client.common.CommonDateFormater; -import org.bonitasoft.web.toolkit.client.common.exception.api.*; +import org.bonitasoft.web.toolkit.client.common.exception.api.APIException; +import org.bonitasoft.web.toolkit.client.common.exception.api.APIForbiddenException; +import org.bonitasoft.web.toolkit.client.common.exception.api.APIIncorrectIdException; +import org.bonitasoft.web.toolkit.client.common.exception.api.APIItemIdMalformedException; +import org.bonitasoft.web.toolkit.client.common.exception.api.APIItemNotFoundException; +import org.bonitasoft.web.toolkit.client.common.exception.api.APIMethodNotAllowedException; +import org.bonitasoft.web.toolkit.client.common.exception.api.APINotFoundException; +import org.bonitasoft.web.toolkit.client.common.exception.api.APITooManyRequestException; import org.bonitasoft.web.toolkit.client.common.i18n.AbstractI18n.LOCALE; import org.bonitasoft.web.toolkit.client.common.json.JSonItemReader; import org.bonitasoft.web.toolkit.client.common.json.JSonSerializer; @@ -45,6 +57,10 @@ public abstract class ToolkitHttpServlet extends HttpServlet { private static final long serialVersionUID = -8470006030459575773L; + public static final DateTimeFormatter RFC1123_DATE_TIME_FORMATTER = DateTimeFormatter + .ofPattern("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US) + .withZone(ZoneId.of("GMT")); + /** * Console logger */ @@ -104,8 +120,8 @@ protected final void outputException(final Throwable e, final HttpServletRequest try { final PrintWriter output = resp.getWriter(); - if (e instanceof APIException) { - setLocalization((APIException) e, LocaleUtils.getUserLocaleAsString(req)); + if (e instanceof APIException apiException) { + setLocalization(apiException, LocaleUtils.getUserLocaleAsString(req)); } output.print(e == null ? "" : JSonSerializer.serialize(e)); @@ -115,6 +131,14 @@ protected final void outputException(final Throwable e, final HttpServletRequest } } + protected final void outputException(final Throwable e, final HttpServletRequest req, + final HttpServletResponse resp, final int httpStatusCode, Map headers) { + for (var header : headers.entrySet()) { + resp.addHeader(header.getKey(), header.getValue()); + } + outputException(e, req, resp, httpStatusCode); + } + /** * Output an exception in JSon. Expect the status code to be already set * @@ -161,12 +185,7 @@ protected void catchAllExceptions(final Throwable exception, final HttpServletRe LOGGER.info(exception.getMessage(), exception); } outputException(exception, req, resp, HttpServletResponse.SC_METHOD_NOT_ALLOWED); - } else if (exception instanceof APINotFoundException) { - if (LOGGER.isInfoEnabled()) { - LOGGER.info(exception.getMessage(), exception); - } - outputException(exception, req, resp, HttpServletResponse.SC_NOT_FOUND); - } else if (exception instanceof ServiceNotFoundException) { + } else if (exception instanceof APINotFoundException || exception instanceof ServiceNotFoundException) { if (LOGGER.isInfoEnabled()) { LOGGER.info(exception.getMessage(), exception); } @@ -194,6 +213,13 @@ protected void catchAllExceptions(final Throwable exception, final HttpServletRe LOGGER.debug(exception.getMessage(), exception); } outputException(exception, req, resp, HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } else if (exception instanceof APITooManyRequestException ex) { + if (LOGGER.isErrorEnabled()) { + LOGGER.error(exception.getMessage(), exception); + } + var headers = Map.of("Retry-After", + RFC1123_DATE_TIME_FORMATTER.format(Instant.ofEpochMilli(ex.getRetryAfter()))); + outputException(exception, req, resp, ex.getStatusCode(), headers); } else { if (LOGGER.isErrorEnabled()) { LOGGER.error(exception.getMessage(), exception); diff --git a/bpm/bonita-web-server/src/main/resources/i18n/portal-js_es.po b/bpm/bonita-web-server/src/main/resources/i18n/portal-js_es.po index 91b4b72c414..ac557c81e92 100644 --- a/bpm/bonita-web-server/src/main/resources/i18n/portal-js_es.po +++ b/bpm/bonita-web-server/src/main/resources/i18n/portal-js_es.po @@ -16,6 +16,12 @@ msgstr "" msgid "1 case has been deleted" msgstr "Se ha eliminado 1 caso" +msgid "A Link to your application made outside the portal, e.g. with Bonita UI Builder." +msgstr "Un enlace a su aplicación hecha fuera del portal, por ejemplo, con Bonita UI Builder." + +msgid "A classic Bonita Living Application." +msgstr "Una Bonita Living Application clásica." + msgid "A page with this name already exists." msgstr "Ya existe una página con este nombre." @@ -106,6 +112,9 @@ msgstr "Error al enviar el formulario.
    Puede ser que la tarea ya no esta dis msgid "An error occurred with the requested operation." msgstr "Ha ocurrido un error con la operación solicitada" +msgid "Application Link" +msgstr "Application Link" + msgid "Application XML file" msgstr "Archivo de la aplicación XML" @@ -523,6 +532,9 @@ msgstr "Última actualización" msgid "Layout" msgstr "Layout" +msgid "Legacy Application" +msgstr "Legacy Application" + msgid "Loading..." msgstr "Cargando…" @@ -856,6 +868,9 @@ msgstr "Ordenar por URL" msgid "Sort by name" msgstr "Ordenar por nombre" +msgid "Sort by type" +msgstr "Ordenar por tipo" + msgid "Sort by updated on" msgstr "Ordenar por actualizada el" @@ -997,6 +1012,12 @@ msgstr "Este es el panel de detalles de la tarea. No hay información para mostr msgid "This name is already in use" msgstr "Este nombre ya está en uso" +msgid "This only changes the application link. The application itself is still deployed at the same location." +msgstr "Esto sólo cambia el enlace de la aplicación. La aplicación misma está desplegada en la misma ubicación." + +msgid "This only deletes the application link. The application itself is not deleted and is still deployed." +msgstr "Esto sólo elimina el enlace de la aplicación. La aplicación en sí misma no se elimina y todavía está desplegada." + msgid "This process is no longer available." msgstr "Este proceso ya no está disponible." diff --git a/bpm/bonita-web-server/src/main/resources/i18n/portal-js_fr.po b/bpm/bonita-web-server/src/main/resources/i18n/portal-js_fr.po index 83e9e45281a..b9e4d679777 100644 --- a/bpm/bonita-web-server/src/main/resources/i18n/portal-js_fr.po +++ b/bpm/bonita-web-server/src/main/resources/i18n/portal-js_fr.po @@ -16,6 +16,12 @@ msgstr "" msgid "1 case has been deleted" msgstr "1 cas a été supprimé" +msgid "A Link to your application made outside the portal, e.g. with Bonita UI Builder." +msgstr "Un Lien vers votre application créée en dehors du portail, par exemple avec Bonita UI Builder." + +msgid "A classic Bonita Living Application." +msgstr "Une Living Application Bonita traditionnelle." + msgid "A page with this name already exists." msgstr "Une page portant ce nom existe déjà." @@ -107,6 +113,9 @@ msgstr "Une erreur s’est produite lors de l’envoi du formulaire.
    Il se msgid "An error occurred with the requested operation." msgstr "Une erreur s'est produite lors de l'opération demandée" +msgid "Application Link" +msgstr "Lien d'Application" + msgid "Application XML file" msgstr "Fichier XML de l'application" @@ -524,6 +533,9 @@ msgstr "Dernière mise à jour" msgid "Layout" msgstr "Layout" +msgid "Legacy Application" +msgstr "Application Traditionnelle" + msgid "Loading..." msgstr "Chargement..." @@ -857,6 +869,9 @@ msgstr "Trier par URL" msgid "Sort by name" msgstr "Trier par nom" +msgid "Sort by type" +msgstr "Trier par type" + msgid "Sort by updated on" msgstr "Trier par date de mise à jour" @@ -998,6 +1013,12 @@ msgstr "Cette zone est dédiée aux détails d'une tâche. Aucune information à msgid "This name is already in use" msgstr "Ce nom est déjà utilisé" +msgid "This only changes the application link. The application itself is still deployed at the same location." +msgstr "Cela ne modifie que le lien de l'application. L'application elle-même est toujours déployée au même endroit." + +msgid "This only deletes the application link. The application itself is not deleted and is still deployed." +msgstr "Ceci ne supprime que le lien de l'application. L'application elle-même n'est pas supprimée et est toujours déployée." + msgid "This process is no longer available." msgstr "Ce processus n'est plus disponible." diff --git a/bpm/bonita-web-server/src/main/resources/i18n/portal-js_ja.po b/bpm/bonita-web-server/src/main/resources/i18n/portal-js_ja.po index 6c9e29fed31..60ad31014b2 100644 --- a/bpm/bonita-web-server/src/main/resources/i18n/portal-js_ja.po +++ b/bpm/bonita-web-server/src/main/resources/i18n/portal-js_ja.po @@ -16,6 +16,12 @@ msgstr "" msgid "1 case has been deleted" msgstr "1 案件が削除されました" +msgid "A Link to your application made outside the portal, e.g. with Bonita UI Builder." +msgstr "" + +msgid "A classic Bonita Living Application." +msgstr "" + msgid "A page with this name already exists." msgstr "この名前のページは既に存在します。" @@ -107,6 +113,9 @@ msgstr "フォームの送信中にエラーが発生しました。
    この msgid "An error occurred with the requested operation." msgstr "要求された操作でエラーが発生しました。" +msgid "Application Link" +msgstr "" + msgid "Application XML file" msgstr "アプリケーションのXMLファイル" @@ -526,6 +535,9 @@ msgstr "最新更新日時" msgid "Layout" msgstr "レイアウト" +msgid "Legacy Application" +msgstr "" + msgid "Loading..." msgstr "ロード中..." @@ -859,6 +871,9 @@ msgstr "URL で並べ替え" msgid "Sort by name" msgstr "名前で並べ替え" +msgid "Sort by type" +msgstr "" + msgid "Sort by updated on" msgstr "更新日で並べ替え" @@ -1000,6 +1015,12 @@ msgstr "これは、タスクの詳細パネルです。表示する情報があ msgid "This name is already in use" msgstr "この名前は既に使用中" +msgid "This only changes the application link. The application itself is still deployed at the same location." +msgstr "" + +msgid "This only deletes the application link. The application itself is not deleted and is still deployed." +msgstr "" + msgid "This process is no longer available." msgstr "このプロセスは既に使用できません。" diff --git a/bpm/bonita-web-server/src/main/resources/i18n/portal-js_pt_BR.po b/bpm/bonita-web-server/src/main/resources/i18n/portal-js_pt_BR.po index 35bc3348eb2..14677629a7b 100644 --- a/bpm/bonita-web-server/src/main/resources/i18n/portal-js_pt_BR.po +++ b/bpm/bonita-web-server/src/main/resources/i18n/portal-js_pt_BR.po @@ -16,6 +16,12 @@ msgstr "" msgid "1 case has been deleted" msgstr "1 caso foi excluído" +msgid "A Link to your application made outside the portal, e.g. with Bonita UI Builder." +msgstr "" + +msgid "A classic Bonita Living Application." +msgstr "" + msgid "A page with this name already exists." msgstr "Já existe uma página com esse nome." @@ -106,6 +112,9 @@ msgstr "Ocorreu um erro ao enviar o formulário.
    A tarefa pode não estar msgid "An error occurred with the requested operation." msgstr "Ocorreu um erro com a operação solicitada" +msgid "Application Link" +msgstr "" + msgid "Application XML file" msgstr "Arquivo XML do aplicativo" @@ -523,6 +532,9 @@ msgstr "Última atualização" msgid "Layout" msgstr "Layout" +msgid "Legacy Application" +msgstr "" + msgid "Loading..." msgstr "Carregando..." @@ -856,6 +868,9 @@ msgstr "Ordenar pela URL" msgid "Sort by name" msgstr "Ordenar por nome" +msgid "Sort by type" +msgstr "" + msgid "Sort by updated on" msgstr "Ordenar pela data de atualização" @@ -997,6 +1012,12 @@ msgstr "Este é o painel de detalhes de tarefa. Nenhuma informação para exibir msgid "This name is already in use" msgstr "Este nome já está em uso" +msgid "This only changes the application link. The application itself is still deployed at the same location." +msgstr "" + +msgid "This only deletes the application link. The application itself is not deleted and is still deployed." +msgstr "" + msgid "This process is no longer available." msgstr "Este processo não está mais disponível." diff --git a/bpm/bonita-web-server/src/main/resources/i18n/portal_es.po b/bpm/bonita-web-server/src/main/resources/i18n/portal_es.po index ef6bce1d071..e5d89c19c12 100644 --- a/bpm/bonita-web-server/src/main/resources/i18n/portal_es.po +++ b/bpm/bonita-web-server/src/main/resources/i18n/portal_es.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: bonita\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-04-01 14:32+0000\n" +"POT-Creation-Date: 2024-10-16 11:55+0000\n" "PO-Revision-Date: 2024-01-01 00:00\n" "Last-Translator: \n" "Language-Team: Spanish\n" @@ -125,9 +125,12 @@ msgstr "La definición de dato %dataName% no existe para el proceso %processId%" msgid "Error during Application import file reading." msgstr "Error durante la lectura del archivo de importación de la aplicación." -msgid "Error occured when starting process %processId%" +msgid "Error occurred when starting process %processId%" msgstr "Ha ocurrido un error al iniciar el proceso %processId%" +msgid "Error occurred when starting process %processId%. Case creation limit reached." +msgstr "Ocurrió un error al iniciar el proceso %processId%. Se alcanzó el límite de creación de casos." + msgid "Error uploading the file. Maybe your session expired. You can try to refresh the page." msgstr "Error subiendo el fichero. Posiblemente su sesión ha expirado. Puede probar a refrescar la página." diff --git a/bpm/bonita-web-server/src/main/resources/i18n/portal_fr.po b/bpm/bonita-web-server/src/main/resources/i18n/portal_fr.po index b09048db34f..18b2c6db2c1 100644 --- a/bpm/bonita-web-server/src/main/resources/i18n/portal_fr.po +++ b/bpm/bonita-web-server/src/main/resources/i18n/portal_fr.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: bonita\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-04-01 14:32+0000\n" +"POT-Creation-Date: 2024-10-16 11:55+0000\n" "PO-Revision-Date: 2024-01-01 00:00\n" "Last-Translator: \n" "Language-Team: French\n" @@ -125,9 +125,12 @@ msgstr "Data definition %dataName% n'existe pas pour le process %processId%" msgid "Error during Application import file reading." msgstr "Erreur lors de l'importation de l'Application." -msgid "Error occured when starting process %processId%" +msgid "Error occurred when starting process %processId%" msgstr "Une erreur s'est produite au démarrage du processus %processId%" +msgid "Error occurred when starting process %processId%. Case creation limit reached." +msgstr "Une erreur s'est produite lors du démarrage du processus %processId%. La limite de création de cas a été atteinte." + msgid "Error uploading the file. Maybe your session expired. You can try to refresh the page." msgstr "Une erreur est survenue lors du chargement du fichier. Votre session a peut-être expiré. Essayez de rafraîchir la page." diff --git a/bpm/bonita-web-server/src/main/resources/i18n/portal_ja.po b/bpm/bonita-web-server/src/main/resources/i18n/portal_ja.po index 355be74fb94..9e8f89ae996 100644 --- a/bpm/bonita-web-server/src/main/resources/i18n/portal_ja.po +++ b/bpm/bonita-web-server/src/main/resources/i18n/portal_ja.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: bonita\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-04-01 14:32+0000\n" +"POT-Creation-Date: 2024-10-16 11:55+0000\n" "PO-Revision-Date: 2024-01-01 00:00\n" "Last-Translator: \n" "Language-Team: Japanese\n" @@ -125,9 +125,12 @@ msgstr "データ定義:%dataName% は、プロセス:%processId% に存在 msgid "Error during Application import file reading." msgstr "アプリケーションのインポート ファイルの読み取り中にエラーが発生しました。" -msgid "Error occured when starting process %processId%" +msgid "Error occurred when starting process %processId%" msgstr "プロセス:%processId% の開始時にエラーが発生しました" +msgid "Error occurred when starting process %processId%. Case creation limit reached." +msgstr "プロセス %processId%の開始時にエラーが発生しました。ケース作成の上限に達しました。" + msgid "Error uploading the file. Maybe your session expired. You can try to refresh the page." msgstr "ファイルのアップロード中にエラーが発生しました。セッションの有効期限が切れた可能性があります。ページを更新してみてください。" diff --git a/bpm/bonita-web-server/src/main/resources/i18n/portal_pt_BR.po b/bpm/bonita-web-server/src/main/resources/i18n/portal_pt_BR.po index 84477db031c..dd14d65fc5d 100644 --- a/bpm/bonita-web-server/src/main/resources/i18n/portal_pt_BR.po +++ b/bpm/bonita-web-server/src/main/resources/i18n/portal_pt_BR.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: bonita\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-04-01 14:32+0000\n" +"POT-Creation-Date: 2024-10-16 11:55+0000\n" "PO-Revision-Date: 2024-01-01 00:00\n" "Last-Translator: \n" "Language-Team: Portuguese, Brazilian\n" @@ -125,9 +125,12 @@ msgstr "Definição do dado %dataName% não existe para o processo %processId%" msgid "Error during Application import file reading." msgstr "Erro na leitura do arquivo de importação de aplicações." -msgid "Error occured when starting process %processId%" +msgid "Error occurred when starting process %processId%" msgstr "Ocorreu um erro ao iniciar o processo %processId%" +msgid "Error occurred when starting process %processId%. Case creation limit reached." +msgstr "Ocorreu um erro ao iniciar o processo %processId%. Limite de criação de casos atingido." + msgid "Error uploading the file. Maybe your session expired. You can try to refresh the page." msgstr "Erro ao carregar o arquivo. Talvez sua sessão tenha expirado. Você pode tentar atualizar a página." diff --git a/bpm/bonita-web-server/src/main/webapp/WEB-INF/web.xml b/bpm/bonita-web-server/src/main/webapp/WEB-INF/web.xml index 4b72250ea7a..7df83a1a9d7 100644 --- a/bpm/bonita-web-server/src/main/webapp/WEB-INF/web.xml +++ b/bpm/bonita-web-server/src/main/webapp/WEB-INF/web.xml @@ -126,6 +126,11 @@ true + + + RedirectFilter + org.bonitasoft.console.common.server.filter.RedirectFilter + SanitizerFilter @@ -238,6 +243,12 @@ REQUEST FORWARD + + RedirectFilter + /apps/sendRedirect + REQUEST + FORWARD + RestAPIAuthorizationFilter /API/* @@ -731,6 +742,7 @@ /API/system/maintenance /API/bpm/processInfo/* + /API/system/information ConsoleServiceServlet diff --git a/bpm/bonita-web-server/src/test/java/org/bonitasoft/console/common/server/filter/RedirectFilterTest.java b/bpm/bonita-web-server/src/test/java/org/bonitasoft/console/common/server/filter/RedirectFilterTest.java new file mode 100644 index 00000000000..b4fc57620cd --- /dev/null +++ b/bpm/bonita-web-server/src/test/java/org/bonitasoft/console/common/server/filter/RedirectFilterTest.java @@ -0,0 +1,93 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.console.common.server.filter; + +import static org.mockito.Mockito.*; + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +public class RedirectFilterTest { + + @Mock + private HttpServletRequest httpRequest; + + @Mock + private HttpServletResponse httpResponse; + + @Mock + private FilterChain filterChain; + + private RedirectFilter redirectFilter; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + redirectFilter = new RedirectFilter(); + } + + @Test + public void testDoFilterWithInternalRedirect() throws IOException, ServletException { + when(httpRequest.getParameter("redirectUrl")).thenReturn("/redirectLink"); + when(httpRequest.getRequestURL()).thenReturn(new StringBuffer("http://bonita:8080/currentPath")); + when(httpRequest.getRequestURI()).thenReturn("/currentPath"); + + redirectFilter.doFilter(httpRequest, httpResponse, filterChain); + + verify(httpResponse).sendRedirect("/redirectLink"); + verify(filterChain, never()).doFilter(httpRequest, httpResponse); + } + + @Test + public void testDoFilterWithExternalRedirect() throws IOException, ServletException { + // using http:// as a prefix to simulate an external redirect + when(httpRequest.getParameter("redirectUrl")).thenReturn("http://external:9090/redirectLink"); + when(httpRequest.getRequestURL()).thenReturn(new StringBuffer("http://bonita:8080/currentPath")); + when(httpRequest.getRequestURI()).thenReturn("/currentPath"); + + redirectFilter.doFilter(httpRequest, httpResponse, filterChain); + + verify(httpResponse, never()).sendRedirect(anyString()); + verify(filterChain).doFilter(httpRequest, httpResponse); + + // using // as a prefix to simulate an external redirect + when(httpRequest.getParameter("redirectUrl")).thenReturn("//external:9090/redirectLink"); + when(httpRequest.getRequestURL()).thenReturn(new StringBuffer("http://bonita:8080/currentPath")); + when(httpRequest.getRequestURI()).thenReturn("/currentPath"); + + redirectFilter.doFilter(httpRequest, httpResponse, filterChain); + + verify(httpResponse, never()).sendRedirect(anyString()); + verify(filterChain, times(2)).doFilter(httpRequest, httpResponse); + } + + @Test + public void testDoFilterWithoutRedirect() throws IOException, ServletException { + when(httpRequest.getParameter("redirectUrl")).thenReturn(null); + + redirectFilter.doFilter(httpRequest, httpResponse, filterChain); + + verify(httpResponse, never()).sendRedirect(anyString()); + verify(filterChain).doFilter(httpRequest, httpResponse); + } +} diff --git a/bpm/bonita-web-server/src/test/java/org/bonitasoft/console/common/server/login/filter/AuthenticationFilterTest.java b/bpm/bonita-web-server/src/test/java/org/bonitasoft/console/common/server/login/filter/AuthenticationFilterTest.java index e3a96523538..bfe35503d92 100644 --- a/bpm/bonita-web-server/src/test/java/org/bonitasoft/console/common/server/login/filter/AuthenticationFilterTest.java +++ b/bpm/bonita-web-server/src/test/java/org/bonitasoft/console/common/server/login/filter/AuthenticationFilterTest.java @@ -371,6 +371,14 @@ public void testMakeRedirectUrl() { assertThat(redirectUrl.getUrl()).isEqualToIgnoringCase("/apps/appDirectoryBonita"); } + @Test + public void testMakeRedirectUrlWithRedirectUrlIncluded() { + when(httpRequest.getRequestURI()).thenReturn("/apps/appDirectoryBonita"); + when(request.getRedirectUrl()).thenReturn("/redirectLink"); + final RedirectUrl redirectUrl = authenticationFilter.makeRedirectUrl(request); + assertThat(redirectUrl.getUrl()).isEqualToIgnoringCase("/redirectLink"); + } + @Test public void testCompileNullPattern() { assertThat(authenticationFilter.compilePattern(null)).isNull(); diff --git a/bpm/bonita-web-server/src/test/java/org/bonitasoft/console/common/server/login/filter/RestAPIAuthorizationFilterTest.java b/bpm/bonita-web-server/src/test/java/org/bonitasoft/console/common/server/login/filter/RestAPIAuthorizationFilterTest.java index 3c91be27e10..d0bb32b365c 100644 --- a/bpm/bonita-web-server/src/test/java/org/bonitasoft/console/common/server/login/filter/RestAPIAuthorizationFilterTest.java +++ b/bpm/bonita-web-server/src/test/java/org/bonitasoft/console/common/server/login/filter/RestAPIAuthorizationFilterTest.java @@ -281,7 +281,7 @@ public void testFilterWithExcludedURL() throws Exception { } @Test - public void testMatchExcludePatterns() throws Exception { + public void testMatchExcludePatterns() { matchExcludePattern("http://host/bonita/portal/resource/page/API/system/i18ntranslation", true); matchExcludePattern("http://host/bonita/apps/app/API/system/i18ntranslation", true); matchExcludePattern("http://host/bonita/API/system/i18ntranslation", true); @@ -294,17 +294,17 @@ public void testMatchExcludePatterns() throws Exception { } @Test - public void testCompileNullPattern() throws Exception { + public void testCompileNullPattern() { assertThat(restAPIAuthorizationFilter.compilePattern(null)).isNull(); } @Test - public void testCompileWrongPattern() throws Exception { + public void testCompileWrongPattern() { assertThat(restAPIAuthorizationFilter.compilePattern("((((")).isNull(); } @Test - public void testCompileSimplePattern() throws Exception { + public void testCompileSimplePattern() { final String patternToCompile = "test"; assertThat(restAPIAuthorizationFilter.compilePattern(patternToCompile)).isNotNull().has(new Condition<>() { @@ -316,7 +316,7 @@ public boolean matches(final Pattern pattern) { } @Test - public void testCompileExcludePattern() throws Exception { + public void testCompileExcludePattern() { final String patternToCompile = RestAPIAuthorizationFilter.AUTHORIZATION_FILTER_EXCLUDED_PAGES_PATTERN; assertThat(restAPIAuthorizationFilter.compilePattern(patternToCompile)).isNotNull().has(new Condition<>() { diff --git a/bpm/bonita-web-server/src/test/java/org/bonitasoft/console/common/server/page/CustomPageAuthorizationsHelperTest.java b/bpm/bonita-web-server/src/test/java/org/bonitasoft/console/common/server/page/CustomPageAuthorizationsHelperTest.java index 6b61c3d7f76..027c786039c 100644 --- a/bpm/bonita-web-server/src/test/java/org/bonitasoft/console/common/server/page/CustomPageAuthorizationsHelperTest.java +++ b/bpm/bonita-web-server/src/test/java/org/bonitasoft/console/common/server/page/CustomPageAuthorizationsHelperTest.java @@ -16,7 +16,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import java.util.Arrays; import java.util.Collections; @@ -72,7 +74,7 @@ public void should_authorize_page_when_appToken_not_null_and_page_authorized_in_ 0, 0, "", ContentType.PAGE, null)); given(applicationAPI.searchApplicationPages(any())) .willReturn(new SearchResultImpl<>(1, Collections. emptyList())); - given(applicationAPI.searchApplications(any())) + given(applicationAPI.searchIApplications(any())) .willReturn(applicationResult); given(applicationResult.getResult()).willReturn(Arrays.asList(application)); @@ -102,7 +104,7 @@ public void should_authorize_page_when_appToken_not_null_and_page_authorized_in_ public void should_unAuthorize_page_when_appToken_not_null_and_page_not_authorized_in_application() throws Exception { - given(applicationAPI.searchApplications(any())) + given(applicationAPI.searchIApplications(any())) .willReturn(applicationResult); given(applicationResult.getResult()).willReturn(Arrays.asList(application)); given(applicationFactory.createApplicationModel(any(String.class))).willReturn(applicationModel); diff --git a/bpm/bonita-web-server/src/test/java/org/bonitasoft/livingapps/ApplicationModelFactoryTest.java b/bpm/bonita-web-server/src/test/java/org/bonitasoft/livingapps/ApplicationModelFactoryTest.java index 5fc9c1a798f..57afb6cd20e 100644 --- a/bpm/bonita-web-server/src/test/java/org/bonitasoft/livingapps/ApplicationModelFactoryTest.java +++ b/bpm/bonita-web-server/src/test/java/org/bonitasoft/livingapps/ApplicationModelFactoryTest.java @@ -24,6 +24,8 @@ import org.bonitasoft.engine.api.ApplicationAPI; import org.bonitasoft.engine.business.application.Application; +import org.bonitasoft.engine.business.application.ApplicationLink; +import org.bonitasoft.engine.business.application.IApplication; import org.bonitasoft.engine.business.application.impl.ApplicationImpl; import org.bonitasoft.engine.business.application.impl.ApplicationPageImpl; import org.bonitasoft.engine.exception.SearchException; @@ -50,15 +52,23 @@ public class ApplicationModelFactoryTest { @Test(expected = CreationException.class) public void should_throw_create_error_exception_when_search_fail() throws Exception { - given(applicationApi.searchApplications(any(SearchOptions.class))).willThrow(SearchException.class); + given(applicationApi.searchIApplications(any(SearchOptions.class))).willThrow(SearchException.class); factory.createApplicationModel("foo"); } @Test(expected = CreationException.class) public void should_throw_create_error_exception_when_application_is_not_found() throws Exception { - given(applicationApi.searchApplications(any(SearchOptions.class))).willReturn( - new SearchResultImpl<>(0, Collections. emptyList())); + given(applicationApi.searchIApplications(any(SearchOptions.class))).willReturn( + new SearchResultImpl<>(1, asList(mock(ApplicationLink.class)))); + + factory.createApplicationModel("foo"); + } + + @Test(expected = CreationException.class) + public void should_throw_create_error_exception_when_only_application_link_is_found() throws Exception { + given(applicationApi.searchIApplications(any(SearchOptions.class))).willReturn( + new SearchResultImpl<>(0, Collections. emptyList())); factory.createApplicationModel("foo"); } @@ -67,8 +77,8 @@ public void should_throw_create_error_exception_when_application_is_not_found() public void should_return_application_found() throws Exception { final ApplicationImpl application = new ApplicationImpl("foobar", "1.0", "bazqux"); application.setId(3); - given(applicationApi.searchApplications(any(SearchOptions.class))).willReturn( - new SearchResultImpl<>(1, asList((Application) application))); + given(applicationApi.searchIApplications(any(SearchOptions.class))).willReturn( + new SearchResultImpl<>(1, asList((IApplication) application))); given(applicationApi.getApplicationHomePage(3)).willReturn(new ApplicationPageImpl(1, 1, "home")); final ApplicationModel model = factory.createApplicationModel("foo"); @@ -79,11 +89,11 @@ public void should_return_application_found() throws Exception { @Test public void should_filter_search_using_given_name() throws Exception { final ArgumentCaptor captor = ArgumentCaptor.forClass(SearchOptions.class); - given(applicationApi.searchApplications(any(SearchOptions.class))).willReturn( + given(applicationApi.searchIApplications(any(SearchOptions.class))).willReturn( new SearchResultImpl<>(1, asList(mock(Application.class)))); factory.createApplicationModel("bar"); - verify(applicationApi).searchApplications(captor.capture()); + verify(applicationApi).searchIApplications(captor.capture()); final SearchFilter filter = captor.getValue().getFilters().get(0); assertThat(filter.getField()).isEqualTo("token"); diff --git a/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/model/ModelFactoryExtTest.java b/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/model/ModelFactoryExtTest.java index 1ad6b2211cb..d3d88f4fb7d 100755 --- a/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/model/ModelFactoryExtTest.java +++ b/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/model/ModelFactoryExtTest.java @@ -16,6 +16,7 @@ import static org.assertj.core.api.Assertions.assertThat; import org.bonitasoft.web.rest.model.application.ApplicationDefinition; +import org.bonitasoft.web.rest.model.application.ApplicationLinkDefinition; import org.bonitasoft.web.rest.model.applicationpage.ApplicationPageDefinition; import org.bonitasoft.web.toolkit.client.data.item.ItemDefinition; import org.junit.Test; @@ -24,6 +25,17 @@ public class ModelFactoryExtTest { private final ModelFactory factory = new ModelFactory(); + @Test + public void defineItemDefinitions_should_return_instanceOf_ApplicationLinkDefinition_for_applicationLink_token() + throws Exception { + //when + final ItemDefinition definition = factory.defineItemDefinitions(ApplicationLinkDefinition.TOKEN); + + //then + assertThat(definition).isNotNull(); + assertThat(definition).isInstanceOf(ApplicationLinkDefinition.class); + } + @Test public void defineItemDefinitions_should_return_instanceOf_ApplicationDefinition_for_application_token() throws Exception { diff --git a/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/server/api/application/APIApplicationTest.java b/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/server/api/application/APIApplicationTest.java index b3fa79c2f82..450ed8e592f 100644 --- a/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/server/api/application/APIApplicationTest.java +++ b/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/server/api/application/APIApplicationTest.java @@ -25,8 +25,10 @@ import org.bonitasoft.engine.session.APISession; import org.bonitasoft.web.rest.model.ModelFactory; -import org.bonitasoft.web.rest.model.application.ApplicationDefinition; +import org.bonitasoft.web.rest.model.application.AbstractApplicationDefinition; +import org.bonitasoft.web.rest.model.application.AbstractApplicationItem; import org.bonitasoft.web.rest.model.application.ApplicationItem; +import org.bonitasoft.web.rest.model.application.ApplicationLinkItem; import org.bonitasoft.web.rest.model.portal.profile.ProfileItem; import org.bonitasoft.web.rest.server.api.applicationpage.APIApplicationDataStoreFactory; import org.bonitasoft.web.rest.server.api.deployer.DeployerFactory; @@ -40,6 +42,7 @@ import org.bonitasoft.web.rest.server.framework.Deployer; import org.bonitasoft.web.rest.server.framework.search.ItemSearchResult; import org.bonitasoft.web.toolkit.client.ItemDefinitionFactory; +import org.bonitasoft.web.toolkit.client.data.APIID; import org.bonitasoft.web.toolkit.client.data.item.ItemDefinition; import org.junit.Before; import org.junit.Test; @@ -95,14 +98,26 @@ public void setUp() throws Exception { } @Test - public void add_should_return_the_result_of_dataStore_add() throws Exception { + public void add_legacy_should_return_the_result_of_dataStore_add() throws Exception { //given final ApplicationItem itemToCreate = mock(ApplicationItem.class); final ApplicationItem createdItem = mock(ApplicationItem.class); - given(dataStore.add(itemToCreate)).willReturn(createdItem); - given(dataStore.add(itemToCreate)).willReturn(createdItem); + given(dataStore.add((AbstractApplicationItem) itemToCreate)).willReturn(createdItem); //when - final ApplicationItem retrievedItem = apiApplication.add(itemToCreate); + final ApplicationItem retrievedItem = (ApplicationItem) apiApplication.add(itemToCreate); + + //then + assertThat(retrievedItem).isEqualTo(createdItem); + } + + @Test + public void add_link_should_return_the_result_of_dataStore_add() throws Exception { + //given + final ApplicationLinkItem itemToCreate = mock(ApplicationLinkItem.class); + final ApplicationLinkItem createdItem = mock(ApplicationLinkItem.class); + given(dataStore.add((AbstractApplicationItem) itemToCreate)).willReturn(createdItem); + //when + final ApplicationLinkItem retrievedItem = (ApplicationLinkItem) apiApplication.add(itemToCreate); //then assertThat(retrievedItem).isEqualTo(createdItem); @@ -112,11 +127,12 @@ public void add_should_return_the_result_of_dataStore_add() throws Exception { public void search_should_return_the_result_of_dataStore_search() throws Exception { //given @SuppressWarnings("unchecked") - final ItemSearchResult result = mock(ItemSearchResult.class); + final ItemSearchResult result = mock(ItemSearchResult.class); given(dataStore.search(0, 10, "request", "default", Collections.singletonMap("name", "hr"))).willReturn(result); //when - final ItemSearchResult retrievedResult = apiApplication.search(0, 10, "request", "default", + final ItemSearchResult retrievedResult = apiApplication.search(0, 10, "request", + "default", Collections.singletonMap("name", "hr")); //then @@ -133,12 +149,12 @@ public void defineDefaultSearchOrder_should_return_attribute_name() throws Excep } @Test - public void defineItemDefinition_return_an_instance_of_ApplicationDefinition() throws Exception { + public void defineItemDefinition_return_an_instance_of_AbstractApplicationDefinition() throws Exception { //when - final ItemDefinition itemDefinition = apiApplication.defineItemDefinition(); + final ItemDefinition itemDefinition = apiApplication.defineItemDefinition(); //then - assertThat(itemDefinition).isExactlyInstanceOf(ApplicationDefinition.class); + assertThat(itemDefinition).isExactlyInstanceOf(AbstractApplicationDefinition.class); } @Test @@ -162,4 +178,19 @@ public void fillDeploys_should_add_deployers_for_createdBy_updatedBy_ProfileId_a assertThat(deployers.get(ApplicationItem.ATTRIBUTE_THEME_ID)).isExactlyInstanceOf(PageDeployer.class); } + @Test + public void update_should_return_the_appropriate_application_kind() throws Exception { + //given + final APIID idToUpdate = mock(APIID.class); + final ApplicationItem updatedItem = mock(ApplicationItem.class); + Map attributes = Collections.emptyMap(); + given(dataStore.update(idToUpdate, attributes)).willReturn(updatedItem); + + //when + final AbstractApplicationItem retrievedItem = apiApplication.update(idToUpdate, attributes); + + //then + assertThat(retrievedItem).isEqualTo(updatedItem); + } + } diff --git a/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/server/api/bpm/process/ProcessInstantiationResourceTest.java b/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/server/api/bpm/process/ProcessInstantiationResourceTest.java index 0e50f34c079..a5382c4e364 100644 --- a/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/server/api/bpm/process/ProcessInstantiationResourceTest.java +++ b/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/server/api/bpm/process/ProcessInstantiationResourceTest.java @@ -24,6 +24,7 @@ import java.io.Serializable; import java.util.Arrays; import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -156,7 +157,7 @@ public void should_instanciate_a_process_with_given_inputs_for_a_specific_user() } @Test - public void should_respond_400_Bad_request_when_contract_is_not_validated_when_instanciate_a_process() + public void should_respond_400_Bad_request_when_contract_is_not_validated_when_instantiate_a_process() throws Exception { doThrow(new ContractViolationException("aMessage", "aMessage", asList("first explanation", "second explanation"), null)) @@ -165,15 +166,15 @@ public void should_respond_400_Bad_request_when_contract_is_not_validated_when_i final Response response = request(URL_API_PROCESS_INSTANTIATION_TEST).post(VALID_POST_BODY); - assertThat(response).hasStatus(Status.CLIENT_ERROR_BAD_REQUEST); assertThat(response) + .hasStatus(Status.CLIENT_ERROR_BAD_REQUEST) .hasJsonEntityEqualTo( "{\"exception\":\"class org.bonitasoft.engine.bpm.contract.ContractViolationException\",\"message\":\"aMessage\",\"explanations\":[\"first explanation\",\"second explanation\"]}"); verify(processInstantiationResource.typeConverterUtil, times(0)).deleteTemporaryFiles(anyMap()); } @Test - public void should_respond_500_Internal_server_error_when_error_occurs_on_process_instanciation() throws Exception { + public void should_respond_500_Internal_server_error_when_error_occurs_on_process_instantiation() throws Exception { doThrow(new ProcessExecutionException("aMessage")) .when(processAPI).startProcessWithInputs(anyLong(), anyMap()); @@ -185,6 +186,21 @@ public void should_respond_500_Internal_server_error_when_error_occurs_on_proces verify(processInstantiationResource.typeConverterUtil, times(0)).deleteTemporaryFiles(anyMap()); } + @Test + public void should_respond_429_Too_Many_Requests_when_case_creation_limit_reached() throws Exception { + var retryAfter = new Date(); + doThrow(new ProcessExecutionException(new RuntimeException("aMessage"), retryAfter.getTime())) + .when(processAPI).startProcessWithInputs(anyLong(), anyMap()); + + final Response response = request(URL_API_PROCESS_INSTANTIATION_TEST).post(VALID_POST_BODY); + + assertThat(response).hasStatus(Status.CLIENT_ERROR_TOO_MANY_REQUESTS); + assertThat(response.getRetryAfter()).isInSameSecondAs(retryAfter); + assertThat(response.getEntityAsText()) + .contains("Case creation limit reached.") + .contains("Unable to start the process with ID"); + } + @Test public void should_respond_400_Bad_request_when_trying_to_execute_with_not_json_payload() throws Exception { final Response response = request(URL_API_PROCESS_INSTANTIATION_TEST).post("invalid json string"); @@ -262,4 +278,5 @@ public void should_getProcessDefinitionIdParameter_throws_an_exception_when_task } } + } diff --git a/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/server/api/platform/SystemInformationControllerTest.java b/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/server/api/platform/SystemInformationControllerTest.java new file mode 100644 index 00000000000..9148591d4e2 --- /dev/null +++ b/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/server/api/platform/SystemInformationControllerTest.java @@ -0,0 +1,58 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.web.rest.server.api.platform; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +import java.util.Map; + +import javax.servlet.http.HttpSession; + +import org.bonitasoft.engine.api.platform.PlatformInformationAPI; +import org.bonitasoft.engine.session.APISession; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class SystemInformationControllerTest { + + @Mock + private PlatformInformationAPI platformInformationAPI; + + @Spy + private SystemInformationController systemInformationController; + + @Test + void get_platform_information_should_return_raw_value_from_Engine() throws Exception { + //given + APISession apiSession = mock(APISession.class); + final HttpSession httpSession = mock(HttpSession.class); + doReturn(apiSession).when(systemInformationController).getApiSession(httpSession); + doReturn(platformInformationAPI).when(systemInformationController).getPlatformInformationAPI(apiSession); + final Map expectedInfo = Map.of("key", "value"); + doReturn(expectedInfo).when(platformInformationAPI).getPlatformInformation(); + + //when + final Map platformInfo = systemInformationController.getPlatformInfo(httpSession); + + //then + assertThat(platformInfo).isEqualTo(expectedInfo); + } + +} diff --git a/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationDataStoreTest.java b/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationDataStoreTest.java index 03389bdbe9b..b8eb64b8a93 100644 --- a/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationDataStoreTest.java +++ b/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationDataStoreTest.java @@ -14,9 +14,14 @@ package org.bonitasoft.web.rest.server.datastore.application; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import java.util.Arrays; import java.util.Collections; @@ -25,8 +30,16 @@ import org.bonitasoft.engine.api.ApplicationAPI; import org.bonitasoft.engine.api.PageAPI; -import org.bonitasoft.engine.business.application.*; +import org.bonitasoft.engine.business.application.ApplicationCreator; +import org.bonitasoft.engine.business.application.ApplicationLinkCreator; +import org.bonitasoft.engine.business.application.ApplicationLinkUpdater; +import org.bonitasoft.engine.business.application.ApplicationNotFoundException; +import org.bonitasoft.engine.business.application.ApplicationPage; +import org.bonitasoft.engine.business.application.ApplicationUpdater; +import org.bonitasoft.engine.business.application.ApplicationVisibility; +import org.bonitasoft.engine.business.application.IApplication; import org.bonitasoft.engine.business.application.impl.ApplicationImpl; +import org.bonitasoft.engine.business.application.impl.ApplicationLinkImpl; import org.bonitasoft.engine.exception.CreationException; import org.bonitasoft.engine.exception.DeletionException; import org.bonitasoft.engine.exception.SearchException; @@ -35,8 +48,10 @@ import org.bonitasoft.engine.search.Order; import org.bonitasoft.engine.search.SearchOptions; import org.bonitasoft.engine.search.impl.SearchResultImpl; +import org.bonitasoft.web.rest.model.application.AbstractApplicationItem; import org.bonitasoft.web.rest.model.application.ApplicationDefinition; import org.bonitasoft.web.rest.model.application.ApplicationItem; +import org.bonitasoft.web.rest.model.application.ApplicationLinkItem; import org.bonitasoft.web.rest.server.APITestWithMock; import org.bonitasoft.web.rest.server.framework.search.ItemSearchResult; import org.bonitasoft.web.toolkit.client.ItemDefinitionFactory; @@ -107,6 +122,25 @@ public void should_return_application_created_by_ApplicationAPI_converted_to_App assertThat(createdItem).isEqualTo(item); } + @Test + public void should_return_application_link_created_by_ApplicationAPI_converted_to_ApplicationLinkItem_on_add() + throws Exception { + //given + final ApplicationLinkCreator creator = new ApplicationLinkCreator("app", "My application", "1.0"); + ApplicationLinkItem app = new ApplicationLinkItem(); + given(converter.toApplicationLinkCreator(app)).willReturn(creator); + final ApplicationLinkImpl application = new ApplicationLinkImpl("app", "1.0", "app desc"); + given(applicationAPI.createApplicationLink(creator)).willReturn(application); + final ApplicationLinkItem item = new ApplicationLinkItem(); + given(converter.toApplicationItem(application)).willReturn(item); + + //when + final ApplicationLinkItem createdItem = dataStore.add(new ApplicationLinkItem()); + + //then + assertThat(createdItem).isEqualTo(item); + } + @Test public void should_create_default_home_page_on_add() throws Exception { //given @@ -142,11 +176,12 @@ public void should_return_application_updated_by_ApplicationAPI_converted_to_App final ApplicationImpl application = new ApplicationImpl("app", "1.0", "app desc", 2L, 3L); given(applicationAPI.updateApplication(1, applicationUpdater)).willReturn(application); + given(applicationAPI.getIApplication(1)).willReturn(application); final ApplicationItem item = new ApplicationItem(); given(converter.toApplicationItem(application)).willReturn(item); //when - final ApplicationItem createdItem = dataStore.update(APIID.makeAPIID(1L), attributesToUpDate); + final ApplicationItem createdItem = (ApplicationItem) dataStore.update(APIID.makeAPIID(1L), attributesToUpDate); //then verify(converter, times(1)).toApplicationUpdater(attributesToUpDate); @@ -155,6 +190,33 @@ public void should_return_application_updated_by_ApplicationAPI_converted_to_App assertThat(createdItem).isEqualTo(new ApplicationItem()); } + @Test + public void should_return_application_link_updated_by_ApplicationAPI_converted_to_ApplicationLinkItem_on_update() + throws Exception { + //given + final HashMap attributesToUpDate = new HashMap<>(); + attributesToUpDate.put(ApplicationLinkItem.ATTRIBUTE_TOKEN, "app_name"); + attributesToUpDate.put(ApplicationLinkItem.ATTRIBUTE_DISPLAY_NAME, "App display name"); + final ApplicationLinkUpdater applicationUpdater = new ApplicationLinkUpdater(); + given(converter.toApplicationLinkUpdater(attributesToUpDate)).willReturn(applicationUpdater); + + final ApplicationLinkImpl application = new ApplicationLinkImpl("app", "1.0", "app desc"); + given(applicationAPI.updateApplicationLink(1, applicationUpdater)).willReturn(application); + given(applicationAPI.getIApplication(1)).willReturn(application); + final ApplicationLinkItem item = new ApplicationLinkItem(); + given(converter.toApplicationItem(application)).willReturn(item); + + //when + final ApplicationLinkItem createdItem = (ApplicationLinkItem) dataStore.update(APIID.makeAPIID(1L), + attributesToUpDate); + + //then + verify(converter, times(1)).toApplicationLinkUpdater(attributesToUpDate); + verify(applicationAPI, times(1)).updateApplicationLink(1, applicationUpdater); + verify(converter, times(1)).toApplicationItem(application); + assertThat(createdItem).isEqualTo(new ApplicationLinkItem()); + } + @Test(expected = APIException.class) public void should_throw_APIException_when_ApplicationAPI_throws_an_exception_on_add() throws Exception { ApplicationItem app = new ApplicationItem(); @@ -173,8 +235,8 @@ public void should_throw_APIException_when_ApplicationAPI_throws_an_exception_on @Test(expected = APIException.class) public void should_throw_APIException_when_ApplicationAPI_throws_an_exception_on_UpDate() throws Exception { //given + given(applicationAPI.getIApplication(eq(1L))).willReturn(mock(ApplicationImpl.class)); when(applicationAPI.updateApplication(eq(1L), any())).thenThrow(new UpdateException("")); - //when dataStore.update(APIID.makeAPIID(1L), new HashMap<>()); } @@ -186,10 +248,26 @@ public void should_return_the_good_application_on_get() throws Exception { final ApplicationItem item = new ApplicationItem(); given(converter.toApplicationItem(application)).willReturn(item); application.setId(1); - given(applicationAPI.getApplication(1)).willReturn(application); + given(applicationAPI.getIApplication(1)).willReturn(application); + + //when + final AbstractApplicationItem retrivedItem = dataStore.get(APIID.makeAPIID("1")); + + //then + assertThat(retrivedItem).isEqualTo(item); + } + + @Test + public void should_return_the_good_application_link_on_get() throws Exception { + //given + final ApplicationLinkImpl application = new ApplicationLinkImpl("app", "1.0", "app desc"); + final ApplicationLinkItem item = new ApplicationLinkItem(); + given(converter.toApplicationItem(application)).willReturn(item); + application.setId(1); + given(applicationAPI.getIApplication(1)).willReturn(application); //when - final ApplicationItem retrivedItem = dataStore.get(APIID.makeAPIID("1")); + final AbstractApplicationItem retrivedItem = dataStore.get(APIID.makeAPIID("1")); //then assertThat(retrivedItem).isEqualTo(item); @@ -198,7 +276,7 @@ public void should_return_the_good_application_on_get() throws Exception { @Test(expected = APIException.class) public void should_return_throw_APIException_on_get_when_engine_throws_exception() throws Exception { //given - given(applicationAPI.getApplication(1)).willThrow(new ApplicationNotFoundException(1)); + given(applicationAPI.getIApplication(1)).willThrow(new ApplicationNotFoundException(1)); //when dataStore.get(APIID.makeAPIID("1")); @@ -245,15 +323,15 @@ public void should_call_engine_with_good_parameters_on_search() throws Exception application.setLastUpdateDate(new Date()); application.setVisibility(ApplicationVisibility.ALL); - given(applicationAPI.searchApplications(any(SearchOptions.class))) - .willReturn(new SearchResultImpl<>(2, Arrays. asList(application))); + given(applicationAPI.searchIApplications(any(SearchOptions.class))) + .willReturn(new SearchResultImpl<>(2, Arrays. asList(application))); //when dataStore.search(page, resultsByPage, search, orders, filters); //then final ArgumentCaptor searchOptionCaptor = ArgumentCaptor.forClass(SearchOptions.class); - verify(applicationAPI, times(1)).searchApplications(searchOptionCaptor.capture()); + verify(applicationAPI, times(1)).searchIApplications(searchOptionCaptor.capture()); final SearchOptions searchOption = searchOptionCaptor.getValue(); assertThat(searchOption.getFilters().get(0).getField()).isEqualTo(ApplicationItem.ATTRIBUTE_CREATED_BY); @@ -285,12 +363,12 @@ public void should_return_a_valid_ItemSearchResult_on_search() throws Exception application.setLastUpdateDate(new Date()); application.setVisibility(ApplicationVisibility.ALL); - given(applicationAPI.searchApplications(any(SearchOptions.class))) - .willReturn(new SearchResultImpl<>(2, Arrays. asList(application))); + given(applicationAPI.searchIApplications(any(SearchOptions.class))) + .willReturn(new SearchResultImpl<>(2, Arrays. asList(application))); //when - final ItemSearchResult retrievedItems = dataStore.search(page, resultsByPage, search, orders, - filters); + final ItemSearchResult retrievedItems = dataStore.search(page, resultsByPage, search, + orders, filters); //then assertThat(retrievedItems.getLength()).isEqualTo(1); @@ -303,7 +381,7 @@ public void should_return_a_valid_ItemSearchResult_on_search() throws Exception @Test(expected = APIException.class) public void should_throw_APIException_on_search_when_engine_throws_exception() throws Exception { //given - given(applicationAPI.searchApplications(any(SearchOptions.class))) + given(applicationAPI.searchIApplications(any(SearchOptions.class))) .willThrow(new SearchException(new Exception())); //when diff --git a/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationItemConverterTest.java b/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationItemConverterTest.java index 3773aefa839..654d09f85c2 100644 --- a/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationItemConverterTest.java +++ b/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/rest/server/datastore/application/ApplicationItemConverterTest.java @@ -77,7 +77,7 @@ public void toApplicationItem_should_map_all_fields() throws Exception { application.setEditable(true); //when - ApplicationItem item = converter.toApplicationItem(application); + ApplicationItem item = (ApplicationItem) converter.toApplicationItem(application); //then assertThat(item).isNotNull(); @@ -100,7 +100,7 @@ public void toApplicationItem_should_map_all_fields() throws Exception { application.setHasIcon(false); - item = converter.toApplicationItem(application); + item = (ApplicationItem) converter.toApplicationItem(application); assertThat(item.getIcon()).isEmpty(); } @@ -121,7 +121,7 @@ public void applicationItem_with_null_homepage_id_should_not_return_null() throw application.setVisibility(APPLICATION_VISIBILITY); //when - final ApplicationItem item = converter.toApplicationItem(application); + final ApplicationItem item = (ApplicationItem) converter.toApplicationItem(application); //then assertThat(item).isNotNull(); @@ -144,7 +144,7 @@ public void applicationItem_with_null_Layout_id_should_not_return_null() throws application.setVisibility(APPLICATION_VISIBILITY); //when - final ApplicationItem item = converter.toApplicationItem(application); + final ApplicationItem item = (ApplicationItem) converter.toApplicationItem(application); //then assertThat(item).isNotNull(); @@ -167,7 +167,7 @@ public void applicationItem_with_null_Theme_id_should_not_return_null() throws E application.setVisibility(APPLICATION_VISIBILITY); //when - final ApplicationItem item = converter.toApplicationItem(application); + final ApplicationItem item = (ApplicationItem) converter.toApplicationItem(application); //then assertThat(item).isNotNull(); diff --git a/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/toolkit/client/common/json/JSonItemReaderTest.java b/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/toolkit/client/common/json/JSonItemReaderTest.java new file mode 100644 index 00000000000..43b7d876f57 --- /dev/null +++ b/bpm/bonita-web-server/src/test/java/org/bonitasoft/web/toolkit/client/common/json/JSonItemReaderTest.java @@ -0,0 +1,81 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.web.toolkit.client.common.json; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.bonitasoft.web.rest.model.application.AbstractApplicationDefinition; +import org.bonitasoft.web.rest.model.application.ApplicationItem; +import org.bonitasoft.web.rest.model.application.ApplicationLinkItem; +import org.junit.Test; + +public class JSonItemReaderTest { + + @Test + public void should_parse_an_implicit_LegacyApplication_from_AbstractApplicationDefinition() throws Exception { + // given + String json = """ + { + "version": "1.0", + "profileId": "2", + "token": "myapp", + "displayName": "My app", + "description": "My application description" + } + """; + // when + var app = JSonItemReader.parseItem(json, AbstractApplicationDefinition.get()); + // then + assertThat(app).isExactlyInstanceOf(ApplicationItem.class); + } + + @Test + public void should_parse_an_explicit_LegacyApplication_from_AbstractApplicationDefinition() throws Exception { + // given + String json = """ + { + "link": "false", + "version": "1.0", + "profileId": "2", + "token": "myapp", + "displayName": "My app", + "description": "My application description" + } + """; + // when + var app = JSonItemReader.parseItem(json, AbstractApplicationDefinition.get()); + // then + assertThat(app).isExactlyInstanceOf(ApplicationItem.class); + } + + @Test + public void should_parse_an_ApplicationLink_from_AbstractApplicationDefinition() throws Exception { + // given + String json = """ + { + "link": "true", + "version": "1.0", + "profileId": "2", + "token": "myapp", + "displayName": "My app", + "description": "My application description" + } + """; + // when + var app = JSonItemReader.parseItem(json, AbstractApplicationDefinition.get()); + // then + assertThat(app).isExactlyInstanceOf(ApplicationLinkItem.class); + } + +} diff --git a/buildSrc/src/main/groovy/org/bonitasoft/engine/gradle/docker/DatabaseExtraConfiguration.groovy b/buildSrc/src/main/groovy/org/bonitasoft/engine/gradle/docker/DatabaseExtraConfiguration.groovy new file mode 100644 index 00000000000..978fa97d9f5 --- /dev/null +++ b/buildSrc/src/main/groovy/org/bonitasoft/engine/gradle/docker/DatabaseExtraConfiguration.groovy @@ -0,0 +1,50 @@ +package org.bonitasoft.engine.gradle.docker + +import groovy.transform.Canonical +import org.gradle.api.Project + +@Canonical +class DatabaseExtraConfiguration { + /** + * Include an additional project in the test classpath + */ + Project includeTestProject + /** + * Excludes test class patterns (e.g. '**/*Test.class') applied to this database vendor. + * It can be combined with {@link #excludeTags}. + */ + List excludes + /** + * Excludes tests marked by JUnit tags (e.g. 'my-tag') applied to this database vendor. + * It can be combined with {@link #excludes}. + */ + List excludeTags + /** + * Enable or disable the execution of the test task for this database configuration + */ + boolean enabled = false + + def excludes(String... excludes) { + this.excludes = [] + this.excludes.addAll(excludes) + } + + def exclude(String excludes) { + if (this.excludes == null) { + this.excludes = [] + } + this.excludes.add(excludes) + } + + def excludeTags(String... tags) { + this.excludeTags = [] + this.excludeTags.addAll(tags) + } + + def excludeTag(String tag) { + if (this.excludeTags == null) { + this.excludeTags = [] + } + this.excludeTags.add(tag) + } +} diff --git a/buildSrc/src/main/groovy/org/bonitasoft/engine/gradle/docker/DatabasePluginExtension.groovy b/buildSrc/src/main/groovy/org/bonitasoft/engine/gradle/docker/DatabasePluginExtension.groovy index dc0865b7917..ecab790525e 100644 --- a/buildSrc/src/main/groovy/org/bonitasoft/engine/gradle/docker/DatabasePluginExtension.groovy +++ b/buildSrc/src/main/groovy/org/bonitasoft/engine/gradle/docker/DatabasePluginExtension.groovy @@ -13,12 +13,34 @@ **/ package org.bonitasoft.engine.gradle.docker -/** - * @author Baptiste Mesta - */ +import org.gradle.api.Action + class DatabasePluginExtension { + /** + * Include test class patterns applied to database vendors + */ List includes + /** + * Exclude test class patterns applied to all database vendors + */ + List excludes + /** + * Extra configuration for the postgres database + */ + DatabaseExtraConfiguration postgres = new DatabaseExtraConfiguration(enabled: true) + /** + * Extra configuration for the mysql database + */ + DatabaseExtraConfiguration mysql = new DatabaseExtraConfiguration() + /** + * Extra configuration for the oracle database + */ + DatabaseExtraConfiguration oracle = new DatabaseExtraConfiguration() + /** + * Extra configuration for the sqlserver database + */ + DatabaseExtraConfiguration sqlserver = new DatabaseExtraConfiguration() def includes(String... includes) { this.includes = [] @@ -32,4 +54,32 @@ class DatabasePluginExtension { this.includes.add(include) } + def excludes(String... excludes) { + this.excludes = [] + this.excludes.addAll(excludes) + } + + def exclude(String exclude) { + if (this.excludes == null) { + this.excludes = [] + } + this.excludes.add(exclude) + } + + def postgres(Action action) { + action.execute(postgres) + } + + def mysql(Action action) { + action.execute(mysql) + } + + def oracle(Action action) { + action.execute(oracle) + } + + def sqlserver(Action action) { + action.execute(sqlserver) + } + } diff --git a/buildSrc/src/main/groovy/org/bonitasoft/engine/gradle/docker/DockerDatabaseContainerTasksCreator.groovy b/buildSrc/src/main/groovy/org/bonitasoft/engine/gradle/docker/DockerDatabaseContainerTasksCreator.groovy index c5a75bed98c..20c28fdac28 100644 --- a/buildSrc/src/main/groovy/org/bonitasoft/engine/gradle/docker/DockerDatabaseContainerTasksCreator.groovy +++ b/buildSrc/src/main/groovy/org/bonitasoft/engine/gradle/docker/DockerDatabaseContainerTasksCreator.groovy @@ -20,8 +20,6 @@ import com.bmuschko.gradle.docker.tasks.container.DockerStartContainer import com.bmuschko.gradle.docker.tasks.container.extras.DockerWaitHealthyContainer import com.bmuschko.gradle.docker.tasks.image.DockerPullImage import org.gradle.api.Project -import org.gradle.api.Task -import org.gradle.api.UnknownTaskException import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.bundling.Zip import org.gradle.api.tasks.testing.Test @@ -31,32 +29,6 @@ import org.gradle.api.tasks.testing.Test */ class DockerDatabaseContainerTasksCreator { - def static vendors = [ - [name : 'oracle', - image : 'bonitasoft.jfrog.io/docker-releases/bonita-oracle-19c-ee:0.0.2', - registryUrlEnv : 'DOCKER_BONITASOFT_REGISTRY', - registryUsernameEnv: 'REGISTRY_USERNAME', - registryPasswordEnv: 'REGISTRY_TOKEN', - portBinding : 1521, - uriTemplate : 'jdbc:oracle:thin:@//%s:%s/ORCLPDB1?oracle.net.disableOob=true', - ], - [name : 'postgres', - image : 'bonitasoft/bonita-postgres:15.3', - portBinding: 5432, - uriTemplate: 'jdbc:postgresql://%s:%s/%s', - ], - [name : 'mysql', - image : 'bonitasoft/bonita-mysql:8.0.33', - portBinding: 3306, - uriTemplate: 'jdbc:mysql://%s:%s/%s?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8', - ], - [name : 'sqlserver', - image : 'bonitasoft/bonita-sqlserver:2022-CU13', - portBinding: 1433, - uriTemplate: 'jdbc:sqlserver://%s:%s;database=%s', - ] - ] - private static String getDockerHost(def project) { def dockerHost = System.getenv('DOCKER_HOST') if (dockerHost?.trim()) { @@ -70,21 +42,22 @@ class DockerDatabaseContainerTasksCreator { private static final String SYS_PROP_DB_USER = 'db.user' private static final String SYS_PROP_DB_PASSWORD = 'db.password' - def static createTasks(Project project, DatabasePluginExtension extension) { + def static createTasks(Project project, DatabasePluginExtension extension, List vendors) { // required to have the environment correctly setup: see https://github.com/bmuschko/gradle-docker-plugin/issues/575#issuecomment-383704012 if (!project.rootProject.plugins.hasPlugin('com.bmuschko.docker-remote-api')) { project.rootProject.plugins.apply('com.bmuschko.docker-remote-api') } project.plugins.apply('com.bmuschko.docker-remote-api') vendors.each { vendor -> + if (!extension."${vendor.name}".enabled) { + return // do not create docker tasks for disabled database configurations + } def uniqueName = vendor.name.capitalize() DbParser.DbConnectionSettings dbConnectionSettings = new DbParser.DbConnectionSettings() DbParser.DbConnectionSettings bdmDbConnectionSettings = new DbParser.DbConnectionSettings() - TaskProvider inspectContainer - TaskProvider removeContainer - TaskProvider pullImage = registerTaskInRootProject(project, "pull${uniqueName}Image", DockerPullImage) { + def pullImage = project.tasks.register("pull${uniqueName}Image", DockerPullImage) { description "Pull docker image for $uniqueName db vendor" group null // do not show task when running `gradle tasks` @@ -99,7 +72,7 @@ class DockerDatabaseContainerTasksCreator { } } - TaskProvider createContainer = registerTaskInRootProject(project, "create${uniqueName}Container", DockerCreateContainer) { + def createContainer = project.tasks.register("create${uniqueName}Container", DockerCreateContainer) { description "Create a docker container for $uniqueName db vendor" group null // do not show task when running `gradle tasks` @@ -115,14 +88,14 @@ class DockerDatabaseContainerTasksCreator { hostConfig.autoRemove = true } - TaskProvider startContainer = registerTaskInRootProject(project, "start${uniqueName}Container", DockerStartContainer) { + def startContainer = project.tasks.register("start${uniqueName}Container", DockerStartContainer) { description "Start a docker container for $uniqueName db vendor" group "docker" targetContainerId createContainer.get().getContainerId() } - def waitForContainerStartup = registerTaskInRootProject(project, "waitFor${uniqueName}ContainerStartup", DockerWaitHealthyContainer) { + def waitForContainerStartup = project.tasks.register("waitFor${uniqueName}ContainerStartup", DockerWaitHealthyContainer) { description "Wait for a started docker container for $vendor.name db vendor to be healthy" group null // do not show task when running `gradle tasks` @@ -130,7 +103,7 @@ class DockerDatabaseContainerTasksCreator { awaitStatusTimeout = 360 } - inspectContainer = project.tasks.register("inspect${uniqueName}ContainerUrl", DockerInspectContainer) { + def inspectContainer = project.tasks.register("inspect${uniqueName}ContainerUrl", DockerInspectContainer) { description = "Get url of a docker container for $uniqueName db vendor" group = null // do not show task when running `gradle tasks` @@ -153,7 +126,7 @@ class DockerDatabaseContainerTasksCreator { } } - removeContainer = registerTaskInRootProject(project, "remove${uniqueName}Container", DockerRemoveContainer) { + def removeContainer = project.tasks.register("remove${uniqueName}Container", DockerRemoveContainer) { description "Remove a docker container for $uniqueName db vendor" group "docker" @@ -166,8 +139,21 @@ class DockerDatabaseContainerTasksCreator { group = "Verification" description = "Runs slow integration test suite on $vendor.name database." systemProperty "bonita.version", project.version - jvmArgs += ['--add-opens','java.base/java.util=ALL-UNNAMED','--add-opens','java.base/java.lang=ALL-UNNAMED','-Dfile.encoding=UTF-8'] + jvmArgs += ['--add-opens', 'java.base/java.util=ALL-UNNAMED', '--add-opens', 'java.base/java.lang=ALL-UNNAMED', '-Dfile.encoding=UTF-8'] + if (extension."${vendor.name}"?.includeTestProject) { + testClassesDirs += extension."${vendor.name}".includeTestProject.sourceSets.test.output.classesDirs + classpath += extension."${vendor.name}".includeTestProject.sourceSets.test.runtimeClasspath + } classpath += project.files(project.configurations.drivers) + if (extension."${vendor.name}"?.excludes) { + exclude(extension."${vendor.name}".excludes) + } + if (extension."${vendor.name}"?.excludeTags) { + useJUnitPlatform { + excludeTags = extension."${vendor.name}".excludeTags + } + } + onlyIf { extension."${vendor.name}"?.enabled } doFirst { String dbUrl = project.hasProperty(SYS_PROP_DB_URL) ? project.property(SYS_PROP_DB_URL) : dbConnectionSettings.dbUrl @@ -204,10 +190,22 @@ class DockerDatabaseContainerTasksCreator { from databaseTestTask.get().reports.html.outputLocation.get().getAsFile() } project.afterEvaluate { - databaseTestTask.configure { includes = extension.includes } + databaseTestTask.configure { + if (extension.includes) { + include(extension.includes) + } + if (extension.excludes) { + exclude(extension.excludes) + } + } + pullImage.configure { onlyIf { extension."${vendor.name}"?.enabled } } + createContainer.configure { onlyIf { extension."${vendor.name}"?.enabled } } + startContainer.configure { onlyIf { extension."${vendor.name}"?.enabled } } + waitForContainerStartup.configure { onlyIf { extension."${vendor.name}"?.enabled } } + inspectContainer.configure { onlyIf { extension."${vendor.name}"?.enabled } } + removeContainer.configure { onlyIf { extension."${vendor.name}"?.enabled } } } - if (createContainer) { createContainer.configure { dependsOn(pullImage) } } @@ -235,11 +233,4 @@ class DockerDatabaseContainerTasksCreator { } } - static TaskProvider registerTaskInRootProject(Project project, String taskName, Class taskType, Closure configuration) { - try { - project.rootProject.tasks.named(taskName) - } catch (UnknownTaskException ignored) { - project.rootProject.tasks.register(taskName, taskType, configuration) - } - } } diff --git a/buildSrc/src/main/groovy/org/bonitasoft/engine/gradle/docker/DockerDatabasePlugin.groovy b/buildSrc/src/main/groovy/org/bonitasoft/engine/gradle/docker/DockerDatabasePlugin.groovy index 7d8ce67e3c0..b4fd6d5cb0b 100644 --- a/buildSrc/src/main/groovy/org/bonitasoft/engine/gradle/docker/DockerDatabasePlugin.groovy +++ b/buildSrc/src/main/groovy/org/bonitasoft/engine/gradle/docker/DockerDatabasePlugin.groovy @@ -17,9 +17,9 @@ class DockerDatabasePlugin implements Plugin { driversConfiguration(project) def databaseIntegrationTest = project.extensions.create("databaseIntegrationTest", DatabasePluginExtension) - DockerDatabaseContainerTasksCreator.createTasks(project, databaseIntegrationTest) project.afterEvaluate { + DockerDatabaseContainerTasksCreator.createTasks(project, databaseIntegrationTest, getVendors()) if (!databaseIntegrationTest.includes) { println "No databaseIntegrationTest.include found. No tests to run!" } @@ -30,10 +30,18 @@ class DockerDatabasePlugin implements Plugin { project.dependencies { // the following jdbc drivers are available for integration tests def versionCatalog = project.extensions.getByType(VersionCatalogsExtension.class).named("libs") - drivers(versionCatalog.findLibrary("mysql").get()) - drivers(versionCatalog.findLibrary("oracle").get()) drivers(versionCatalog.findLibrary("postgresql").get()) - drivers(versionCatalog.findLibrary("msSqlServer").get()) } } + + List getVendors() { + return [ + [name : 'postgres', + image : 'bonitasoft/bonita-postgres:16.4', + portBinding: 5432, + uriTemplate: 'jdbc:postgresql://%s:%s/%s', + ] + ] + } + } diff --git a/common.gradle b/common.gradle index fa82d079fdc..9488824acbd 100644 --- a/common.gradle +++ b/common.gradle @@ -4,7 +4,7 @@ allprojects { apply plugin: 'maven-publish' group = 'org.bonitasoft.engine' - + tasks.withType(Copy).configureEach { setDuplicatesStrategy(DuplicatesStrategy.INCLUDE) } @@ -59,13 +59,19 @@ subprojects { mavenLocal() } + dependencies { + testImplementation libs.junit5api + testCompileOnly libs.junit4 + testRuntimeOnly libs.junitJupiterEngine + // to support junit4 tests + testRuntimeOnly libs.junitVintageEngine + } + java { toolchain { languageVersion = JavaLanguageVersion.of(17) } } - configurations.configureEach { - } afterEvaluate { tasks.withType(AbstractCompile).configureEach { options.encoding = 'UTF-8' } } @@ -73,9 +79,6 @@ subprojects { options.encoding = 'UTF-8' options.fork = true } - tasks.named('test') { - jvmArgs += ['--add-opens','java.base/java.util=ALL-UNNAMED','--add-opens','java.base/java.lang=ALL-UNNAMED','-Dfile.encoding=UTF-8'] - } tasks.withType(Javadoc).configureEach { options.addStringOption('Xdoclint:none', '-quiet') options.encoding = 'UTF-8' @@ -85,7 +88,13 @@ subprojects { description "List runtime dependencies for a specified configuration" configurations = [project.configurations.runtimeClasspath] } + + // Configure all test tasks (test, integrationTest, httpIT, databaseTest) tasks.withType(Test).configureEach { + useJUnitPlatform { + includeEngines 'junit-jupiter', 'junit-vintage' + } + jvmArgs += ['--add-opens', 'java.base/java.util=ALL-UNNAMED', '--add-opens', 'java.base/java.lang=ALL-UNNAMED', '-Dfile.encoding=UTF-8'] if (!project.hasProperty("createTestReports")) { reports.html.required = false reports.junitXml.required = false diff --git a/gradle.properties b/gradle.properties index 459d096b5ac..3caf3748392 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,5 +2,5 @@ org.gradle.jvmargs=--add-opens java.base/java.util=ALL-UNNAMED --add-opens java. org.gradle.caching=true org.gradle.vfs.watch=true -version=10.1-SNAPSHOT -brandingVersion=2024.2-SNAPSHOT \ No newline at end of file +version=10.2-SNAPSHOT +brandingVersion=2024.3-SNAPSHOT \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 22e1ca63cdc..39a23e114b1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,36 +4,36 @@ groovyVersion = "3.0.19" springVersion = "5.3.39" springSessionVersion = "2.7.4" springBootVersion = "2.7.18" -commonsLangVersion = "3.11" -bonitaArtifactsModelVersion = "1.0.0" -bonitaSecurityVersion = "1.25.11" +commonsLangVersion = "3.14.0" +bonitaArtifactsModelVersion = "1.1.1" +bonitaSecurityVersion = "1.26.2" commonsIOVersion = "2.17.0" commonsFileUploadVersion = "1.5" commonsBeanutilsVersion = "1.9.4" commonsCollectionsVersion = "4.4" tomcatVersion = "9.0.96" -commonsCLIVersion = "1.4" +commonsCLIVersion = "1.8.0" commonsTextVersion = "1.10.0" semver4jVersion = '3.1.0' slf4jVersion = "1.7.36" # Attention, see PassingPropertiesJCacheRegionFactory javadoc if this version changes: -hibernateVersion = "5.4.32.Final" -# version used by hibernate 5.4.32.Final (MUST BE REMOVED WHEN HIBERNATE IS UPGRADED to 5.6+): +hibernateVersion = "5.4.33" +# version used by hibernate 5.4.33 (MUST BE REMOVED WHEN HIBERNATE IS UPGRADED to 5.6+): javassistVersion = "3.27.0-GA" # javax.persistence-api is used by hibernate: javaxPersistenceApiVersion = "2.2" -jacksonBomVersion = "2.15.3" +jacksonBomVersion = "2.17.1" jakartaTransactionVersion = "1.3.3" jakartaServletVersion = "4.0.4" # Keep this until all client projects have migrated to jakarta or it will break their builds ! javaxServletVersion = "4.0.1" -httpComponentsVersion = "4.5.13" +httpComponentsVersion = "4.5.14" xstreamVersion = "1.4.21" ehCacheVersion = "2.10.10.12.7" -eclipseCompilerVersion = "3.20.0" +eclipseCompilerVersion = "3.38.0" jakartaActivationVersion = "1.2.2" quartzVersion = "2.3.2" -micrometerVersion = "1.6.1" +micrometerVersion = "1.13.1" # DB drivers: mysqlVersion = "8.2.0" msSqlServerVersion = "8.4.1.jre8" @@ -44,7 +44,7 @@ narayanaVersion = "5.10.6.Final" logbackVersion = "1.2.13" jaxbVersion = "2.3.1" javaxAnnotationsVersion = "1.3.2" -hazelcastVersion = "5.3.5" # Also update http://www.hazelcast.com/schema/config/hazelcast-config-.xsd if needed +hazelcastVersion = "5.4.0" # Also update http://www.hazelcast.com/schema/config/hazelcast-config-.xsd if needed jcacheVersion = "1.0.0" guavaVersion = "32.1.2-jre" antlr4RuntimeVersion = "4.7.2" @@ -146,7 +146,6 @@ bonitaTestLicenses = { group = "org.bonitasoft.security", name = "test-licenses" guava = { group = "com.google.guava", name = "guava", version.ref = "guavaVersion" } antlr4Runtime = { group = "org.antlr", name = "antlr4-runtime", version.ref = "antlr4RuntimeVersion" } commonsLang = { group = "org.apache.commons", name = "commons-lang3", version.ref = "commonsLangVersion" } -snakeyaml = "org.yaml:snakeyaml:1.32" commonsIO = { group = "commons-io", name = "commons-io", version.ref = "commonsIOVersion" } commonsFileUpload = { group = "commons-fileupload", name = "commons-fileupload", version.ref = "commonsFileUploadVersion" } commonsBeanUtils = { group = "commons-beanutils", name = "commons-beanutils", version.ref = "commonsBeanutilsVersion" } @@ -189,13 +188,13 @@ micrometerRegistryPrometheus = { group = "io.micrometer", name = "micrometer-reg narayanaJta = { group = "org.jboss.narayana.jta", name = "narayana-jta", version.ref = "narayanaVersion" } jaxbCodeModel = { group = "org.glassfish.jaxb", name = "codemodel", version.ref = "jaxbVersion" } -h2 = "com.h2database:h2:1.4.199" +h2 = "com.h2database:h2:1.4.200" mysql = { group = "com.mysql", name = "mysql-connector-j", version.ref = "mysqlVersion" } msSqlServer = { group = "com.microsoft.sqlserver", name = "mssql-jdbc", version.ref = "msSqlServerVersion" } oracle = { group = "com.oracle.database.jdbc", name = "ojdbc8", version.ref = "oracleVersion" } postgresql = { group = "org.postgresql", name = "postgresql", version.ref = "postgresqlVersion" } -lombok = "org.projectlombok:lombok:1.18.30" +lombok = "org.projectlombok:lombok:1.18.32" logback = { group = "ch.qos.logback", name = "logback-classic", version.ref = "logbackVersion" } diff --git a/platform/platform-resources/build.gradle b/platform/platform-resources/build.gradle index ab20040719b..3cc44883f25 100644 --- a/platform/platform-resources/build.gradle +++ b/platform/platform-resources/build.gradle @@ -8,6 +8,8 @@ group = 'org.bonitasoft.platform' description = '' dependencies { + implementation platform(libs.jacksonBom) + annotationProcessor libs.lombok compileOnly libs.lombok api libs.springTx @@ -15,8 +17,9 @@ dependencies { api libs.springContext api libs.slf4jApi api libs.commonsIO + api libs.springBootAutoconfigure + implementation "com.fasterxml.jackson.core:jackson-databind" - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.mockitoCore testImplementation libs.logback diff --git a/platform/platform-resources/src/main/java/org/bonitasoft/platform/configuration/impl/BonitaAllConfigurationPreparedStatementSetter.java b/platform/platform-resources/src/main/java/org/bonitasoft/platform/configuration/impl/BonitaAllConfigurationPreparedStatementSetter.java index 999d63097fc..37c66f41d56 100644 --- a/platform/platform-resources/src/main/java/org/bonitasoft/platform/configuration/impl/BonitaAllConfigurationPreparedStatementSetter.java +++ b/platform/platform-resources/src/main/java/org/bonitasoft/platform/configuration/impl/BonitaAllConfigurationPreparedStatementSetter.java @@ -18,6 +18,8 @@ import java.util.List; import org.bonitasoft.platform.configuration.model.FullBonitaConfiguration; +import org.bonitasoft.platform.database.DatabaseVendor; +import org.bonitasoft.platform.setup.PlatformSetup; import org.springframework.jdbc.core.BatchPreparedStatementSetter; import org.springframework.jdbc.support.lob.TemporaryLobCreator; @@ -30,15 +32,12 @@ public class BonitaAllConfigurationPreparedStatementSetter public static final String INSERT_CONFIGURATION = "INSERT into configuration(tenant_id, content_type, resource_name, resource_content) values (?,?,?,?)"; private final List bonitaConfigurations; - String dbVendor; + private final String dbVendor; public BonitaAllConfigurationPreparedStatementSetter(List bonitaConfigurations, String dbVendor) { this.bonitaConfigurations = bonitaConfigurations; - this.dbVendor = dbVendor; - if (this.dbVendor == null) { - this.dbVendor = System.getProperty("sysprop.bonita.db.vendor"); - } + this.dbVendor = dbVendor == null ? PlatformSetup.getPropertyBonitaDbVendor() : dbVendor; } @Override @@ -47,14 +46,11 @@ public void setValues(PreparedStatement ps, int i) throws SQLException { ps.setLong(COLUMN_INDEX_TENANT_ID, bonitaConfiguration.getTenantId()); ps.setString(COLUMN_INDEX_TYPE, bonitaConfiguration.getConfigurationType()); ps.setString(COLUMN_INDEX_RESOURCE_NAME, bonitaConfiguration.getResourceName()); - switch (dbVendor) { - case "h2": - case "postgres": + switch (DatabaseVendor.parseValue(dbVendor)) { + case H2, POSTGRES: ps.setBytes(COLUMN_INDEX_RESOURCE_CONTENT, bonitaConfiguration.getResourceContent()); break; - case "oracle": - case "mysql": - case "sqlserver": + case ORACLE, MYSQL, SQLSERVER: TemporaryLobCreator temporaryLobCreator = new TemporaryLobCreator(); temporaryLobCreator.setBlobAsBytes(ps, COLUMN_INDEX_RESOURCE_CONTENT, bonitaConfiguration.getResourceContent()); diff --git a/platform/platform-resources/src/main/java/org/bonitasoft/platform/configuration/impl/BonitaConfigurationPreparedStatementSetter.java b/platform/platform-resources/src/main/java/org/bonitasoft/platform/configuration/impl/BonitaConfigurationPreparedStatementSetter.java index 85c14bffece..60a91fce674 100644 --- a/platform/platform-resources/src/main/java/org/bonitasoft/platform/configuration/impl/BonitaConfigurationPreparedStatementSetter.java +++ b/platform/platform-resources/src/main/java/org/bonitasoft/platform/configuration/impl/BonitaConfigurationPreparedStatementSetter.java @@ -19,6 +19,8 @@ import org.bonitasoft.platform.configuration.model.BonitaConfiguration; import org.bonitasoft.platform.configuration.type.ConfigurationType; +import org.bonitasoft.platform.database.DatabaseVendor; +import org.bonitasoft.platform.setup.PlatformSetup; import org.springframework.jdbc.core.BatchPreparedStatementSetter; import org.springframework.jdbc.support.lob.TemporaryLobCreator; @@ -30,17 +32,14 @@ public class BonitaConfigurationPreparedStatementSetter implements BatchPrepared public static final String INSERT_CONFIGURATION = "INSERT into configuration(tenant_id, content_type, resource_name, resource_content) values (?,?,?,?)"; private final List bonitaConfigurations; - private String dbVendor; - private ConfigurationType type; - private long tenantId; + private final String dbVendor; + private final ConfigurationType type; + private final long tenantId; public BonitaConfigurationPreparedStatementSetter(List bonitaConfigurations, String dbVendor, ConfigurationType type, long tenantId) { this.bonitaConfigurations = bonitaConfigurations; - this.dbVendor = dbVendor; - if (this.dbVendor == null) { - this.dbVendor = System.getProperty("sysprop.bonita.db.vendor"); - } + this.dbVendor = dbVendor == null ? PlatformSetup.getPropertyBonitaDbVendor() : dbVendor; this.type = type; this.tenantId = tenantId; } @@ -51,16 +50,12 @@ public void setValues(PreparedStatement ps, int i) throws SQLException { ps.setLong(COLUMN_INDEX_TENANT_ID, tenantId); ps.setString(COLUMN_INDEX_TYPE, type.toString()); ps.setString(COLUMN_INDEX_RESOURCE_NAME, bonitaConfiguration.getResourceName()); - switch (dbVendor) { - case "h2": - case "postgres": + switch (DatabaseVendor.parseValue(dbVendor)) { + case H2, POSTGRES: ps.setBytes(COLUMN_INDEX_RESOURCE_CONTENT, bonitaConfiguration.getResourceContent()); break; - case "oracle": - case "mysql": - case "sqlserver": - TemporaryLobCreator temporaryLobCreator = new TemporaryLobCreator(); - temporaryLobCreator.setBlobAsBytes(ps, COLUMN_INDEX_RESOURCE_CONTENT, + case ORACLE, MYSQL, SQLSERVER: + new TemporaryLobCreator().setBlobAsBytes(ps, COLUMN_INDEX_RESOURCE_CONTENT, bonitaConfiguration.getResourceContent()); break; default: diff --git a/platform/platform-resources/src/main/java/org/bonitasoft/platform/configuration/impl/BonitaConfigurationTenantUpdater.java b/platform/platform-resources/src/main/java/org/bonitasoft/platform/configuration/impl/BonitaConfigurationTenantUpdater.java index e20b5039707..9262f3a263f 100644 --- a/platform/platform-resources/src/main/java/org/bonitasoft/platform/configuration/impl/BonitaConfigurationTenantUpdater.java +++ b/platform/platform-resources/src/main/java/org/bonitasoft/platform/configuration/impl/BonitaConfigurationTenantUpdater.java @@ -19,6 +19,7 @@ import org.bonitasoft.platform.configuration.model.BonitaConfiguration; import org.bonitasoft.platform.configuration.type.ConfigurationType; +import org.bonitasoft.platform.database.DatabaseVendor; import org.springframework.jdbc.core.BatchPreparedStatementSetter; import org.springframework.jdbc.support.lob.TemporaryLobCreator; @@ -30,8 +31,8 @@ public class BonitaConfigurationTenantUpdater implements BatchPreparedStatementS public static final String UPDATE_ALL_TENANTS_CONFIGURATION = "UPDATE configuration SET resource_content=? WHERE content_type=? AND resource_name=?"; private final List bonitaConfigurations; - private String dbVendor; - private ConfigurationType type; + private final String dbVendor; + private final ConfigurationType type; public BonitaConfigurationTenantUpdater(List bonitaConfigurations, String dbVendor, ConfigurationType type) { @@ -45,14 +46,11 @@ public void setValues(PreparedStatement ps, int i) throws SQLException { final BonitaConfiguration bonitaConfiguration = bonitaConfigurations.get(i); ps.setString(2, type.toString()); ps.setString(3, bonitaConfiguration.getResourceName()); - switch (dbVendor) { - case "h2": - case "postgres": + switch (DatabaseVendor.parseValue(dbVendor)) { + case H2, POSTGRES: ps.setBytes(1, bonitaConfiguration.getResourceContent()); break; - case "oracle": - case "mysql": - case "sqlserver": + case ORACLE, MYSQL, SQLSERVER: new TemporaryLobCreator().setBlobAsBytes(ps, 1, bonitaConfiguration.getResourceContent()); break; default: diff --git a/platform/platform-resources/src/main/java/org/bonitasoft/platform/configuration/impl/ConfigurationServiceImpl.java b/platform/platform-resources/src/main/java/org/bonitasoft/platform/configuration/impl/ConfigurationServiceImpl.java index eb0abdc9b4e..ea2c1b6557d 100644 --- a/platform/platform-resources/src/main/java/org/bonitasoft/platform/configuration/impl/ConfigurationServiceImpl.java +++ b/platform/platform-resources/src/main/java/org/bonitasoft/platform/configuration/impl/ConfigurationServiceImpl.java @@ -47,7 +47,6 @@ import org.bonitasoft.platform.exception.PlatformException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; @@ -67,18 +66,10 @@ public class ConfigurationServiceImpl implements ConfigurationService { private final TransactionTemplate transactionTemplate; - @Value("${db.vendor}") - private String dbVendor; + private final String dbVendor; - @Autowired public ConfigurationServiceImpl(JdbcTemplate jdbcTemplate, - TransactionTemplate transactionTemplate) { - this.jdbcTemplate = jdbcTemplate; - this.transactionTemplate = transactionTemplate; - } - - public ConfigurationServiceImpl(JdbcTemplate jdbcTemplate, - TransactionTemplate transactionTemplate, String dbVendor) { + TransactionTemplate transactionTemplate, @Value("${db.vendor}") String dbVendor) { this.jdbcTemplate = jdbcTemplate; this.transactionTemplate = transactionTemplate; this.dbVendor = dbVendor; diff --git a/platform/platform-resources/src/main/java/org/bonitasoft/platform/configuration/util/LicensesResourceVisitor.java b/platform/platform-resources/src/main/java/org/bonitasoft/platform/configuration/util/LicensesResourceVisitor.java index b79ca6f322a..ecc860b7238 100644 --- a/platform/platform-resources/src/main/java/org/bonitasoft/platform/configuration/util/LicensesResourceVisitor.java +++ b/platform/platform-resources/src/main/java/org/bonitasoft/platform/configuration/util/LicensesResourceVisitor.java @@ -35,7 +35,7 @@ public class LicensesResourceVisitor extends SimpleFileVisitor { private final List bonitaConfigurations; - private final static Logger LOGGER = LoggerFactory.getLogger(LicensesResourceVisitor.class); + private static final Logger LOGGER = LoggerFactory.getLogger(LicensesResourceVisitor.class); private Path dir; public LicensesResourceVisitor(List bonitaConfigurations) { @@ -64,7 +64,7 @@ private void initRootFolder(Path dir) { @Override public FileVisitResult visitFile(Path path, BasicFileAttributes basicFileAttributes) throws IOException { if (isLicenseFile(path)) { - LOGGER.info("found license file: " + path.getFileName()); + LOGGER.info("Found license file: {}", path.getFileName()); bonitaConfigurations.add(new BonitaConfiguration(path.getFileName().toString(), Files.readAllBytes(path))); } return CONTINUE; diff --git a/platform/platform-resources/src/main/java/org/bonitasoft/platform/database/DatabaseVendor.java b/platform/platform-resources/src/main/java/org/bonitasoft/platform/database/DatabaseVendor.java new file mode 100644 index 00000000000..5bf20d50010 --- /dev/null +++ b/platform/platform-resources/src/main/java/org/bonitasoft/platform/database/DatabaseVendor.java @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.platform.database; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Getter +public enum DatabaseVendor { + + H2("h2"), // + MYSQL("mysql"), // + ORACLE("oracle"), // + POSTGRES("postgres"), // + SQLSERVER("sqlserver"); + + private final String value; + + public static DatabaseVendor parseValue(String databaseVendorValue) { + for (DatabaseVendor databaseVendor : DatabaseVendor.values()) { + if (databaseVendor.value.equalsIgnoreCase(databaseVendorValue)) { + return databaseVendor; + } + } + throw new IllegalArgumentException("Unknown database vendor: " + databaseVendorValue); + } + + public boolean equalsValue(String anotherValue) { + return value.equals(anotherValue); + } +} diff --git a/platform/platform-resources/src/main/java/org/bonitasoft/platform/setup/PlatformSetup.java b/platform/platform-resources/src/main/java/org/bonitasoft/platform/setup/PlatformSetup.java index bdd90982dad..fa35fa77d27 100644 --- a/platform/platform-resources/src/main/java/org/bonitasoft/platform/setup/PlatformSetup.java +++ b/platform/platform-resources/src/main/java/org/bonitasoft/platform/setup/PlatformSetup.java @@ -13,6 +13,7 @@ **/ package org.bonitasoft.platform.setup; +import static java.lang.System.lineSeparator; import static org.bonitasoft.platform.configuration.type.ConfigurationType.*; import java.io.File; @@ -30,6 +31,7 @@ import javax.sql.DataSource; +import lombok.Getter; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.io.filefilter.RegexFileFilter; @@ -38,12 +40,13 @@ import org.bonitasoft.platform.configuration.model.FullBonitaConfiguration; import org.bonitasoft.platform.configuration.model.LightBonitaConfiguration; import org.bonitasoft.platform.configuration.type.ConfigurationType; +import org.bonitasoft.platform.database.DatabaseVendor; import org.bonitasoft.platform.exception.PlatformException; import org.bonitasoft.platform.version.VersionService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; @@ -57,49 +60,70 @@ * @author Baptiste Mesta */ @Component +@ConditionalOnSingleCandidate(PlatformSetup.class) public class PlatformSetup { public static final long DEFAULT_TENANT_ID = 1L; - private static final String LINE_SEPARATOR = System.getProperty("line.separator"); public static final String BONITA_SETUP_FOLDER = "org.bonitasoft.platform.setup.folder"; - private static final Logger LOGGER = LoggerFactory.getLogger(PlatformSetup.class); - public static final String PLATFORM_CONF_FOLDER_NAME = "platform_conf"; public static final String BONITA_CLIENT_HOME_FOLDER = "bonita.client.home"; - @Autowired - private ScriptExecutor scriptExecutor; + public static final String BONITA_DB_VENDOR_PROPERTY = "sysprop.bonita.db.vendor"; + public static final String BONITA_BDM_DB_VENDOR_PROPERTY = "sysprop.bonita.bdm.db.vendor"; + + protected static final Logger LOGGER = LoggerFactory.getLogger(PlatformSetup.class); - @Autowired - private ConfigurationService configurationService; + private final ScriptExecutor scriptExecutor; - @Autowired - private VersionService versionService; + @Getter // Used by distrib bundle tests + private final ConfigurationService configurationService; - @Value("${db.vendor}") - private String dbVendor; + @Getter + private final VersionService versionService; - @Autowired - private DataSource dataSource; + private final DataSource dataSource; + + protected String dbVendor; + protected String bdmDbVendor; private Path initialConfigurationFolder; private Path currentConfigurationFolder; private Path backupConfigurationFolder; - private Path licensesFolder; + protected Path licensesFolder; private Path backupLicensesFolder; private final ResourcePatternResolver cpResourceResolver = new PathMatchingResourcePatternResolver( PlatformSetup.class.getClassLoader()); - @Autowired - PlatformSetup(ScriptExecutor scriptExecutor, ConfigurationService configurationService, - VersionService versionService, DataSource dataSource) { + public PlatformSetup(ScriptExecutor scriptExecutor, ConfigurationService configurationService, + VersionService versionService, DataSource dataSource, @Value("${db.vendor}") String dbVendor, + @Value("${bdm.db.vendor}") String bdmDbVendor) { this.scriptExecutor = scriptExecutor; this.configurationService = configurationService; this.versionService = versionService; this.dataSource = dataSource; + this.dbVendor = dbVendor; + this.bdmDbVendor = bdmDbVendor; + } + + /** + * Gets the value of the system property indicated by the key {@link PlatformSetup#BONITA_DB_VENDOR_PROPERTY} + * + * @return the string value of the system property, or null if there is no property with that key + */ + public static String getPropertyBonitaDbVendor() { + return System.getProperty(BONITA_DB_VENDOR_PROPERTY); + } + + /** + * Gets the value of the system property indicated by the key {@link PlatformSetup#BONITA_BDM_DB_VENDOR_PROPERTY} + * + * @return the string value of the system property, or null if there is no property with that key + */ + public static String getPropertyBonitaBdmDbVendor() { + return System.getProperty(BONITA_BDM_DB_VENDOR_PROPERTY); } /** @@ -110,8 +134,7 @@ public void init() throws PlatformException { if (isPlatformAlreadyCreated()) { LOGGER.info("Platform is already created."); if (Files.isDirectory(initialConfigurationFolder)) { - LOGGER.info("Upgrading default configuration with files from folder: " - + initialConfigurationFolder.toString()); + LOGGER.info("Upgrading default configuration with files from folder: {}", initialConfigurationFolder); updateDefaultConfigurationFromFolder(initialConfigurationFolder); } else { LOGGER.info("Upgrading default configuration with files from classpath"); @@ -124,14 +147,14 @@ public void init() throws PlatformException { initializePlatform(); LOGGER.info("Platform created."); if (Files.isDirectory(initialConfigurationFolder)) { - LOGGER.info("Database will be initialized with configuration files from folder: " - + initialConfigurationFolder.toString()); + LOGGER.info("Database will be initialized with configuration files from folder: {}", + initialConfigurationFolder); pushFromFolder(initialConfigurationFolder); } else { LOGGER.warn("Database will be initialized with configuration files from classpath"); insertNewConfigurationsFromClasspathIfExist(); } - pushLicenses(); + pushLicenses(true); LOGGER.info("Initial configuration files successfully pushed to database"); initializeTenant(); @@ -191,14 +214,15 @@ public void push(boolean forcePush) throws PlatformException { preventFromPushingZeroLicense(); checkPlatformVersion(); checkPushFolderExists(currentConfigurationFolder); - LOGGER.info("Configuration currently in database will be replaced by configuration from folder: " - + currentConfigurationFolder.toString()); + LOGGER.info("Configuration currently in database will be replaced by configuration from folder: {}", + currentConfigurationFolder); ensureNoCriticalFoldersAreDeleted(forcePush); pull(backupConfigurationFolder, backupLicensesFolder); - LOGGER.info("Backup directory created: {}", backupConfigurationFolder.toString()); + LOGGER.info("Backup directory created: {}", backupConfigurationFolder); + var hasLicenses = !getConfigurationService().getLicenses().isEmpty(); clean(); pushFromFolder(currentConfigurationFolder); - pushLicenses(); + pushLicenses(hasLicenses); LOGGER.info( "Configuration files successfully pushed to database. You can now restart Bonita to reflect your changes."); } @@ -211,7 +235,7 @@ private void ensureNoCriticalFoldersAreDeleted(boolean forcePush) throws Platfor final Path folder = getFolderFromConfiguration(configuration); if (!Files.isDirectory(folder)) { if (forcePush) { - LOGGER.warn("Force-pushing the deletion of folder {}", folder.toString()); + LOGGER.warn("Force-pushing the deletion of folder {}", folder); } else { throw new PlatformException("You are trying to remove a protected folder from configuration: " + getSpecificErrorMessage(configuration, folder)); @@ -238,7 +262,7 @@ private String getSpecificErrorMessage(LightBonitaConfiguration configuration, P ". To remove a tenant, please search for 'Platform API' on https://documentation.bonitasoft.com"; } return message - + LINE_SEPARATOR + + lineSeparator() + "To restore the deleted folders, run 'setup pull'. You will lose the locally modified configuration."; } @@ -313,23 +337,25 @@ private void checkPlatformVersion() throws PlatformException { /** * lookup for license file and push them to database */ - private void pushLicenses() throws PlatformException { - if (!Files.isDirectory(licensesFolder)) { - //do nothing in community - return; - } - LOGGER.info("Pushing license files from folder:{}", licensesFolder.toString()); - configurationService.storeLicenses(licensesFolder.toFile()); + protected void pushLicenses(boolean hasLicenses) throws PlatformException { + // Nothing to do in community } private void initializePlatform() throws PlatformException { scriptExecutor.createAndInitializePlatformIfNecessary(); } - void initProperties() { + void initProperties() throws PlatformException { if (dbVendor == null) { - dbVendor = System.getProperty("sysprop.bonita.db.vendor"); + dbVendor = getPropertyBonitaDbVendor(); } + checkSupportedVendor(dbVendor); + + if (bdmDbVendor == null) { + bdmDbVendor = getPropertyBonitaBdmDbVendor(); + } + checkSupportedVendor(bdmDbVendor); + String setupFolderPath = System.getProperty(BONITA_SETUP_FOLDER); Path platformConfFolder; if (setupFolderPath != null) { @@ -341,6 +367,21 @@ void initProperties() { initializeFoldersPaths(platformConfFolder); } + /** + * Check that the given `databaseVendor` is supported using the community edition. + * + * @param databaseVendor database vendor to check + * @throws PlatformException if the given database vendor is not supported + * @throws IllegalArgumentException if `databaseVendor` is null or is not a recognized database vendor + */ + protected void checkSupportedVendor(String databaseVendor) throws PlatformException, IllegalArgumentException { + DatabaseVendor vendor = DatabaseVendor.parseValue(databaseVendor); + if (vendor != DatabaseVendor.H2 && vendor != DatabaseVendor.POSTGRES) { + throw new PlatformException("Database vendor '" + vendor + "' is not supported with the community edition"); + } + LOGGER.debug("Database vendor '{}' is supported", vendor); + } + private void initializeFoldersPaths(Path platformConfFolder) { initialConfigurationFolder = platformConfFolder.resolve("initial"); currentConfigurationFolder = platformConfFolder.resolve("current"); @@ -453,17 +494,6 @@ private BonitaConfiguration getBonitaConfigurationFromClassPath(String folder, S } } - private void addConfigurationFromClassPathToList(ArrayList configurations, - ConfigurationType type, String resourceName, Long tenantId) throws IOException { - try (InputStream resourceAsStream = this.getClass() - .getResourceAsStream("/" + type.name().toLowerCase() + "/" + resourceName)) { - if (resourceAsStream != null) { - configurations.add(new FullBonitaConfiguration(resourceName, IOUtils.toByteArray(resourceAsStream), - type.name().toUpperCase(), tenantId)); - } - } - } - public void destroy() throws PlatformException { initPlatformSetup(); if (isPlatformAlreadyCreated()) { @@ -476,17 +506,12 @@ public void initPlatformSetup() throws PlatformException { initDataSource(); } - // Used by distrib bundle tests - public ConfigurationService getConfigurationService() { - return configurationService; - } - void preventFromPushingZeroLicense() throws PlatformException { if (Files.isDirectory(licensesFolder)) { final String[] licenseFiles = licensesFolder.toFile().list(new RegexFileFilter(".*\\.lic")); - if (licenseFiles.length == 0) { - throw new PlatformException("No license (.lic file) found." + LINE_SEPARATOR - + "This would prevent Bonita Platform subscription edition to start normally." + LINE_SEPARATOR + if (licenseFiles == null || licenseFiles.length == 0) { + throw new PlatformException("No license (.lic file) found." + lineSeparator() + + "This would prevent Bonita Platform subscription edition to start normally." + lineSeparator() + "Place your license file in '" + licensesFolder.toAbsolutePath().toString() + "' and then try again."); } diff --git a/platform/platform-resources/src/main/java/org/bonitasoft/platform/setup/PlatformSetupAccessor.java b/platform/platform-resources/src/main/java/org/bonitasoft/platform/setup/PlatformSetupAccessor.java index 06270955e21..8737f11689a 100644 --- a/platform/platform-resources/src/main/java/org/bonitasoft/platform/setup/PlatformSetupAccessor.java +++ b/platform/platform-resources/src/main/java/org/bonitasoft/platform/setup/PlatformSetupAccessor.java @@ -33,19 +33,30 @@ */ public class PlatformSetupAccessor { - private static PlatformSetup _INSTANCE; + private static final PlatformSetupAccessor _UNIQUE = new PlatformSetupAccessor(); - public static PlatformSetup getPlatformSetup() throws NamingException { - if (_INSTANCE == null) { - _INSTANCE = createPlatformSetup(); + private PlatformSetup instance; + + protected PlatformSetupAccessor() { + // Empty protected constructor to prevent instantiation + } + + public static PlatformSetupAccessor getInstance() { + return _UNIQUE; + } + + public PlatformSetup getPlatformSetup() throws NamingException { + if (instance == null) { + instance = initPlatformSetup(); } - return _INSTANCE; + return instance; } - private static PlatformSetup createPlatformSetup() throws NamingException { + private PlatformSetup initPlatformSetup() throws NamingException { final DataSource dataSource = lookupDataSource(); - String dbVendor = System.getProperty("sysprop.bonita.db.vendor"); - return createNewPlatformSetup(dataSource, dbVendor); + String dbVendor = PlatformSetup.getPropertyBonitaDbVendor(); + String bdmDbVendor = PlatformSetup.getPropertyBonitaBdmDbVendor(); + return createNewPlatformSetup(dataSource, dbVendor, bdmDbVendor); } /** @@ -53,15 +64,30 @@ private static PlatformSetup createPlatformSetup() throws NamingException { * * @param dataSource the datasource to use to access the database * @param dbVendor the Database vendor (default H2) to point at + * @param bdmDbVendor the BDM Database vendor (default H2) to point at * @return a NEW instance of Platform Setup */ - public static PlatformSetup createNewPlatformSetup(DataSource dataSource, String dbVendor) { + public PlatformSetup createNewPlatformSetup(DataSource dataSource, String dbVendor, String bdmDbVendor) { JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); final DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource); TransactionTemplate transactionTemplate = new TransactionTemplate(dataSourceTransactionManager); VersionService versionService = new VersionServiceImpl(jdbcTemplate); - return new PlatformSetup(new ScriptExecutor(dbVendor, dataSource, versionService), - new ConfigurationServiceImpl(jdbcTemplate, transactionTemplate, dbVendor), versionService, dataSource); + return createPlatformSetup( + createScriptExecutor(dataSource, dbVendor, versionService), + new ConfigurationServiceImpl(jdbcTemplate, transactionTemplate, dbVendor), + versionService, dataSource, dbVendor, bdmDbVendor); + } + + protected PlatformSetup createPlatformSetup(ScriptExecutor scriptExecutor, + ConfigurationService configurationService, VersionService versionService, DataSource dataSource, + String dbVendor, String bdmDbVendor) { + return new PlatformSetup(scriptExecutor, configurationService, versionService, dataSource, dbVendor, + bdmDbVendor); + } + + protected ScriptExecutor createScriptExecutor(DataSource dataSource, String dbVendor, + VersionService versionService) { + return new ScriptExecutor(dbVendor, dataSource, versionService); } private static DataSource lookupDataSource() throws NamingException { @@ -77,6 +103,6 @@ public static ConfigurationService getConfigurationService() throws NamingExcept final DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource); TransactionTemplate transactionTemplate = new TransactionTemplate(dataSourceTransactionManager); return new ConfigurationServiceImpl(jdbcTemplate, transactionTemplate, - System.getProperty("sysprop.bonita.db.vendor")); + PlatformSetup.getPropertyBonitaDbVendor()); } } diff --git a/platform/platform-resources/src/main/java/org/bonitasoft/platform/setup/ScriptExecutor.java b/platform/platform-resources/src/main/java/org/bonitasoft/platform/setup/ScriptExecutor.java index 9b9f70f88be..1639e13cf28 100644 --- a/platform/platform-resources/src/main/java/org/bonitasoft/platform/setup/ScriptExecutor.java +++ b/platform/platform-resources/src/main/java/org/bonitasoft/platform/setup/ScriptExecutor.java @@ -16,22 +16,28 @@ import static java.util.Arrays.asList; import static org.bonitasoft.platform.setup.PlatformSetup.BONITA_SETUP_FOLDER; import static org.bonitasoft.platform.setup.PlatformSetup.PLATFORM_CONF_FOLDER_NAME; +import static org.bonitasoft.platform.setup.SimpleEncryptor.encrypt; import java.io.File; import java.io.IOException; import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; +import java.security.GeneralSecurityException; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.sql.DataSource; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.bonitasoft.platform.exception.PlatformException; import org.bonitasoft.platform.version.VersionService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; import org.springframework.context.annotation.PropertySource; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; @@ -46,6 +52,7 @@ */ @Slf4j @Component +@ConditionalOnSingleCandidate(ScriptExecutor.class) @PropertySource("classpath:/application.properties") public class ScriptExecutor { @@ -59,7 +66,7 @@ public class ScriptExecutor { private final String dbVendor; - private VersionService versionService; + private final VersionService versionService; @Autowired public ScriptExecutor(@Value("${db.vendor}") String dbVendor, DataSource datasource, @@ -69,7 +76,7 @@ public ScriptExecutor(@Value("${db.vendor}") String dbVendor, DataSource datasou } this.dbVendor = dbVendor; this.datasource = datasource; - log.info("configuration for Database vendor: " + dbVendor); + log.info("configuration for Database vendor: {}", dbVendor); this.sqlFolder = "/sql/" + dbVendor; this.versionService = versionService; } @@ -104,14 +111,24 @@ protected void insertPlatform() { String version = versionService.getPlatformSetupVersion(); String databaseSchemaVersion = versionService.getSupportedDatabaseSchemaVersion(); - final String sql = "INSERT INTO platform (id, version, initial_bonita_version, application_version, maintenance_message_active, created, created_by) " - + "VALUES (?, ?, ?, ?, ?, ?, ?)"; + final String sql = "INSERT INTO platform (id, version, initial_bonita_version, application_version, " + + "maintenance_message_active, created, created_by, information) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; new JdbcTemplate(datasource).update(sql, 1L, databaseSchemaVersion, version, "0.0.0", false, - System.currentTimeMillis(), "platformAdmin"); + System.currentTimeMillis(), "platformAdmin", getInformationInitialValue()); } - private void insertTenant() { + protected String getInformationInitialValue() { + try { + return encrypt(new ObjectMapper().writeValueAsBytes(new ArrayList())); + } catch (GeneralSecurityException | JsonProcessingException e) { + log.debug(e.getMessage(), e); + throw new IllegalStateException("Cannot properly setup Bonita platform"); + } + } + + protected void insertTenant() { final String sql = "INSERT INTO tenant (id, created, createdBy, description, defaultTenant, name, status) " + "VALUES (?, ?, ?, ?, ?, ?, ?)"; @@ -187,19 +204,10 @@ protected void executeSQLResource(final String sqlFile, boolean shouldContinueOn populate.setContinueOnError(shouldContinueOnError); populate.setIgnoreFailedDrops(true); populate.addScript(sqlResource); - populate.setSeparator(getSeparator()); populate.execute(datasource); log.info("Executed SQL script " + sqlResource.getURL().getFile()); } - private String getSeparator() { - if ("sqlserver".equals(dbVendor)) { - return "GO"; - } else { - return ";"; - } - } - public void initializePlatformStructure() throws PlatformException { try { executeSQLResources(Collections.singletonList("initTables.sql"), FAIL_ON_ERROR); diff --git a/platform/platform-resources/src/main/java/org/bonitasoft/platform/setup/SimpleEncryptor.java b/platform/platform-resources/src/main/java/org/bonitasoft/platform/setup/SimpleEncryptor.java new file mode 100644 index 00000000000..1a1e238ca40 --- /dev/null +++ b/platform/platform-resources/src/main/java/org/bonitasoft/platform/setup/SimpleEncryptor.java @@ -0,0 +1,65 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.platform.setup; + +import java.security.GeneralSecurityException; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.util.Base64; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; + +/** + * @author Emmanuel Duchastenier + */ +public final class SimpleEncryptor { + + private static final byte[] SALT = new byte[] { 0x47, 0x6f, 0x6f, 0x64, 0x4a, 0x6f, 0x62, 0x21 }; + private static final char[] PASSPHRASE = new String(new byte[] { 0x48, 0x34, 0x76, 0x33, 0x46, 0x75, 0x6e, + 0x57, 0x31, 0x37, 0x68, 0x38, 0x30, 0x6e, 0x31, 0x37, 0x34 }).toCharArray(); + + private static final SecretKey SECRET_KEY = SimpleEncryptor.generateKey(); + + private SimpleEncryptor() { + } + + public static SecretKey generateKey() { + try { + SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); + KeySpec spec = new PBEKeySpec(PASSPHRASE, SALT, 1000, 256); + return new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES"); + } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { + throw new IllegalStateException(e); + } + } + + public static String encrypt(byte[] data) throws GeneralSecurityException { + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.ENCRYPT_MODE, SECRET_KEY); + byte[] encryptedBytes = cipher.doFinal(data); + return Base64.getEncoder().encodeToString(encryptedBytes); + } + + public static byte[] decrypt(String encryptedData) throws GeneralSecurityException { + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.DECRYPT_MODE, SECRET_KEY); + byte[] decodedBytes = Base64.getDecoder().decode(encryptedData); + return cipher.doFinal(decodedBytes); + } +} diff --git a/platform/platform-resources/src/main/java/org/bonitasoft/platform/version/VersionService.java b/platform/platform-resources/src/main/java/org/bonitasoft/platform/version/VersionService.java index b47f880c0b2..0bb91a91661 100644 --- a/platform/platform-resources/src/main/java/org/bonitasoft/platform/version/VersionService.java +++ b/platform/platform-resources/src/main/java/org/bonitasoft/platform/version/VersionService.java @@ -27,6 +27,21 @@ public interface VersionService { */ String retrieveDatabaseSchemaVersion() throws PlatformException; + /** + * Retrieves the platform information in database + * + * @return platform information + * @throws PlatformException + */ + String retrievePlatformInformation() throws PlatformException; + + /** + * Clear platform information + * + * @throws PlatformException + */ + void clearPlatformInformation() throws PlatformException; + /** * Retrieves the platform setup tool version * diff --git a/platform/platform-resources/src/main/java/org/bonitasoft/platform/version/impl/VersionServiceImpl.java b/platform/platform-resources/src/main/java/org/bonitasoft/platform/version/impl/VersionServiceImpl.java index 9cfc46b226d..10c414a465a 100644 --- a/platform/platform-resources/src/main/java/org/bonitasoft/platform/version/impl/VersionServiceImpl.java +++ b/platform/platform-resources/src/main/java/org/bonitasoft/platform/version/impl/VersionServiceImpl.java @@ -33,7 +33,9 @@ @Service public class VersionServiceImpl implements VersionService { - private static final String SQL_PLATFORM_VERSION = "SELECT p.version FROM platform p ORDER BY p.id"; + private static final String SQL_PLATFORM_VERSION = "SELECT p.version FROM platform p"; + private static final String SQL_PLATFORM_INFORMATION = "SELECT p.information FROM platform p"; + private static final String SQL_CLEAR_PLATFORM_INFORMATION = "UPDATE platform SET information = NULL"; private JdbcTemplate jdbcTemplate; @@ -56,6 +58,29 @@ public String retrieveDatabaseSchemaVersion() throws PlatformException { return strings.get(0); } + @Override + public String retrievePlatformInformation() throws PlatformException { + final List strings; + try { + strings = jdbcTemplate.queryForList(SQL_PLATFORM_INFORMATION, String.class); + } catch (DataAccessException e) { + throw new PlatformException("Platform is not created. Run 'setup init' first.", e); + } + if (hasNotSingleResult(strings)) { + throw new PlatformException("Platform is not created. Run 'setup init' first."); + } + return strings.get(0); + } + + @Override + public void clearPlatformInformation() throws PlatformException { + try { + jdbcTemplate.execute(SQL_CLEAR_PLATFORM_INFORMATION); + } catch (DataAccessException e) { + throw new PlatformException("Unable to clear platform information", e); + } + } + private boolean hasNotSingleResult(List strings) { return strings == null || strings.size() != 1; } diff --git a/platform/platform-resources/src/main/resources/sql/h2/createTables.sql b/platform/platform-resources/src/main/resources/sql/h2/createTables.sql index 280bfadcdf4..50421277bb4 100644 --- a/platform/platform-resources/src/main/resources/sql/h2/createTables.sql +++ b/platform/platform-resources/src/main/resources/sql/h2/createTables.sql @@ -524,7 +524,8 @@ CREATE TABLE business_app ( iconContent LONGBLOB, displayName VARCHAR(255) NOT NULL, editable BOOLEAN, - internalProfile VARCHAR(255) + internalProfile VARCHAR(255), + isLink BOOLEAN DEFAULT FALSE ); ALTER TABLE business_app ADD CONSTRAINT pk_business_app PRIMARY KEY (tenantid, id); diff --git a/platform/platform-resources/src/main/resources/sql/mysql/cleanTables.sql b/platform/platform-resources/src/main/resources/sql/mysql/cleanTables.sql deleted file mode 100644 index d6aa4cf7ca4..00000000000 --- a/platform/platform-resources/src/main/resources/sql/mysql/cleanTables.sql +++ /dev/null @@ -1,61 +0,0 @@ -DELETE FROM arch_contract_data; -DELETE FROM contract_data; -DELETE FROM actormember; -DELETE FROM actor; -DELETE FROM processcategorymapping; -DELETE FROM category; -DELETE FROM arch_process_comment; -DELETE FROM process_comment; -DELETE FROM process_definition; -DELETE FROM arch_document_mapping; -DELETE FROM document; -DELETE FROM document_mapping; -DELETE FROM arch_flownode_instance; -DELETE FROM arch_process_instance; -DELETE FROM arch_connector_instance; -DELETE FROM arch_multi_biz_data; -DELETE FROM arch_ref_biz_data_inst; -DELETE FROM multi_biz_data; -DELETE FROM ref_biz_data_inst; -DELETE FROM pending_mapping; -DELETE FROM message_instance; -DELETE FROM waiting_event; -DELETE FROM event_trigger_instance; -DELETE FROM connector_instance; -DELETE FROM flownode_instance; -DELETE FROM process_instance; -DELETE FROM processsupervisor; -DELETE FROM business_app_menu; -DELETE FROM business_app_page; -DELETE FROM business_app; -DELETE FROM command; -DELETE FROM arch_data_instance; -DELETE FROM data_instance; -DELETE FROM dependencymapping; -DELETE FROM dependency; -DELETE FROM external_identity_mapping; -DELETE FROM user_membership; -DELETE FROM custom_usr_inf_val; -DELETE FROM custom_usr_inf_def; -DELETE FROM user_contactinfo; -DELETE FROM user_login; -DELETE FROM user_; -DELETE FROM role; -DELETE FROM group_; -DELETE FROM queriablelog_p; -DELETE FROM queriable_log; -DELETE FROM page; -DELETE FROM sequence WHERE tenantId <> -1; -DELETE FROM profilemember; -DELETE FROM profile; -DELETE FROM job_log; -DELETE FROM job_param; -DELETE FROM job_desc; -DELETE FROM tenant; -DELETE FROM platformCommand; -DELETE FROM form_mapping; -DELETE FROM page_mapping; -DELETE FROM proc_parameter; - --- do NOT clear directly PLATFORM table, Hibernate needs to update its cache to know the platform has been deleted - \ No newline at end of file diff --git a/platform/platform-resources/src/main/resources/sql/mysql/createQuartzTables.sql b/platform/platform-resources/src/main/resources/sql/mysql/createQuartzTables.sql deleted file mode 100644 index dc58cf96405..00000000000 --- a/platform/platform-resources/src/main/resources/sql/mysql/createQuartzTables.sql +++ /dev/null @@ -1,260 +0,0 @@ -CREATE TABLE QRTZ_CALENDARS ( - SCHED_NAME VARCHAR(120) NOT NULL, - CALENDAR_NAME VARCHAR (200) NOT NULL , - CALENDAR MEDIUMBLOB NOT NULL -) ENGINE = INNODB; - -CREATE TABLE QRTZ_CRON_TRIGGERS ( - SCHED_NAME VARCHAR(120) NOT NULL, - TRIGGER_NAME VARCHAR (200) NOT NULL , - TRIGGER_GROUP VARCHAR (200) NOT NULL , - CRON_EXPRESSION VARCHAR (120) NOT NULL , - TIME_ZONE_ID VARCHAR (80) -) ENGINE = INNODB; - -CREATE TABLE QRTZ_FIRED_TRIGGERS ( - SCHED_NAME VARCHAR(120) NOT NULL, - ENTRY_ID VARCHAR (95) NOT NULL , - TRIGGER_NAME VARCHAR (200) NOT NULL , - TRIGGER_GROUP VARCHAR (200) NOT NULL , - INSTANCE_NAME VARCHAR (200) NOT NULL , - FIRED_TIME BIGINT NOT NULL , - SCHED_TIME BIGINT NOT NULL , - PRIORITY INTEGER NOT NULL , - STATE VARCHAR (16) NOT NULL, - JOB_NAME VARCHAR (200) NULL , - JOB_GROUP VARCHAR (200) NULL , - IS_NONCONCURRENT BOOLEAN NULL , - REQUESTS_RECOVERY BOOLEAN NULL -) ENGINE = INNODB; - -CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS ( - SCHED_NAME VARCHAR(120) NOT NULL, - TRIGGER_GROUP VARCHAR (200) NOT NULL -) ENGINE = INNODB; - -CREATE TABLE QRTZ_SCHEDULER_STATE ( - SCHED_NAME VARCHAR(120) NOT NULL, - INSTANCE_NAME VARCHAR (200) NOT NULL , - LAST_CHECKIN_TIME BIGINT NOT NULL , - CHECKIN_INTERVAL BIGINT NOT NULL -) ENGINE = INNODB; - -CREATE TABLE QRTZ_LOCKS ( - SCHED_NAME VARCHAR(120) NOT NULL, - LOCK_NAME VARCHAR (40) NOT NULL -) ENGINE = INNODB; - -CREATE TABLE QRTZ_JOB_DETAILS ( - SCHED_NAME VARCHAR(120) NOT NULL, - JOB_NAME VARCHAR (200) NOT NULL , - JOB_GROUP VARCHAR (200) NOT NULL , - DESCRIPTION VARCHAR (250) NULL , - JOB_CLASS_NAME VARCHAR (250) NOT NULL , - IS_DURABLE BOOLEAN NOT NULL , - IS_NONCONCURRENT BOOLEAN NOT NULL , - IS_UPDATE_DATA BOOLEAN NOT NULL , - REQUESTS_RECOVERY BOOLEAN NOT NULL , - JOB_DATA MEDIUMBLOB NULL -) ENGINE = INNODB; - -CREATE TABLE QRTZ_SIMPLE_TRIGGERS ( - SCHED_NAME VARCHAR(120) NOT NULL, - TRIGGER_NAME VARCHAR (200) NOT NULL , - TRIGGER_GROUP VARCHAR (200) NOT NULL , - REPEAT_COUNT BIGINT NOT NULL , - REPEAT_INTERVAL BIGINT NOT NULL , - TIMES_TRIGGERED BIGINT NOT NULL -) ENGINE = INNODB; - -CREATE TABLE QRTZ_SIMPROP_TRIGGERS - ( - SCHED_NAME VARCHAR(120) NOT NULL, - TRIGGER_NAME VARCHAR(200) NOT NULL, - TRIGGER_GROUP VARCHAR(200) NOT NULL, - STR_PROP_1 VARCHAR(512) NULL, - STR_PROP_2 VARCHAR(512) NULL, - STR_PROP_3 VARCHAR(512) NULL, - INT_PROP_1 INTEGER NULL, - INT_PROP_2 INTEGER NULL, - LONG_PROP_1 BIGINT NULL, - LONG_PROP_2 BIGINT NULL, - DEC_PROP_1 NUMERIC(13,4) NULL, - DEC_PROP_2 NUMERIC(13,4) NULL, - BOOL_PROP_1 BOOLEAN NULL, - BOOL_PROP_2 BOOLEAN NULL -) ENGINE = INNODB; - -CREATE TABLE QRTZ_BLOB_TRIGGERS ( - SCHED_NAME VARCHAR(120) NOT NULL, - TRIGGER_NAME VARCHAR (200) NOT NULL , - TRIGGER_GROUP VARCHAR (200) NOT NULL , - BLOB_DATA MEDIUMBLOB NULL -) ENGINE = INNODB; - -CREATE TABLE QRTZ_TRIGGERS ( - SCHED_NAME VARCHAR(120) NOT NULL, - TRIGGER_NAME VARCHAR (200) NOT NULL , - TRIGGER_GROUP VARCHAR (200) NOT NULL , - JOB_NAME VARCHAR (200) NOT NULL , - JOB_GROUP VARCHAR (200) NOT NULL , - DESCRIPTION VARCHAR (250) NULL , - NEXT_FIRE_TIME BIGINT NULL , - PREV_FIRE_TIME BIGINT NULL , - PRIORITY INTEGER NULL , - TRIGGER_STATE VARCHAR (16) NOT NULL , - TRIGGER_TYPE VARCHAR (8) NOT NULL , - START_TIME BIGINT NOT NULL , - END_TIME BIGINT NULL , - CALENDAR_NAME VARCHAR (200) NULL , - MISFIRE_INSTR SMALLINT NULL , - JOB_DATA MEDIUMBLOB NULL -) ENGINE = INNODB; - -ALTER TABLE QRTZ_CALENDARS ADD - CONSTRAINT PK_QRTZ_CALENDARS PRIMARY KEY - ( - SCHED_NAME, - CALENDAR_NAME - ); - -ALTER TABLE QRTZ_CRON_TRIGGERS ADD - CONSTRAINT PK_QRTZ_CRON_TRIGGERS PRIMARY KEY - ( - SCHED_NAME, - TRIGGER_NAME, - TRIGGER_GROUP - ); - -ALTER TABLE QRTZ_FIRED_TRIGGERS ADD - CONSTRAINT PK_QRTZ_FIRED_TRIGGERS PRIMARY KEY - ( - SCHED_NAME, - ENTRY_ID - ); - -ALTER TABLE QRTZ_PAUSED_TRIGGER_GRPS ADD - CONSTRAINT PK_QRTZ_PAUSED_TRIGGER_GRPS PRIMARY KEY - ( - SCHED_NAME, - TRIGGER_GROUP - ); - -ALTER TABLE QRTZ_SCHEDULER_STATE ADD - CONSTRAINT PK_QRTZ_SCHEDULER_STATE PRIMARY KEY - ( - SCHED_NAME, - INSTANCE_NAME - ); - -ALTER TABLE QRTZ_LOCKS ADD - CONSTRAINT PK_QRTZ_LOCKS PRIMARY KEY - ( - SCHED_NAME, - LOCK_NAME - ); - -ALTER TABLE QRTZ_JOB_DETAILS ADD - CONSTRAINT PK_QRTZ_JOB_DETAILS PRIMARY KEY - ( - SCHED_NAME, - JOB_NAME, - JOB_GROUP - ); - -ALTER TABLE QRTZ_SIMPLE_TRIGGERS ADD - CONSTRAINT PK_QRTZ_SIMPLE_TRIGGERS PRIMARY KEY - ( - SCHED_NAME, - TRIGGER_NAME, - TRIGGER_GROUP - ); - -ALTER TABLE QRTZ_SIMPROP_TRIGGERS ADD - CONSTRAINT PK_QRTZ_SIMPROP_TRIGGERS PRIMARY KEY - ( - SCHED_NAME, - TRIGGER_NAME, - TRIGGER_GROUP - ); - -ALTER TABLE QRTZ_TRIGGERS ADD - CONSTRAINT PK_QRTZ_TRIGGERS PRIMARY KEY - ( - SCHED_NAME, - TRIGGER_NAME, - TRIGGER_GROUP - ); - -ALTER TABLE QRTZ_CRON_TRIGGERS ADD - CONSTRAINT FK_QRTZ_CRON_TRIGGERS FOREIGN KEY - ( - SCHED_NAME, - TRIGGER_NAME, - TRIGGER_GROUP - ) REFERENCES QRTZ_TRIGGERS ( - SCHED_NAME, - TRIGGER_NAME, - TRIGGER_GROUP - ) ON DELETE CASCADE; - - -ALTER TABLE QRTZ_SIMPLE_TRIGGERS ADD - CONSTRAINT FK_QRTZ_SIMPLE_TRIGGERS FOREIGN KEY - ( - SCHED_NAME, - TRIGGER_NAME, - TRIGGER_GROUP - ) REFERENCES QRTZ_TRIGGERS ( - SCHED_NAME, - TRIGGER_NAME, - TRIGGER_GROUP - ) ON DELETE CASCADE; - -ALTER TABLE QRTZ_SIMPROP_TRIGGERS ADD - CONSTRAINT FK_QRTZ_SIMPROP_TRIGGERS FOREIGN KEY - ( - SCHED_NAME, - TRIGGER_NAME, - TRIGGER_GROUP - ) REFERENCES QRTZ_TRIGGERS ( - SCHED_NAME, - TRIGGER_NAME, - TRIGGER_GROUP - ) ON DELETE CASCADE; - - -ALTER TABLE QRTZ_TRIGGERS ADD - CONSTRAINT FK_QRTZ_TRIGGERS FOREIGN KEY - ( - SCHED_NAME, - JOB_NAME, - JOB_GROUP - ) REFERENCES QRTZ_JOB_DETAILS ( - SCHED_NAME, - JOB_NAME, - JOB_GROUP - ); - -CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY); -CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP); - -CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP); -CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP); -CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME); -CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP); -CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE); -CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE); -CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE); -CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME); -CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME); -CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME); -CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE); -CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE); - -CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME); -CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY); -CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP); -CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP); -CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP); -CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP); diff --git a/platform/platform-resources/src/main/resources/sql/mysql/createTables.sql b/platform/platform-resources/src/main/resources/sql/mysql/createTables.sql deleted file mode 100644 index 3ed0a471858..00000000000 --- a/platform/platform-resources/src/main/resources/sql/mysql/createTables.sql +++ /dev/null @@ -1,1053 +0,0 @@ -CREATE TABLE configuration ( - tenant_id BIGINT NOT NULL, - content_type VARCHAR(50) NOT NULL, - resource_name VARCHAR(120) NOT NULL, - resource_content BLOB -) ENGINE = INNODB; -ALTER TABLE configuration ADD CONSTRAINT pk_configuration PRIMARY KEY (tenant_id, content_type, resource_name); -CREATE INDEX idx_configuration ON configuration (tenant_id, content_type); - -CREATE TABLE contract_data ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - kind VARCHAR(20) NOT NULL, - scopeId BIGINT NOT NULL, - name VARCHAR(50) NOT NULL, - val LONGTEXT -) ENGINE = INNODB; -ALTER TABLE contract_data ADD CONSTRAINT pk_contract_data PRIMARY KEY (tenantid, id, scopeId); -ALTER TABLE contract_data ADD CONSTRAINT uc_cd_scope_name UNIQUE (kind, scopeId, name, tenantid); -CREATE INDEX idx_cd_scope_name ON contract_data (kind, scopeId, name, tenantid); - -CREATE TABLE arch_contract_data ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - kind VARCHAR(20) NOT NULL, - scopeId BIGINT NOT NULL, - name VARCHAR(50) NOT NULL, - val LONGTEXT, - archiveDate BIGINT NOT NULL, - sourceObjectId BIGINT NOT NULL -) ENGINE = INNODB; -ALTER TABLE arch_contract_data ADD CONSTRAINT pk_arch_contract_data PRIMARY KEY (tenantid, id, scopeId); -ALTER TABLE arch_contract_data ADD CONSTRAINT uc_acd_scope_name UNIQUE (kind, scopeId, name, tenantid); -CREATE INDEX idx_acd_scope_name ON arch_contract_data (kind, scopeId, name, tenantid); - -CREATE TABLE actor ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - scopeId BIGINT NOT NULL, - name VARCHAR(50) NOT NULL, - displayName VARCHAR(75), - description TEXT, - initiator BOOLEAN, - UNIQUE (tenantid, id, scopeId, name), - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; - -CREATE TABLE actormember ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - actorId BIGINT NOT NULL, - userId BIGINT NOT NULL, - groupId BIGINT NOT NULL, - roleId BIGINT NOT NULL, - UNIQUE (tenantid, actorid, userId, groupId, roleId), - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -CREATE TABLE category ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - name VARCHAR(50) NOT NULL, - creator BIGINT, - description TEXT, - creationDate BIGINT NOT NULL, - lastUpdateDate BIGINT NOT NULL, - UNIQUE (tenantid, name), - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; - -CREATE TABLE processcategorymapping ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - categoryid BIGINT NOT NULL, - processid BIGINT NOT NULL, - UNIQUE (tenantid, categoryid, processid), - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; - -ALTER TABLE processcategorymapping ADD CONSTRAINT fk_catmapping_catid FOREIGN KEY (tenantid, categoryid) REFERENCES category(tenantid, id) ON DELETE CASCADE; - -CREATE TABLE arch_process_comment( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - userId BIGINT, - processInstanceId BIGINT NOT NULL, - postDate BIGINT NOT NULL, - content VARCHAR(512) NOT NULL, - archiveDate BIGINT NOT NULL, - sourceObjectId BIGINT NOT NULL, - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -CREATE INDEX idx1_arch_process_comment on arch_process_comment (sourceobjectid, tenantid); -CREATE INDEX idx2_arch_process_comment on arch_process_comment (processInstanceId, archivedate, tenantid); - -CREATE TABLE process_comment ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - kind VARCHAR(25) NOT NULL, - userId BIGINT, - processInstanceId BIGINT NOT NULL, - postDate BIGINT NOT NULL, - content VARCHAR(512) NOT NULL, - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -CREATE INDEX idx1_process_comment on process_comment (processInstanceId, tenantid); - -CREATE TABLE process_definition ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - processId BIGINT NOT NULL, - name VARCHAR(150) NOT NULL, - version VARCHAR(50) NOT NULL, - description VARCHAR(255), - deploymentDate BIGINT NOT NULL, - deployedBy BIGINT NOT NULL, - activationState VARCHAR(30) NOT NULL, - configurationState VARCHAR(30) NOT NULL, - displayName VARCHAR(75), - displayDescription VARCHAR(255), - lastUpdateDate BIGINT, - categoryId BIGINT, - iconPath VARCHAR(255), - content_tenantid BIGINT NOT NULL, - content_id BIGINT NOT NULL, - PRIMARY KEY (tenantid, id), - UNIQUE (tenantid, name, version) -) ENGINE = INNODB; -CREATE TABLE process_content ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - content MEDIUMTEXT NOT NULL, - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -CREATE TABLE arch_document_mapping ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - sourceObjectId BIGINT, - processinstanceid BIGINT NOT NULL, - documentid BIGINT NOT NULL, - name VARCHAR(50) NOT NULL, - description TEXT, - version VARCHAR(50) NOT NULL, - index_ INT NOT NULL, - archiveDate BIGINT NOT NULL, - PRIMARY KEY (tenantid, ID) -) ENGINE = INNODB; -CREATE INDEX idx_a_doc_mp_pr_id ON arch_document_mapping (processinstanceid, tenantid); - -CREATE TABLE document ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - author BIGINT, - creationdate BIGINT NOT NULL, - hascontent BOOLEAN NOT NULL, - filename VARCHAR(255), - mimetype VARCHAR(255), - url VARCHAR(1024), - content LONGBLOB, - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; - -CREATE TABLE document_mapping ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - processinstanceid BIGINT NOT NULL, - documentid BIGINT NOT NULL, - name VARCHAR(50) NOT NULL, - description TEXT, - version VARCHAR(50) NOT NULL, - index_ INT NOT NULL, - PRIMARY KEY (tenantid, ID) -) ENGINE = INNODB; - -CREATE TABLE arch_process_instance ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - name VARCHAR(75) NOT NULL, - processDefinitionId BIGINT NOT NULL, - description VARCHAR(255), - startDate BIGINT NOT NULL, - startedBy BIGINT NOT NULL, - startedBySubstitute BIGINT NOT NULL, - endDate BIGINT NOT NULL, - archiveDate BIGINT NOT NULL, - stateId INT NOT NULL, - lastUpdate BIGINT NOT NULL, - rootProcessInstanceId BIGINT, - callerId BIGINT, - sourceObjectId BIGINT NOT NULL, - stringIndex1 VARCHAR(255), - stringIndex2 VARCHAR(255), - stringIndex3 VARCHAR(255), - stringIndex4 VARCHAR(255), - stringIndex5 VARCHAR(255), - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -CREATE INDEX idx1_arch_process_instance ON arch_process_instance (tenantId, sourceObjectId, rootProcessInstanceId, callerId); -CREATE INDEX idx2_arch_process_instance ON arch_process_instance (tenantId, processDefinitionId, archiveDate); -CREATE INDEX idx3_arch_process_instance ON arch_process_instance (tenantId, sourceObjectId, callerId, stateId); - -CREATE TABLE arch_flownode_instance ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - flownodeDefinitionId BIGINT NOT NULL, - kind VARCHAR(25) NOT NULL, - sourceObjectId BIGINT, - archiveDate BIGINT NOT NULL, - rootContainerId BIGINT NOT NULL, - parentContainerId BIGINT NOT NULL, - name VARCHAR(255) NOT NULL, - displayName VARCHAR(255), - displayDescription VARCHAR(255), - stateId INT NOT NULL, - stateName VARCHAR(50), - terminal BOOLEAN NOT NULL, - stable BOOLEAN , - actorId BIGINT NULL, - assigneeId BIGINT DEFAULT 0 NOT NULL, - reachedStateDate BIGINT, - lastUpdateDate BIGINT, - expectedEndDate BIGINT, - claimedDate BIGINT, - priority TINYINT, - gatewayType VARCHAR(50), - hitBys VARCHAR(255), - logicalGroup1 BIGINT NOT NULL, - logicalGroup2 BIGINT NOT NULL, - logicalGroup3 BIGINT, - logicalGroup4 BIGINT NOT NULL, - loop_counter INT, - loop_max INT, - loopCardinality INT, - loopDataInputRef VARCHAR(255), - loopDataOutputRef VARCHAR(255), - description VARCHAR(255), - sequential BOOLEAN, - dataInputItemRef VARCHAR(255), - dataOutputItemRef VARCHAR(255), - nbActiveInst INT, - nbCompletedInst INT, - nbTerminatedInst INT, - executedBy BIGINT, - executedBySubstitute BIGINT, - activityInstanceId BIGINT, - aborting BOOLEAN NOT NULL, - triggeredByEvent BOOLEAN, - interrupting BOOLEAN, - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -CREATE INDEX idx_afi_kind_lg2_executedBy ON arch_flownode_instance(logicalGroup2, tenantId, kind, executedBy); -CREATE INDEX idx_afi_kind_lg3 ON arch_flownode_instance(tenantId, kind, logicalGroup3); -CREATE INDEX idx_afi_kind_lg4 ON arch_flownode_instance(tenantId, logicalGroup4); -CREATE INDEX idx_afi_sourceId_tenantid_kind ON arch_flownode_instance (sourceObjectId, tenantid, kind); -CREATE INDEX idx1_arch_flownode_instance ON arch_flownode_instance (tenantId, rootContainerId, parentContainerId); -CREATE INDEX idx_lg4_lg2 on arch_flownode_instance(tenantid, logicalGroup4, logicalGroup2); - -CREATE TABLE arch_connector_instance ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - containerId BIGINT NOT NULL, - containerType VARCHAR(10) NOT NULL, - connectorId VARCHAR(255) NOT NULL, - version VARCHAR(50) NOT NULL, - name VARCHAR(255) NOT NULL, - activationEvent VARCHAR(30), - state VARCHAR(50), - sourceObjectId BIGINT, - archiveDate BIGINT NOT NULL, - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; - -CREATE INDEX idx1_arch_connector_instance ON arch_connector_instance (tenantId, containerId, containerType); -CREATE TABLE process_instance ( - id BIGINT NOT NULL, - name VARCHAR(75) NOT NULL, - processDefinitionId BIGINT NOT NULL, - description VARCHAR(255), - startDate BIGINT NOT NULL, - startedBy BIGINT NOT NULL, - startedBySubstitute BIGINT NOT NULL, - endDate BIGINT NOT NULL, - stateId INT NOT NULL, - stateCategory VARCHAR(50) NOT NULL, - lastUpdate BIGINT NOT NULL, - containerId BIGINT, - rootProcessInstanceId BIGINT, - callerId BIGINT, - callerType VARCHAR(50), - interruptingEventId BIGINT, - stringIndex1 VARCHAR(255), - stringIndex2 VARCHAR(255), - stringIndex3 VARCHAR(255), - stringIndex4 VARCHAR(255), - stringIndex5 VARCHAR(255), - PRIMARY KEY (id) -) ENGINE = INNODB; - -CREATE INDEX idx1_proc_inst_pdef_state ON process_instance (processdefinitionid, stateid); - -CREATE TABLE flownode_instance ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - flownodeDefinitionId BIGINT NOT NULL, - kind VARCHAR(25) NOT NULL, - rootContainerId BIGINT NOT NULL, - parentContainerId BIGINT NOT NULL, - name VARCHAR(255) NOT NULL, - displayName VARCHAR(255), - displayDescription VARCHAR(255), - stateId INT NOT NULL, - stateName VARCHAR(50), - prev_state_id INT NOT NULL, - terminal BOOLEAN NOT NULL, - stable BOOLEAN , - actorId BIGINT NULL, - assigneeId BIGINT DEFAULT 0 NOT NULL, - reachedStateDate BIGINT, - lastUpdateDate BIGINT, - expectedEndDate BIGINT, - claimedDate BIGINT, - priority TINYINT, - gatewayType VARCHAR(50), - hitBys VARCHAR(255), - stateCategory VARCHAR(50) NOT NULL, - logicalGroup1 BIGINT NOT NULL, - logicalGroup2 BIGINT NOT NULL, - logicalGroup3 BIGINT, - logicalGroup4 BIGINT NOT NULL, - loop_counter INT, - loop_max INT, - description VARCHAR(255), - sequential BOOLEAN, - loopDataInputRef VARCHAR(255), - loopDataOutputRef VARCHAR(255), - dataInputItemRef VARCHAR(255), - dataOutputItemRef VARCHAR(255), - loopCardinality INT, - nbActiveInst INT, - nbCompletedInst INT, - nbTerminatedInst INT, - executedBy BIGINT, - executedBySubstitute BIGINT, - activityInstanceId BIGINT, - state_executing BOOLEAN DEFAULT FALSE, - abortedByBoundary BIGINT, - triggeredByEvent BOOLEAN, - interrupting BOOLEAN, - tokenCount INT NOT NULL, - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -CREATE INDEX idx_fni_rootcontid ON flownode_instance (rootContainerId); -CREATE INDEX idx_fni_loggroup4 ON flownode_instance (logicalGroup4); -CREATE INDEX idx_fni_loggroup3_terminal ON flownode_instance(logicalgroup3, terminal, tenantid); -CREATE INDEX idx_fn_lg2_state_tenant_del ON flownode_instance (logicalGroup2, stateName, tenantid); -CREATE INDEX idx_fni_activity_instance_id_kind ON flownode_instance(activityInstanceId, kind, tenantid); - -CREATE TABLE connector_instance ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - containerId BIGINT NOT NULL, - containerType VARCHAR(10) NOT NULL, - connectorId VARCHAR(255) NOT NULL, - version VARCHAR(50) NOT NULL, - name VARCHAR(255) NOT NULL, - activationEvent VARCHAR(30), - state VARCHAR(50), - executionOrder INT, - exceptionMessage VARCHAR(255), - stackTrace TEXT, - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -CREATE INDEX idx_ci_container_activation ON connector_instance (tenantid, containerId, containerType, activationEvent); - -CREATE TABLE event_trigger_instance ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - eventInstanceId BIGINT NOT NULL, - eventInstanceName VARCHAR(50), - executionDate BIGINT, - jobTriggerName VARCHAR(255), - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; - -CREATE TABLE waiting_event ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - kind VARCHAR(15) NOT NULL, - eventType VARCHAR(50), - messageName VARCHAR(255), - signalName VARCHAR(255), - errorCode VARCHAR(255), - processName VARCHAR(150), - flowNodeName VARCHAR(50), - flowNodeDefinitionId BIGINT, - subProcessId BIGINT, - processDefinitionId BIGINT, - rootProcessInstanceId BIGINT, - parentProcessInstanceId BIGINT, - flowNodeInstanceId BIGINT, - relatedActivityInstanceId BIGINT, - locked BOOLEAN, - active BOOLEAN, - progress TINYINT, - correlation1 VARCHAR(128), - correlation2 VARCHAR(128), - correlation3 VARCHAR(128), - correlation4 VARCHAR(128), - correlation5 VARCHAR(128), - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -CREATE INDEX idx_waiting_event ON waiting_event (progress, tenantid, kind, locked, active); -CREATE INDEX idx_waiting_event_correl ON waiting_event (correlation1, correlation2, correlation3, correlation4, correlation5); - -CREATE TABLE message_instance ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - messageName VARCHAR(255) NOT NULL, - targetProcess VARCHAR(255) NOT NULL, - targetFlowNode VARCHAR(255) NULL, - locked BOOLEAN NOT NULL, - handled BOOLEAN NOT NULL, - processDefinitionId BIGINT NOT NULL, - flowNodeName VARCHAR(255), - correlation1 VARCHAR(128), - correlation2 VARCHAR(128), - correlation3 VARCHAR(128), - correlation4 VARCHAR(128), - correlation5 VARCHAR(128), - creationDate BIGINT NOT NULL, - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -CREATE INDEX idx_message_instance ON message_instance (messageName, targetProcess, correlation1, correlation2); -CREATE INDEX idx_message_instance_correl ON message_instance (correlation1, correlation2, correlation3, correlation4, correlation5); - -CREATE TABLE pending_mapping ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - activityId BIGINT NOT NULL, - actorId BIGINT, - userId BIGINT, - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -CREATE UNIQUE INDEX idx_UQ_pending_mapping ON pending_mapping (tenantid, activityId, userId, actorId); - -CREATE TABLE ref_biz_data_inst ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - kind VARCHAR(15) NOT NULL, - name VARCHAR(255) NOT NULL, - proc_inst_id BIGINT, - fn_inst_id BIGINT, - data_id BIGINT, - data_classname VARCHAR(255) NOT NULL -) ENGINE = INNODB; - -CREATE INDEX idx_biz_data_inst1 ON ref_biz_data_inst (tenantid, proc_inst_id); -CREATE INDEX idx_biz_data_inst2 ON ref_biz_data_inst (tenantid, fn_inst_id); -CREATE INDEX idx_biz_data_inst3 ON ref_biz_data_inst (proc_inst_id); -ALTER TABLE ref_biz_data_inst ADD CONSTRAINT pk_ref_biz_data_inst PRIMARY KEY (tenantid, id); -ALTER TABLE ref_biz_data_inst ADD CONSTRAINT fk_ref_biz_data_proc FOREIGN KEY (proc_inst_id) REFERENCES process_instance(id) ON DELETE CASCADE; -ALTER TABLE ref_biz_data_inst ADD CONSTRAINT fk_ref_biz_data_fn FOREIGN KEY (tenantid, fn_inst_id) REFERENCES flownode_instance(tenantid, id) ON DELETE CASCADE; - -CREATE TABLE multi_biz_data ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - idx BIGINT NOT NULL, - data_id BIGINT NOT NULL, - PRIMARY KEY (tenantid, id, data_id) -) ENGINE = INNODB; - -ALTER TABLE multi_biz_data ADD CONSTRAINT fk_rbdi_mbd FOREIGN KEY (tenantid, id) REFERENCES ref_biz_data_inst(tenantid, id) ON DELETE CASCADE; - -CREATE TABLE arch_ref_biz_data_inst ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - kind VARCHAR(15) NOT NULL, - name VARCHAR(255) NOT NULL, - orig_proc_inst_id BIGINT, - orig_fn_inst_id BIGINT, - data_id BIGINT, - data_classname VARCHAR(255) NOT NULL -); -CREATE INDEX idx_arch_biz_data_inst1 ON arch_ref_biz_data_inst (tenantid, orig_proc_inst_id); -CREATE INDEX idx_arch_biz_data_inst2 ON arch_ref_biz_data_inst (tenantid, orig_fn_inst_id); -ALTER TABLE arch_ref_biz_data_inst ADD CONSTRAINT pk_arch_ref_biz_data_inst PRIMARY KEY (tenantid, id); - -CREATE TABLE arch_multi_biz_data ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - idx BIGINT NOT NULL, - data_id BIGINT NOT NULL -); -ALTER TABLE arch_multi_biz_data ADD CONSTRAINT pk_arch_rbdi_mbd PRIMARY KEY (tenantid, id, data_id); -ALTER TABLE arch_multi_biz_data ADD CONSTRAINT fk_arch_rbdi_mbd FOREIGN KEY (tenantid, id) REFERENCES arch_ref_biz_data_inst(tenantid, id) ON DELETE CASCADE; - -CREATE TABLE processsupervisor ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - processDefId BIGINT NOT NULL, - userId BIGINT NOT NULL, - groupId BIGINT NOT NULL, - roleId BIGINT NOT NULL, - UNIQUE (tenantid, processDefId, userId, groupId, roleId), - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; - -CREATE TABLE business_app ( - tenantId BIGINT NOT NULL, - id BIGINT NOT NULL, - token VARCHAR(50) NOT NULL, - version VARCHAR(50) NOT NULL, - description TEXT, - iconPath VARCHAR(255), - creationDate BIGINT NOT NULL, - createdBy BIGINT NOT NULL, - lastUpdateDate BIGINT NOT NULL, - updatedBy BIGINT NOT NULL, - state VARCHAR(30) NOT NULL, - homePageId BIGINT, - profileId BIGINT, - layoutId BIGINT, - themeId BIGINT, - iconMimeType VARCHAR(255), - iconContent LONGBLOB, - displayName VARCHAR(255) NOT NULL, - editable BOOLEAN, - internalProfile VARCHAR(255) -) ENGINE = INNODB; - -ALTER TABLE business_app ADD CONSTRAINT pk_business_app PRIMARY KEY (tenantid, id); -ALTER TABLE business_app ADD CONSTRAINT uk_app_token_version UNIQUE (tenantId, token, version); - -CREATE INDEX idx_app_token ON business_app (token, tenantid); -CREATE INDEX idx_app_profile ON business_app (profileId, tenantid); -CREATE INDEX idx_app_homepage ON business_app (homePageId, tenantid); - -CREATE TABLE business_app_page ( - tenantId BIGINT NOT NULL, - id BIGINT NOT NULL, - applicationId BIGINT NOT NULL, - pageId BIGINT NOT NULL, - token VARCHAR(255) NOT NULL -) ENGINE = INNODB; - -ALTER TABLE business_app_page ADD CONSTRAINT pk_business_app_page PRIMARY KEY (tenantid, id); -ALTER TABLE business_app_page ADD CONSTRAINT uk_app_page_appId_token UNIQUE (tenantId, applicationId, token); - -CREATE INDEX idx_app_page_token ON business_app_page (applicationId, token, tenantid); -CREATE INDEX idx_app_page_pageId ON business_app_page (pageId, tenantid); - -CREATE TABLE business_app_menu ( - tenantId BIGINT NOT NULL, - id BIGINT NOT NULL, - displayName VARCHAR(255) NOT NULL, - applicationId BIGINT NOT NULL, - applicationPageId BIGINT, - parentId BIGINT, - index_ BIGINT -) ENGINE = INNODB; - -ALTER TABLE business_app_menu ADD CONSTRAINT pk_business_app_menu PRIMARY KEY (tenantid, id); - -CREATE INDEX idx_app_menu_app ON business_app_menu (applicationId, tenantid); -CREATE INDEX idx_app_menu_page ON business_app_menu (applicationPageId, tenantid); -CREATE INDEX idx_app_menu_parent ON business_app_menu (parentId, tenantid); - -CREATE TABLE command ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - name VARCHAR(50) NOT NULL, - description TEXT, - IMPLEMENTATION VARCHAR(100) NOT NULL, - isSystem BOOLEAN, - UNIQUE (tenantid, name), - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -CREATE TABLE arch_data_instance ( - tenantId BIGINT NOT NULL, - id BIGINT NOT NULL, - name VARCHAR(50), - description VARCHAR(50), - transientData BOOLEAN, - className VARCHAR(100), - containerId BIGINT, - containerType VARCHAR(60), - namespace VARCHAR(100), - element VARCHAR(60), - intValue INT, - longValue BIGINT, - shortTextValue VARCHAR(255), - booleanValue BOOLEAN, - doubleValue NUMERIC(19,5), - floatValue FLOAT, - blobValue MEDIUMBLOB, - clobValue MEDIUMTEXT, - discriminant VARCHAR(50) NOT NULL, - archiveDate BIGINT NOT NULL, - sourceObjectId BIGINT NOT NULL, - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; - -CREATE INDEX idx1_arch_data_instance ON arch_data_instance (tenantId, containerId, containerType, archiveDate, name, sourceObjectId); -CREATE INDEX idx2_arch_data_instance ON arch_data_instance (sourceObjectId, containerId, archiveDate, id, tenantId); - -CREATE TABLE data_instance ( - tenantId BIGINT NOT NULL, - id BIGINT NOT NULL, - name VARCHAR(50), - description VARCHAR(50), - transientData BOOLEAN, - className VARCHAR(100), - containerId BIGINT, - containerType VARCHAR(60), - namespace VARCHAR(100), - element VARCHAR(60), - intValue INT, - longValue BIGINT, - shortTextValue VARCHAR(255), - booleanValue BOOLEAN, - doubleValue NUMERIC(19,5), - floatValue FLOAT, - blobValue MEDIUMBLOB, - clobValue MEDIUMTEXT, - discriminant VARCHAR(50) NOT NULL, - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -CREATE INDEX idx_datai_container ON data_instance (tenantId, containerId, containerType, name); - -CREATE TABLE dependency ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - name VARCHAR(150) NOT NULL, - description TEXT, - filename VARCHAR(255) NOT NULL, - value_ MEDIUMBLOB NOT NULL, - UNIQUE (tenantId, name), - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -CREATE INDEX idx_dependency_name ON dependency (name); - -CREATE TABLE dependencymapping ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - artifactid BIGINT NOT NULL, - artifacttype VARCHAR(50) NOT NULL, - dependencyid BIGINT NOT NULL, - UNIQUE (tenantid, dependencyid, artifactid, artifacttype), - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -CREATE INDEX idx_dependencymapping_depid ON dependencymapping (dependencyid); -ALTER TABLE dependencymapping ADD CONSTRAINT fk_depmapping_depid FOREIGN KEY (tenantid, dependencyid) REFERENCES dependency(tenantid, id) ON DELETE CASCADE; -CREATE TABLE pdependency ( - id BIGINT NOT NULL, - name VARCHAR(50) NOT NULL UNIQUE, - description TEXT, - filename VARCHAR(255) NOT NULL, - value_ MEDIUMBLOB NOT NULL, - PRIMARY KEY (id) -) ENGINE = INNODB; -CREATE INDEX idx_pdependency_name ON pdependency (name); - -CREATE TABLE pdependencymapping ( - id BIGINT NOT NULL, - artifactid BIGINT NOT NULL, - artifacttype VARCHAR(50) NOT NULL, - dependencyid BIGINT NOT NULL, - UNIQUE (dependencyid, artifactid, artifacttype), - PRIMARY KEY (id) -) ENGINE = INNODB; -CREATE INDEX idx_pdependencymapping_depid ON pdependencymapping (dependencyid); -ALTER TABLE pdependencymapping ADD CONSTRAINT fk_pdepmapping_depid FOREIGN KEY (dependencyid) REFERENCES pdependency(id) ON DELETE CASCADE; -CREATE TABLE external_identity_mapping ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - kind VARCHAR(25) NOT NULL, - externalId VARCHAR(50) NOT NULL, - userId BIGINT NOT NULL, - groupId BIGINT NOT NULL, - roleId BIGINT NOT NULL, - UNIQUE (tenantid, kind, externalId, userId, groupId, roleId), - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; - -CREATE TABLE group_ ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - name VARCHAR(125) NOT NULL, - parentPath VARCHAR(255), - displayName VARCHAR(255), - description TEXT, - createdBy BIGINT, - creationDate BIGINT, - lastUpdate BIGINT, - iconid BIGINT, - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -CREATE INDEX idx_group_name ON group_ (tenantid, parentPath, name); - -CREATE TABLE role ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - name VARCHAR(255) NOT NULL, - displayName VARCHAR(255), - description TEXT, - createdBy BIGINT, - creationDate BIGINT, - lastUpdate BIGINT, - iconid BIGINT, - UNIQUE (tenantid, name), - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; - -CREATE INDEX idx_role_name ON role (tenantid, name); - -CREATE TABLE user_ ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - enabled BOOLEAN NOT NULL, - userName VARCHAR(255) NOT NULL, - password VARCHAR(60), - firstName VARCHAR(255), - lastName VARCHAR(255), - title VARCHAR(50), - jobTitle VARCHAR(255), - managerUserId BIGINT, - createdBy BIGINT, - creationDate BIGINT, - lastUpdate BIGINT, - iconid BIGINT, - UNIQUE (tenantid, userName), - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; - -CREATE INDEX idx_user_name ON user_ (tenantid, userName); - -CREATE TABLE user_login ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - lastConnection BIGINT, - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; - -CREATE TABLE user_contactinfo ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - userId BIGINT NOT NULL, - email VARCHAR(255), - phone VARCHAR(50), - mobile VARCHAR(50), - fax VARCHAR(50), - building VARCHAR(50), - room VARCHAR(50), - address VARCHAR(255), - zipCode VARCHAR(50), - city VARCHAR(255), - state VARCHAR(255), - country VARCHAR(255), - website VARCHAR(255), - personal BOOLEAN NOT NULL, - UNIQUE (tenantid, userId, personal), - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -ALTER TABLE user_contactinfo ADD CONSTRAINT fk_contact_user FOREIGN KEY (tenantid, userId) REFERENCES user_ (tenantid, id) ON DELETE CASCADE; -CREATE INDEX idx_user_contactinfo ON user_contactinfo (userId, tenantid, personal); - - -CREATE TABLE custom_usr_inf_def ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - name VARCHAR(75) NOT NULL, - description TEXT, - UNIQUE (tenantid, name), - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; - -CREATE INDEX idx_custom_usr_inf_def_name ON custom_usr_inf_def (tenantid, name); - -CREATE TABLE custom_usr_inf_val ( - id BIGINT NOT NULL, - tenantid BIGINT NOT NULL, - definitionId BIGINT NOT NULL, - userId BIGINT NOT NULL, - value VARCHAR(255), - UNIQUE (tenantid, definitionId, userId), - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -ALTER TABLE custom_usr_inf_val ADD CONSTRAINT fk_user_id FOREIGN KEY (tenantid, userId) REFERENCES user_ (tenantid, id) ON DELETE CASCADE; -ALTER TABLE custom_usr_inf_val ADD CONSTRAINT fk_definition_id FOREIGN KEY (tenantid, definitionId) REFERENCES custom_usr_inf_def (tenantid, id) ON DELETE CASCADE; - -CREATE TABLE user_membership ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - userId BIGINT NOT NULL, - roleId BIGINT NOT NULL, - groupId BIGINT NOT NULL, - assignedBy BIGINT, - assignedDate BIGINT, - UNIQUE (tenantid, userId, roleId, groupId), - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -CREATE TABLE queriable_log ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - log_timestamp BIGINT NOT NULL, - whatYear SMALLINT NOT NULL, - whatMonth TINYINT NOT NULL, - dayOfYear SMALLINT NOT NULL, - weekOfYear TINYINT NOT NULL, - userId VARCHAR(255) NOT NULL, - threadNumber BIGINT NOT NULL, - clusterNode VARCHAR(50), - productVersion VARCHAR(50) NOT NULL, - severity VARCHAR(50) NOT NULL, - actionType VARCHAR(50) NOT NULL, - actionScope VARCHAR(100), - actionStatus TINYINT NOT NULL, - rawMessage VARCHAR(255) NOT NULL, - callerClassName VARCHAR(200), - callerMethodName VARCHAR(80), - numericIndex1 BIGINT, - numericIndex2 BIGINT, - numericIndex3 BIGINT, - numericIndex4 BIGINT, - numericIndex5 BIGINT, - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; - -CREATE TABLE queriablelog_p ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - queriableLogId BIGINT NOT NULL, - name VARCHAR(50) NOT NULL, - stringValue VARCHAR(255), - blobId BIGINT, - valueType VARCHAR(30), - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; - -CREATE INDEX idx_queriablelog ON queriablelog_p (queriableLogId); -ALTER TABLE queriablelog_p ADD CONSTRAINT fk_queriableLogId FOREIGN KEY (tenantid, queriableLogId) REFERENCES queriable_log(tenantid, id); -CREATE TABLE page ( - tenantId BIGINT NOT NULL, - id BIGINT NOT NULL, - name VARCHAR(255) NOT NULL, - displayName VARCHAR(255) NOT NULL, - description TEXT, - installationDate BIGINT NOT NULL, - installedBy BIGINT NOT NULL, - provided BOOLEAN, - editable BOOLEAN, - removable BOOLEAN, - lastModificationDate BIGINT NOT NULL, - lastUpdatedBy BIGINT NOT NULL, - contentName VARCHAR(280) NOT NULL, - content LONGBLOB, - contentType VARCHAR(50) NOT NULL, - processDefinitionId BIGINT NOT NULL, - pageHash VARCHAR(32) -) ENGINE = INNODB; - -ALTER TABLE page ADD CONSTRAINT pk_page PRIMARY KEY (tenantid, id); -ALTER TABLE page ADD CONSTRAINT uk_page UNIQUE (tenantid, name, processDefinitionId); - - -CREATE TABLE sequence ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - nextid BIGINT NOT NULL, - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -CREATE TABLE blob_ ( - tenantId BIGINT NOT NULL, - id BIGINT NOT NULL, - blobValue MEDIUMBLOB, - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; - -CREATE TABLE platform ( - id BIGINT NOT NULL, - version VARCHAR(50) NOT NULL, - initial_bonita_version VARCHAR(50) NOT NULL, - application_version VARCHAR(50) NOT NULL, - maintenance_message TEXT, - maintenance_message_active BOOLEAN NOT NULL, - created BIGINT NOT NULL, - created_by VARCHAR(50) NOT NULL, - information TEXT, - PRIMARY KEY (id) -) ENGINE = INNODB; - -CREATE TABLE tenant ( - id BIGINT NOT NULL, - created BIGINT NOT NULL, - createdBy VARCHAR(50) NOT NULL, - description VARCHAR(255), - defaultTenant BOOLEAN NOT NULL, - iconname VARCHAR(50), - iconpath VARCHAR(255), - name VARCHAR(50) NOT NULL, - status VARCHAR(15) NOT NULL, - PRIMARY KEY (id) -) ENGINE = INNODB; -CREATE TABLE platformCommand ( - id BIGINT PRIMARY KEY, - name VARCHAR(50) NOT NULL UNIQUE, - description TEXT, - IMPLEMENTATION VARCHAR(100) NOT NULL -) ENGINE = INNODB; -CREATE TABLE profile ( - tenantId BIGINT NOT NULL, - id BIGINT NOT NULL, - isDefault BOOLEAN NOT NULL, - name VARCHAR(50) NOT NULL, - description TEXT, - creationDate BIGINT NOT NULL, - createdBy BIGINT NOT NULL, - lastUpdateDate BIGINT NOT NULL, - lastUpdatedBy BIGINT NOT NULL, - UNIQUE (tenantId, name), - PRIMARY KEY (tenantId, id) -) ENGINE = INNODB; - -CREATE TABLE profilemember ( - tenantId BIGINT NOT NULL, - id BIGINT NOT NULL, - profileId BIGINT NOT NULL, - userId BIGINT NOT NULL, - groupId BIGINT NOT NULL, - roleId BIGINT NOT NULL, - UNIQUE (tenantId, profileId, userId, groupId, roleId), - PRIMARY KEY (tenantId, id) -) ENGINE = INNODB; - -CREATE TABLE job_desc ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - jobclassname VARCHAR(100) NOT NULL, - jobname VARCHAR(100) NOT NULL, - description VARCHAR(50), - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -CREATE INDEX fk_job_desc_Id_idx ON job_desc(id ASC, tenantid ASC); - -CREATE TABLE job_param ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - jobDescriptorId BIGINT NOT NULL, - key_ VARCHAR(50) NOT NULL, - value_ MEDIUMBLOB NOT NULL, - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -CREATE INDEX fk_job_param_jobId_idx ON job_param(jobDescriptorId ASC, tenantid ASC); -ALTER TABLE job_param ADD CONSTRAINT fk_job_param_jobid FOREIGN KEY (tenantid, jobDescriptorId) REFERENCES job_desc(tenantid, id) ON DELETE CASCADE; -CREATE INDEX idx_job_param_tenant_jobid ON job_param (tenantid, jobDescriptorId); - -CREATE TABLE job_log ( - tenantid BIGINT NOT NULL, - id BIGINT NOT NULL, - jobDescriptorId BIGINT NOT NULL, - retryNumber BIGINT, - lastUpdateDate BIGINT, - lastMessage TEXT, - UNIQUE (tenantId, jobDescriptorId), - PRIMARY KEY (tenantid, id) -) ENGINE = INNODB; -CREATE INDEX fk_job_log_jobId_idx ON job_log(jobDescriptorId ASC, tenantid ASC); - -ALTER TABLE job_log ADD CONSTRAINT fk_job_log_jobid FOREIGN KEY (tenantid, jobDescriptorId) REFERENCES job_desc(tenantid, id) ON DELETE CASCADE; - -CREATE TABLE form_mapping ( - tenantId BIGINT NOT NULL, - id BIGINT NOT NULL, - process BIGINT NOT NULL, - type INT NOT NULL, - task VARCHAR(255), - page_mapping_tenant_id BIGINT, - page_mapping_id BIGINT, - lastUpdateDate BIGINT, - lastUpdatedBy BIGINT, - target VARCHAR(16) NOT NULL, - PRIMARY KEY (tenantId, id) -) ENGINE = INNODB; - -CREATE TABLE page_mapping ( - tenantId BIGINT NOT NULL, - id BIGINT NOT NULL, - key_ VARCHAR(255) NOT NULL, - pageId BIGINT NULL, - url VARCHAR(1024) NULL, - urladapter VARCHAR(255) NULL, - page_authoriz_rules TEXT NULL, - lastUpdateDate BIGINT NULL, - lastUpdatedBy BIGINT NULL, - PRIMARY KEY (tenantId, id), - UNIQUE (tenantId, key_) -) ENGINE = INNODB; - -ALTER TABLE form_mapping ADD CONSTRAINT fk_form_mapping_key FOREIGN KEY (page_mapping_tenant_id, page_mapping_id) REFERENCES page_mapping(tenantId, id); - -CREATE TABLE proc_parameter ( - tenantId BIGINT NOT NULL, - id BIGINT NOT NULL, - process_id BIGINT NOT NULL, - name VARCHAR(255) NOT NULL, - value MEDIUMTEXT NULL, - PRIMARY KEY (tenantId, id) -) ENGINE = INNODB; - -CREATE TABLE bar_resource ( - tenantId BIGINT NOT NULL, - id BIGINT NOT NULL, - process_id BIGINT NOT NULL, - name VARCHAR(255) NOT NULL, - type VARCHAR(16) NOT NULL, - content LONGBLOB NOT NULL, - UNIQUE (tenantId, process_id, name, type), - PRIMARY KEY (tenantId, id) -) ENGINE = INNODB; -CREATE INDEX idx_bar_resource ON bar_resource (tenantId, process_id, type, name); - -CREATE TABLE temporary_content ( - id BIGINT NOT NULL, - creationDate BIGINT NOT NULL, - key_ VARCHAR(255) NOT NULL, - fileName VARCHAR(255) NOT NULL, - mimeType VARCHAR(255) NOT NULL, - content LONGBLOB NOT NULL, - UNIQUE (key_), - PRIMARY KEY (id) -) ENGINE = INNODB; -CREATE INDEX idx_temporary_content ON temporary_content (key_); - -CREATE TABLE tenant_resource ( - tenantId BIGINT NOT NULL, - id BIGINT NOT NULL, - name VARCHAR(255) NOT NULL, - type VARCHAR(16) NOT NULL, - content LONGBLOB NOT NULL, - lastUpdatedBy BIGINT NOT NULL, - lastUpdateDate BIGINT, - state VARCHAR(50) NOT NULL, - CONSTRAINT UK_tenant_resource UNIQUE (tenantId, name, type), - PRIMARY KEY (tenantId, id) -) ENGINE = INNODB; -CREATE INDEX idx_tenant_resource ON tenant_resource (tenantId, type, name); - -CREATE TABLE icon ( - tenantId BIGINT NOT NULL, - id BIGINT NOT NULL, - mimetype VARCHAR(255) NOT NULL, - content LONGBLOB NOT NULL, - CONSTRAINT pk_icon PRIMARY KEY (tenantId, id) -) ENGINE = INNODB; diff --git a/platform/platform-resources/src/main/resources/sql/mysql/dropQuartzTables.sql b/platform/platform-resources/src/main/resources/sql/mysql/dropQuartzTables.sql deleted file mode 100644 index d9c9529da3e..00000000000 --- a/platform/platform-resources/src/main/resources/sql/mysql/dropQuartzTables.sql +++ /dev/null @@ -1,11 +0,0 @@ -DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS; -DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS; -DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE; -DROP TABLE IF EXISTS QRTZ_LOCKS; -DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS; -DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS; -DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS; -DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS; -DROP TABLE IF EXISTS QRTZ_TRIGGERS; -DROP TABLE IF EXISTS QRTZ_JOB_DETAILS; -DROP TABLE IF EXISTS QRTZ_CALENDARS; diff --git a/platform/platform-resources/src/main/resources/sql/mysql/dropTables.sql b/platform/platform-resources/src/main/resources/sql/mysql/dropTables.sql deleted file mode 100644 index b5c9288d054..00000000000 --- a/platform/platform-resources/src/main/resources/sql/mysql/dropTables.sql +++ /dev/null @@ -1,68 +0,0 @@ -DROP TABLE configuration; -DROP TABLE arch_contract_data; -DROP TABLE contract_data; -DROP TABLE actormember; -DROP TABLE actor; -DROP TABLE processcategorymapping; -DROP TABLE category; -DROP TABLE arch_process_comment; -DROP TABLE process_comment; -DROP TABLE process_definition; -DROP TABLE arch_document_mapping; -DROP TABLE document_mapping; -DROP TABLE document; -DROP TABLE arch_flownode_instance; -DROP TABLE arch_process_instance; -DROP TABLE arch_connector_instance; -DROP TABLE arch_multi_biz_data; -DROP TABLE arch_ref_biz_data_inst; -DROP TABLE multi_biz_data; -DROP TABLE ref_biz_data_inst; -DROP TABLE pending_mapping; -DROP TABLE connector_instance; -DROP TABLE flownode_instance; -DROP TABLE process_instance; -DROP TABLE event_trigger_instance; -DROP TABLE waiting_event; -DROP TABLE message_instance; -DROP TABLE processsupervisor; -DROP TABLE business_app_menu; -DROP TABLE business_app_page; -DROP TABLE business_app; -DROP TABLE command; -DROP TABLE arch_data_instance; -DROP TABLE data_instance; -DROP TABLE dependencymapping; -DROP TABLE dependency; -DROP TABLE pdependencymapping; -DROP TABLE pdependency; -DROP TABLE external_identity_mapping; -DROP TABLE user_membership; -DROP TABLE custom_usr_inf_val; -DROP TABLE custom_usr_inf_def; -DROP TABLE user_contactinfo; -DROP TABLE user_login; -DROP TABLE user_; -DROP TABLE role; -DROP TABLE group_; -DROP TABLE queriablelog_p; -DROP TABLE queriable_log; -DROP TABLE page; -DROP TABLE blob_; -DROP TABLE profilemember; -DROP TABLE profile; -DROP TABLE job_log; -DROP TABLE job_param; -DROP TABLE job_desc; -DROP TABLE sequence; -DROP TABLE tenant; -DROP TABLE platform; -DROP TABLE platformCommand; -DROP TABLE form_mapping; -DROP TABLE page_mapping; -DROP TABLE process_content; -DROP TABLE proc_parameter; -DROP TABLE bar_resource; -DROP TABLE temporary_content; -DROP TABLE tenant_resource; -DROP TABLE icon; \ No newline at end of file diff --git a/platform/platform-resources/src/main/resources/sql/mysql/initTables.sql b/platform/platform-resources/src/main/resources/sql/mysql/initTables.sql deleted file mode 100644 index bfeebfde4aa..00000000000 --- a/platform/platform-resources/src/main/resources/sql/mysql/initTables.sql +++ /dev/null @@ -1,66 +0,0 @@ -INSERT INTO sequence VALUES (-1, 1, 1); -INSERT INTO sequence VALUES (-1, 2, 1); -INSERT INTO sequence VALUES (-1, 3, 1); -INSERT INTO sequence VALUES (-1, 4, 1); -INSERT INTO sequence VALUES (-1, 5, 1); -INSERT INTO sequence VALUES(1, 10, 1); -INSERT INTO sequence VALUES(1, 11, 1); -INSERT INTO sequence VALUES(1, 20, 1); -INSERT INTO sequence VALUES(1, 21, 1); -INSERT INTO sequence VALUES(1, 22, 1); -INSERT INTO sequence VALUES(1, 23, 1); -INSERT INTO sequence VALUES(1, 24, 1); -INSERT INTO sequence VALUES(1, 25, 1); -INSERT INTO sequence VALUES(1, 26, 1); -INSERT INTO sequence VALUES(1, 27, 1); -INSERT INTO sequence VALUES(1, 30, 1); -INSERT INTO sequence VALUES(1, 31, 1); -INSERT INTO sequence VALUES(1, 70, 1); -INSERT INTO sequence VALUES(1, 71, 1); -INSERT INTO sequence VALUES(1, 72, 1); -INSERT INTO sequence VALUES(1, 90, 1); -INSERT INTO sequence VALUES(1, 9990, 1); -INSERT INTO sequence VALUES(1, 9992, 1); -INSERT INTO sequence VALUES(1, 10000, 1); -INSERT INTO sequence VALUES(1, 10001, 1); -INSERT INTO sequence VALUES(1, 10010, 1); -INSERT INTO sequence VALUES(1, 10011, 1); -INSERT INTO sequence VALUES(1, 10012, 1); -INSERT INTO sequence VALUES(1, 10014, 1); -INSERT INTO sequence VALUES(1, 10015, 1); -INSERT INTO sequence VALUES(1, 10016, 1); -INSERT INTO sequence VALUES(1, 10017, 1); -INSERT INTO sequence VALUES(1, 10018, 1); -INSERT INTO sequence VALUES(1, 10020, 1); -INSERT INTO sequence VALUES(1, 10021, 1); -INSERT INTO sequence VALUES(1, 10030, 1); -INSERT INTO sequence VALUES(1, 10031, 1); -INSERT INTO sequence VALUES(1, 10040, 1); -INSERT INTO sequence VALUES(1, 20051, 1); -INSERT INTO sequence VALUES(1, 10050, 1); -INSERT INTO sequence VALUES(1, 10060, 1); -INSERT INTO sequence VALUES(1, 10070, 1); -INSERT INTO sequence VALUES(1, 10080, 1); -INSERT INTO sequence VALUES(1, 10090, 1); -INSERT INTO sequence VALUES(1, 10096, 1); -INSERT INTO sequence VALUES(1, 10120, 1); -INSERT INTO sequence VALUES(1, 10121, 1); -INSERT INTO sequence VALUES(1, 10200, 1); -INSERT INTO sequence VALUES(1, 10201, 1); -INSERT INTO sequence VALUES(1, 10202, 1); -INSERT INTO sequence VALUES(1, 10210, 1); -INSERT INTO sequence VALUES(1, 10220, 1); -INSERT INTO sequence VALUES(1, 10300, 1); -INSERT INTO sequence VALUES(1, 10310, 1); -INSERT INTO sequence VALUES(1, 10400, 1); -INSERT INTO sequence VALUES(1, 10500, 1); -INSERT INTO sequence VALUES(1, 10501, 1); -INSERT INTO sequence VALUES(1, 20010, 1); -INSERT INTO sequence VALUES(1, 20011, 1); -INSERT INTO sequence VALUES(1, 20013, 1); -INSERT INTO sequence VALUES(1, 20040, 1); -INSERT INTO sequence VALUES(1, 20050, 1); -INSERT INTO sequence VALUES(1, 20210, 1); -INSERT INTO sequence VALUES(1, 20220, 1); -INSERT INTO sequence VALUES(1, 20096, 1); - diff --git a/platform/platform-resources/src/main/resources/sql/mysql/postCreateStructure.sql b/platform/platform-resources/src/main/resources/sql/mysql/postCreateStructure.sql deleted file mode 100755 index 25d655c3d1a..00000000000 --- a/platform/platform-resources/src/main/resources/sql/mysql/postCreateStructure.sql +++ /dev/null @@ -1,69 +0,0 @@ --- ------------------------------------------------ Foreign Keys ----------------------------------------------- -ALTER TABLE actor ADD CONSTRAINT fk_actor_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE actormember ADD CONSTRAINT fk_actormember_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE actormember ADD CONSTRAINT fk_actormember_actorId FOREIGN KEY (tenantid, actorId) REFERENCES actor(tenantid, id); --- ALTER TABLE queriable_log ADD CONSTRAINT fk_queriable_log_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE queriablelog_p ADD CONSTRAINT fk_queriablelog_p_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE category ADD CONSTRAINT fk_category_tenantId FOREIGN KEY (tenantid) REFERENCES tenant (id); -ALTER TABLE command ADD CONSTRAINT fk_command_tenantId FOREIGN KEY (tenantid) REFERENCES tenant (id); -ALTER TABLE connector_instance ADD CONSTRAINT fk_connector_instance_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE data_instance ADD CONSTRAINT fk_data_instance_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE dependency ADD CONSTRAINT fk_dependency_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE dependencymapping ADD CONSTRAINT fk_dependencymapping_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE document ADD CONSTRAINT fk_document_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE document_mapping ADD CONSTRAINT fk_document_mapping_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE document_mapping ADD CONSTRAINT fk_docmap_docid FOREIGN KEY (tenantid, documentid) REFERENCES document(tenantid, id) ON DELETE CASCADE; -ALTER TABLE event_trigger_instance ADD CONSTRAINT fk_event_trigger_instance_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE external_identity_mapping ADD CONSTRAINT fk_external_identity_mapping_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE flownode_instance ADD CONSTRAINT fk_flownode_instance_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE group_ ADD CONSTRAINT fk_group__tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE job_desc ADD CONSTRAINT fk_job_desc_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE job_param ADD CONSTRAINT fk_job_param_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE custom_usr_inf_def ADD CONSTRAINT fk_custom_usr_inf_def_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE custom_usr_inf_val ADD CONSTRAINT fk_custom_usr_inf_val_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE pending_mapping ADD CONSTRAINT fk_pending_mapping_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE pending_mapping ADD CONSTRAINT fk_pending_mapping_flownode_instanceId FOREIGN KEY (tenantid, activityId) REFERENCES flownode_instance(tenantid, id); -ALTER TABLE processcategorymapping ADD CONSTRAINT fk_processcategorymapping_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE process_comment ADD CONSTRAINT fk_process_comment_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE process_definition ADD CONSTRAINT fk_process_definition_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE process_definition ADD CONSTRAINT fk_process_definition_content FOREIGN KEY (content_tenantid, content_id) REFERENCES process_content(tenantid, id); -ALTER TABLE processsupervisor ADD CONSTRAINT fk_processsupervisor_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE profile ADD CONSTRAINT fk_profile_tenantId FOREIGN KEY (tenantId) REFERENCES tenant(id); -ALTER TABLE profilemember ADD CONSTRAINT fk_profilemember_tenantId FOREIGN KEY (tenantId) REFERENCES tenant(id); -ALTER TABLE multi_biz_data ADD CONSTRAINT fk_multi_biz_data_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE ref_biz_data_inst ADD CONSTRAINT fk_ref_biz_data_inst_tenantId FOREIGN KEY (tenantId) REFERENCES tenant(id); -ALTER TABLE role ADD CONSTRAINT fk_role_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE user_ ADD CONSTRAINT fk_user__tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE user_membership ADD CONSTRAINT fk_user_membership_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE waiting_event ADD CONSTRAINT fk_waiting_event_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); - -ALTER TABLE profilemember ADD CONSTRAINT fk_profilemember_profileId FOREIGN KEY (tenantId, profileId) REFERENCES profile(tenantId, id); --- ALTER TABLE process_comment ADD CONSTRAINT fk_process_comment_process_instanceId FOREIGN KEY (processInstanceId) REFERENCES process_instance(id); - --- business application -ALTER TABLE business_app ADD CONSTRAINT fk_app_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE business_app ADD CONSTRAINT fk_app_profileId FOREIGN KEY (tenantid, profileId) REFERENCES profile (tenantid, id); -ALTER TABLE business_app ADD CONSTRAINT fk_app_layoutId FOREIGN KEY (tenantid, layoutId) REFERENCES page (tenantid, id); -ALTER TABLE business_app ADD CONSTRAINT fk_app_themeId FOREIGN KEY (tenantid, themeId) REFERENCES page (tenantid, id); -ALTER TABLE business_app_page ADD CONSTRAINT fk_app_page_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE business_app_page ADD CONSTRAINT fk_bus_app_id FOREIGN KEY (tenantid, applicationId) REFERENCES business_app (tenantid, id) ON DELETE CASCADE; -ALTER TABLE business_app_page ADD CONSTRAINT fk_page_id FOREIGN KEY (tenantid, pageId) REFERENCES page (tenantid, id); - -ALTER TABLE business_app_menu ADD CONSTRAINT fk_app_menu_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); - --- cannot have both fk_app_menu_appId and fk_app_menu_pageId because this create to path for deletion of business_app_menu elements: --- business_app -> business_app_menu --- business_app -> business_app_page -> business_app_menu --- this is not allowed in SQL Server -ALTER TABLE business_app_menu ADD CONSTRAINT fk_app_menu_appId FOREIGN KEY (tenantid, applicationId) REFERENCES business_app (tenantid, id); -ALTER TABLE business_app_menu ADD CONSTRAINT fk_app_menu_pageId FOREIGN KEY (tenantid, applicationPageId) REFERENCES business_app_page (tenantid, id); - -ALTER TABLE business_app_menu ADD CONSTRAINT fk_app_menu_parentId FOREIGN KEY (tenantid, parentId) REFERENCES business_app_menu (tenantid, id); - --- ------------------------ Foreign Keys to disable if archiving is on another BD ------------------ -ALTER TABLE arch_document_mapping ADD CONSTRAINT fk_arch_document_mapping_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE arch_document_mapping ADD CONSTRAINT fk_archdocmap_docid FOREIGN KEY (tenantid, documentid) REFERENCES document(tenantid, id) ON DELETE CASCADE; -ALTER TABLE arch_flownode_instance ADD CONSTRAINT fk_arch_flownode_instance_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE arch_process_comment ADD CONSTRAINT fk_arch_process_comment_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE arch_process_instance ADD CONSTRAINT fk_arch_process_instance_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE arch_data_instance ADD CONSTRAINT fk_arch_data_instance_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); diff --git a/platform/platform-resources/src/main/resources/sql/mysql/preDropStructure.sql b/platform/platform-resources/src/main/resources/sql/mysql/preDropStructure.sql deleted file mode 100644 index 6e22a304944..00000000000 --- a/platform/platform-resources/src/main/resources/sql/mysql/preDropStructure.sql +++ /dev/null @@ -1,64 +0,0 @@ --- ------------------------------------------------ Foreign Keys ----------------------------------------------- -ALTER TABLE actor DROP FOREIGN KEY fk_actor_tenantId; -ALTER TABLE actormember DROP FOREIGN KEY fk_actormember_tenantId; -ALTER TABLE actormember DROP FOREIGN KEY fk_actormember_actorId; --- ALTER TABLE queriable_log DROP FOREIGN KEY fk_queriable_log_tenantId; -ALTER TABLE queriablelog_p DROP FOREIGN KEY fk_queriablelog_p_tenantId; -ALTER TABLE category DROP FOREIGN KEY fk_category_tenantId; -ALTER TABLE command DROP FOREIGN KEY fk_command_tenantId; -ALTER TABLE connector_instance DROP FOREIGN KEY fk_connector_instance_tenantId; -ALTER TABLE data_instance DROP FOREIGN KEY fk_data_instance_tenantId; -ALTER TABLE dependency DROP FOREIGN KEY fk_dependency_tenantId; -ALTER TABLE dependencymapping DROP FOREIGN KEY fk_dependencymapping_tenantId; -ALTER TABLE document DROP FOREIGN KEY fk_document_tenantId; -ALTER TABLE document_mapping DROP FOREIGN KEY fk_document_mapping_tenantId; -ALTER TABLE document_mapping DROP FOREIGN KEY fk_docmap_docid; -ALTER TABLE event_trigger_instance DROP FOREIGN KEY fk_event_trigger_instance_tenantId; -ALTER TABLE external_identity_mapping DROP FOREIGN KEY fk_external_identity_mapping_tenantId; -ALTER TABLE flownode_instance DROP FOREIGN KEY fk_flownode_instance_tenantId; -ALTER TABLE group_ DROP FOREIGN KEY fk_group__tenantId; -ALTER TABLE job_desc DROP FOREIGN KEY fk_job_desc_tenantId; -ALTER TABLE job_param DROP FOREIGN KEY fk_job_param_tenantId; -ALTER TABLE custom_usr_inf_def DROP FOREIGN KEY fk_custom_usr_inf_def_tenantId; -ALTER TABLE custom_usr_inf_val DROP FOREIGN KEY fk_custom_usr_inf_val_tenantId; -ALTER TABLE pending_mapping DROP FOREIGN KEY fk_pending_mapping_tenantId; -ALTER TABLE pending_mapping DROP FOREIGN KEY fk_pending_mapping_flownode_instanceId; -ALTER TABLE processcategorymapping DROP FOREIGN KEY fk_processcategorymapping_tenantId; -ALTER TABLE process_comment DROP FOREIGN KEY fk_process_comment_tenantId; -ALTER TABLE process_definition DROP FOREIGN KEY fk_process_definition_tenantId; -ALTER TABLE process_definition DROP FOREIGN KEY fk_process_definition_content; -ALTER TABLE processsupervisor DROP FOREIGN KEY fk_processsupervisor_tenantId; -ALTER TABLE profile DROP FOREIGN KEY fk_profile_tenantId; -ALTER TABLE profilemember DROP FOREIGN KEY fk_profilemember_tenantId; -ALTER TABLE multi_biz_data DROP FOREIGN KEY fk_multi_biz_data_tenantId; -ALTER TABLE ref_biz_data_inst DROP FOREIGN KEY fk_ref_biz_data_inst_tenantId; -ALTER TABLE role DROP FOREIGN KEY fk_role_tenantId; -ALTER TABLE user_ DROP FOREIGN KEY fk_user__tenantId; -ALTER TABLE user_membership DROP FOREIGN KEY fk_user_membership_tenantId; -ALTER TABLE waiting_event DROP FOREIGN KEY fk_waiting_event_tenantId; - -ALTER TABLE profilemember DROP FOREIGN KEY fk_profilemember_profileId; --- ALTER TABLE process_comment DROP FOREIGN KEY fk_process_comment_process_instanceId; - --- business application -ALTER TABLE business_app_menu DROP FOREIGN KEY fk_app_menu_tenantId; -ALTER TABLE business_app_menu DROP FOREIGN KEY fk_app_menu_appId; -ALTER TABLE business_app_menu DROP FOREIGN KEY fk_app_menu_pageId; -ALTER TABLE business_app_menu DROP FOREIGN KEY fk_app_menu_parentId; -ALTER TABLE business_app_page DROP FOREIGN KEY fk_app_page_tenantId; -ALTER TABLE business_app_page DROP FOREIGN KEY fk_bus_app_id; -ALTER TABLE business_app_page DROP FOREIGN KEY fk_page_id; -ALTER TABLE business_app DROP FOREIGN KEY fk_app_profileId; -ALTER TABLE business_app DROP FOREIGN KEY fk_app_tenantId; -ALTER TABLE business_app DROP FOREIGN KEY fk_app_layoutId; -ALTER TABLE business_app DROP FOREIGN KEY fk_app_themeId; - - - --- ------------------------ Foreign Keys to disable if archiving is on another BD ------------------ -ALTER TABLE arch_document_mapping DROP FOREIGN KEY fk_arch_document_mapping_tenantId; -ALTER TABLE arch_document_mapping DROP FOREIGN KEY fk_archdocmap_docid; -ALTER TABLE arch_flownode_instance DROP FOREIGN KEY fk_arch_flownode_instance_tenantId; -ALTER TABLE arch_process_comment DROP FOREIGN KEY fk_arch_process_comment_tenantId; -ALTER TABLE arch_process_instance DROP FOREIGN KEY fk_arch_process_instance_tenantId; -ALTER TABLE arch_data_instance DROP FOREIGN KEY fk_arch_data_instance_tenantId; diff --git a/platform/platform-resources/src/main/resources/sql/oracle/cleanTables.sql b/platform/platform-resources/src/main/resources/sql/oracle/cleanTables.sql deleted file mode 100644 index 11fcb69ea66..00000000000 --- a/platform/platform-resources/src/main/resources/sql/oracle/cleanTables.sql +++ /dev/null @@ -1,60 +0,0 @@ -DELETE FROM arch_contract_data; -DELETE FROM contract_data; -DELETE FROM actormember; -DELETE FROM actor; -DELETE FROM processcategorymapping; -DELETE FROM category; -DELETE FROM arch_process_comment; -DELETE FROM process_comment; -DELETE FROM process_definition; -DELETE FROM arch_document_mapping; -DELETE FROM document; -DELETE FROM document_mapping; -DELETE FROM arch_flownode_instance; -DELETE FROM arch_process_instance; -DELETE FROM arch_connector_instance; -DELETE FROM arch_multi_biz_data; -DELETE FROM arch_ref_biz_data_inst; -DELETE FROM multi_biz_data; -DELETE FROM ref_biz_data_inst; -DELETE FROM pending_mapping; -DELETE FROM message_instance; -DELETE FROM waiting_event; -DELETE FROM event_trigger_instance; -DELETE FROM connector_instance; -DELETE FROM flownode_instance; -DELETE FROM process_instance; -DELETE FROM processsupervisor; -DELETE FROM business_app_menu; -DELETE FROM business_app_page; -DELETE FROM business_app; -DELETE FROM command; -DELETE FROM arch_data_instance; -DELETE FROM data_instance; -DELETE FROM dependencymapping; -DELETE FROM dependency; -DELETE FROM external_identity_mapping; -DELETE FROM user_membership; -DELETE FROM custom_usr_inf_val; -DELETE FROM custom_usr_inf_def; -DELETE FROM user_contactinfo; -DELETE FROM user_login; -DELETE FROM user_; -DELETE FROM role; -DELETE FROM group_; -DELETE FROM queriablelog_p; -DELETE FROM queriable_log; -DELETE FROM page; -DELETE FROM sequence WHERE tenantId <> -1; -DELETE FROM profilemember; -DELETE FROM profile; -DELETE FROM job_log; -DELETE FROM job_param; -DELETE FROM job_desc; -DELETE FROM tenant; -DELETE FROM platformCommand; -DELETE FROM form_mapping; -DELETE FROM page_mapping; -DELETE FROM proc_parameter; - - \ No newline at end of file diff --git a/platform/platform-resources/src/main/resources/sql/oracle/createQuartzTables.sql b/platform/platform-resources/src/main/resources/sql/oracle/createQuartzTables.sql deleted file mode 100644 index e600184efeb..00000000000 --- a/platform/platform-resources/src/main/resources/sql/oracle/createQuartzTables.sql +++ /dev/null @@ -1,260 +0,0 @@ -CREATE TABLE QRTZ_CALENDARS ( - SCHED_NAME VARCHAR2(120) NOT NULL, - CALENDAR_NAME VARCHAR2 (200) NOT NULL , - CALENDAR BLOB NOT NULL -); - -CREATE TABLE QRTZ_CRON_TRIGGERS ( - SCHED_NAME VARCHAR2(120) NOT NULL, - TRIGGER_NAME VARCHAR2 (200) NOT NULL , - TRIGGER_GROUP VARCHAR2 (200) NOT NULL , - CRON_EXPRESSION VARCHAR2 (120) NOT NULL , - TIME_ZONE_ID VARCHAR2 (80) -); - -CREATE TABLE QRTZ_FIRED_TRIGGERS ( - SCHED_NAME VARCHAR2(120) NOT NULL, - ENTRY_ID VARCHAR2 (95) NOT NULL , - TRIGGER_NAME VARCHAR2 (200) NOT NULL , - TRIGGER_GROUP VARCHAR2 (200) NOT NULL , - INSTANCE_NAME VARCHAR2 (200) NOT NULL , - FIRED_TIME NUMBER(19, 0) NOT NULL , - SCHED_TIME NUMBER(19, 0) NOT NULL , - PRIORITY NUMBER(10, 0) NOT NULL , - STATE VARCHAR2 (16) NOT NULL, - JOB_NAME VARCHAR2 (200) NULL , - JOB_GROUP VARCHAR2 (200) NULL , - IS_NONCONCURRENT NUMBER(1) NULL , - REQUESTS_RECOVERY NUMBER(1) NULL -); - -CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS ( - SCHED_NAME VARCHAR2(120) NOT NULL, - TRIGGER_GROUP VARCHAR2 (200) NOT NULL -); - -CREATE TABLE QRTZ_SCHEDULER_STATE ( - SCHED_NAME VARCHAR2(120) NOT NULL, - INSTANCE_NAME VARCHAR2 (200) NOT NULL , - LAST_CHECKIN_TIME NUMBER(19, 0) NOT NULL , - CHECKIN_INTERVAL NUMBER(19, 0) NOT NULL -); - -CREATE TABLE QRTZ_LOCKS ( - SCHED_NAME VARCHAR2(120) NOT NULL, - LOCK_NAME VARCHAR2 (40) NOT NULL -); - -CREATE TABLE QRTZ_JOB_DETAILS ( - SCHED_NAME VARCHAR2(120) NOT NULL, - JOB_NAME VARCHAR2 (200) NOT NULL , - JOB_GROUP VARCHAR2 (200) NOT NULL , - DESCRIPTION VARCHAR2 (250) NULL , - JOB_CLASS_NAME VARCHAR2 (250) NOT NULL , - IS_DURABLE NUMBER(1) NOT NULL , - IS_NONCONCURRENT NUMBER(1) NOT NULL , - IS_UPDATE_DATA NUMBER(1) NOT NULL , - REQUESTS_RECOVERY NUMBER(1) NOT NULL , - JOB_DATA BLOB NULL -); - -CREATE TABLE QRTZ_SIMPLE_TRIGGERS ( - SCHED_NAME VARCHAR2(120) NOT NULL, - TRIGGER_NAME VARCHAR2 (200) NOT NULL , - TRIGGER_GROUP VARCHAR2 (200) NOT NULL , - REPEAT_COUNT NUMBER(19, 0) NOT NULL , - REPEAT_INTERVAL NUMBER(19, 0) NOT NULL , - TIMES_TRIGGERED NUMBER(19, 0) NOT NULL -); - -CREATE TABLE qrtz_simprop_triggers - ( - SCHED_NAME VARCHAR2(120) NOT NULL, - TRIGGER_NAME VARCHAR2(200) NOT NULL, - TRIGGER_GROUP VARCHAR2(200) NOT NULL, - STR_PROP_1 VARCHAR2(512) NULL, - STR_PROP_2 VARCHAR2(512) NULL, - STR_PROP_3 VARCHAR2(512) NULL, - INT_PROP_1 NUMBER(10, 0) NULL, - INT_PROP_2 NUMBER(10, 0) NULL, - LONG_PROP_1 NUMBER(19, 0) NULL, - LONG_PROP_2 NUMBER(19, 0) NULL, - DEC_PROP_1 NUMERIC(13,4) NULL, - DEC_PROP_2 NUMERIC(13,4) NULL, - BOOL_PROP_1 NUMBER(1) NULL, - BOOL_PROP_2 NUMBER(1) NULL -); - -CREATE TABLE QRTZ_BLOB_TRIGGERS ( - SCHED_NAME VARCHAR2(120) NOT NULL, - TRIGGER_NAME VARCHAR2 (200) NOT NULL , - TRIGGER_GROUP VARCHAR2 (200) NOT NULL , - BLOB_DATA BLOB NULL -); - -CREATE TABLE QRTZ_TRIGGERS ( - SCHED_NAME VARCHAR2(120) NOT NULL, - TRIGGER_NAME VARCHAR2 (200) NOT NULL , - TRIGGER_GROUP VARCHAR2 (200) NOT NULL , - JOB_NAME VARCHAR2 (200) NOT NULL , - JOB_GROUP VARCHAR2 (200) NOT NULL , - DESCRIPTION VARCHAR2 (250) NULL , - NEXT_FIRE_TIME NUMBER(19, 0) NULL , - PREV_FIRE_TIME NUMBER(19, 0) NULL , - PRIORITY NUMBER(10, 0) NULL , - TRIGGER_STATE VARCHAR2 (16) NOT NULL , - TRIGGER_TYPE VARCHAR2 (8) NOT NULL , - START_TIME NUMBER(19, 0) NOT NULL , - END_TIME NUMBER(19, 0) NULL , - CALENDAR_NAME VARCHAR2 (200) NULL , - MISFIRE_INSTR SMALLINT NULL , - JOB_DATA BLOB NULL -); - -ALTER TABLE QRTZ_CALENDARS ADD - CONSTRAINT PK_QRTZ_CALENDARS PRIMARY KEY - ( - SCHED_NAME, - CALENDAR_NAME - ); - -ALTER TABLE QRTZ_CRON_TRIGGERS ADD - CONSTRAINT PK_QRTZ_CRON_TRIGGERS PRIMARY KEY - ( - SCHED_NAME, - TRIGGER_NAME, - TRIGGER_GROUP - ); - -ALTER TABLE QRTZ_FIRED_TRIGGERS ADD - CONSTRAINT PK_QRTZ_FIRED_TRIGGERS PRIMARY KEY - ( - SCHED_NAME, - ENTRY_ID - ); - -ALTER TABLE QRTZ_PAUSED_TRIGGER_GRPS ADD - CONSTRAINT PK_QRTZ_PAUSED_TRIGGER_GRPS PRIMARY KEY - ( - SCHED_NAME, - TRIGGER_GROUP - ); - -ALTER TABLE QRTZ_SCHEDULER_STATE ADD - CONSTRAINT PK_QRTZ_SCHEDULER_STATE PRIMARY KEY - ( - SCHED_NAME, - INSTANCE_NAME - ); - -ALTER TABLE QRTZ_LOCKS ADD - CONSTRAINT PK_QRTZ_LOCKS PRIMARY KEY - ( - SCHED_NAME, - LOCK_NAME - ); - -ALTER TABLE QRTZ_JOB_DETAILS ADD - CONSTRAINT PK_QRTZ_JOB_DETAILS PRIMARY KEY - ( - SCHED_NAME, - JOB_NAME, - JOB_GROUP - ); - -ALTER TABLE QRTZ_SIMPLE_TRIGGERS ADD - CONSTRAINT PK_QRTZ_SIMPLE_TRIGGERS PRIMARY KEY - ( - SCHED_NAME, - TRIGGER_NAME, - TRIGGER_GROUP - ); - -ALTER TABLE QRTZ_SIMPROP_TRIGGERS ADD - CONSTRAINT PK_QRTZ_SIMPROP_TRIGGERS PRIMARY KEY - ( - SCHED_NAME, - TRIGGER_NAME, - TRIGGER_GROUP - ); - -ALTER TABLE QRTZ_TRIGGERS ADD - CONSTRAINT PK_QRTZ_TRIGGERS PRIMARY KEY - ( - SCHED_NAME, - TRIGGER_NAME, - TRIGGER_GROUP - ); - -ALTER TABLE QRTZ_CRON_TRIGGERS ADD - CONSTRAINT FK_QRTZ_CRON_TRIGGERS FOREIGN KEY - ( - SCHED_NAME, - TRIGGER_NAME, - TRIGGER_GROUP - ) REFERENCES QRTZ_TRIGGERS ( - SCHED_NAME, - TRIGGER_NAME, - TRIGGER_GROUP - ) ON DELETE CASCADE; - - -ALTER TABLE QRTZ_SIMPLE_TRIGGERS ADD - CONSTRAINT FK_QRTZ_SIMPLE_TRIGGERS FOREIGN KEY - ( - SCHED_NAME, - TRIGGER_NAME, - TRIGGER_GROUP - ) REFERENCES QRTZ_TRIGGERS ( - SCHED_NAME, - TRIGGER_NAME, - TRIGGER_GROUP - ) ON DELETE CASCADE; - -ALTER TABLE QRTZ_SIMPROP_TRIGGERS ADD - CONSTRAINT FK_QRTZ_SIMPROP_TRIGGERS FOREIGN KEY - ( - SCHED_NAME, - TRIGGER_NAME, - TRIGGER_GROUP - ) REFERENCES QRTZ_TRIGGERS ( - SCHED_NAME, - TRIGGER_NAME, - TRIGGER_GROUP - ) ON DELETE CASCADE; - - -ALTER TABLE QRTZ_TRIGGERS ADD - CONSTRAINT FK_QRTZ_TRIGGERS FOREIGN KEY - ( - SCHED_NAME, - JOB_NAME, - JOB_GROUP - ) REFERENCES QRTZ_JOB_DETAILS ( - SCHED_NAME, - JOB_NAME, - JOB_GROUP - ); - -CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY); -CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP); - -CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP); -CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP); -CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME); -CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP); -CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE); -CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE); -CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE); -CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME); -CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME); -CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME); -CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE); -CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE); - -CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME); -CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY); -CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP); -CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP); -CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP); -CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP); \ No newline at end of file diff --git a/platform/platform-resources/src/main/resources/sql/oracle/createTables.sql b/platform/platform-resources/src/main/resources/sql/oracle/createTables.sql deleted file mode 100644 index 32e81c4a1ba..00000000000 --- a/platform/platform-resources/src/main/resources/sql/oracle/createTables.sql +++ /dev/null @@ -1,1038 +0,0 @@ -CREATE TABLE configuration ( - tenant_id NUMBER(19, 0) NOT NULL, - content_type VARCHAR2(50 CHAR) NOT NULL, - resource_name VARCHAR2(120 CHAR) NOT NULL, - resource_content BLOB NOT NULL -); -ALTER TABLE configuration ADD CONSTRAINT pk_configuration PRIMARY KEY (tenant_id, content_type, resource_name); -CREATE INDEX idx_configuration ON configuration (tenant_id, content_type); - -CREATE TABLE contract_data ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - kind VARCHAR2(20 CHAR) NOT NULL, - scopeId NUMBER(19, 0) NOT NULL, - name VARCHAR2(50 CHAR) NOT NULL, - val CLOB -); -ALTER TABLE contract_data ADD CONSTRAINT pk_contract_data PRIMARY KEY (tenantid, id, scopeId); -ALTER TABLE contract_data ADD CONSTRAINT uc_cd_scope_name UNIQUE (kind, scopeId, name, tenantid); - -CREATE TABLE arch_contract_data ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - kind VARCHAR2(20 CHAR) NOT NULL, - scopeId NUMBER(19, 0) NOT NULL, - name VARCHAR2(50 CHAR) NOT NULL, - val CLOB, - archiveDate NUMBER(19, 0) NOT NULL, - sourceObjectId NUMBER(19, 0) NOT NULL -); -ALTER TABLE arch_contract_data ADD CONSTRAINT pk_arch_contract_data PRIMARY KEY (tenantid, id, scopeId); -ALTER TABLE arch_contract_data ADD CONSTRAINT uc_acd_scope_name UNIQUE (kind, scopeId, name, tenantid); - -CREATE TABLE actor ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - scopeId NUMBER(19, 0) NOT NULL, - name VARCHAR2(50 CHAR) NOT NULL, - displayName VARCHAR2(75 CHAR), - description VARCHAR2(1024 CHAR), - initiator NUMBER(1), - CONSTRAINT UK_Actor UNIQUE (tenantid, id, scopeId, name), - PRIMARY KEY (tenantid, id) -); - -CREATE TABLE actormember ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - actorId NUMBER(19, 0) NOT NULL, - userId NUMBER(19, 0) NOT NULL, - groupId NUMBER(19, 0) NOT NULL, - roleId NUMBER(19, 0) NOT NULL, - UNIQUE (tenantid, actorid, userId, groupId, roleId), - PRIMARY KEY (tenantid, id) -); -CREATE TABLE category ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - name VARCHAR2(50 CHAR) NOT NULL, - creator NUMBER(19, 0), - description VARCHAR2(1024 CHAR), - creationDate NUMBER(19, 0) NOT NULL, - lastUpdateDate NUMBER(19, 0) NOT NULL, - CONSTRAINT UK_Category UNIQUE (tenantid, name), - PRIMARY KEY (tenantid, id) -); - -CREATE TABLE processcategorymapping ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - categoryid NUMBER(19, 0) NOT NULL, - processid NUMBER(19, 0) NOT NULL, - UNIQUE (tenantid, categoryid, processid), - PRIMARY KEY (tenantid, id) -); - -ALTER TABLE processcategorymapping ADD CONSTRAINT fk_catmapping_catid FOREIGN KEY (tenantid, categoryid) REFERENCES category(tenantid, id) ON DELETE CASCADE; - -CREATE TABLE arch_process_comment( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - userId NUMBER(19, 0), - processInstanceId NUMBER(19, 0) NOT NULL, - postDate NUMBER(19, 0) NOT NULL, - content VARCHAR2(512 CHAR) NOT NULL, - archiveDate NUMBER(19, 0) NOT NULL, - sourceObjectId NUMBER(19, 0) NOT NULL, - PRIMARY KEY (tenantid, id) -); - -CREATE INDEX idx1_arch_process_comment on arch_process_comment (sourceobjectid, tenantid); -CREATE INDEX idx2_arch_process_comment on arch_process_comment (processInstanceId, archivedate, tenantid); -CREATE TABLE process_comment ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - kind VARCHAR2(25 CHAR) NOT NULL, - userId NUMBER(19, 0), - processInstanceId NUMBER(19, 0) NOT NULL, - postDate NUMBER(19, 0) NOT NULL, - content VARCHAR2(512 CHAR) NOT NULL, - PRIMARY KEY (tenantid, id) -); -CREATE INDEX idx1_process_comment on process_comment (processInstanceId, tenantid); - -CREATE TABLE process_definition ( - tenantId NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - processId NUMBER(19, 0) NOT NULL, - name VARCHAR2(150 CHAR) NOT NULL, - version VARCHAR2(50 CHAR) NOT NULL, - description VARCHAR2(255 CHAR), - deploymentDate NUMBER(19, 0) NOT NULL, - deployedBy NUMBER(19, 0) NOT NULL, - activationState VARCHAR2(30 CHAR) NOT NULL, - configurationState VARCHAR2(30 CHAR) NOT NULL, - displayName VARCHAR2(75 CHAR), - displayDescription VARCHAR2(255 CHAR), - lastUpdateDate NUMBER(19, 0), - categoryId NUMBER(19, 0), - iconPath VARCHAR2(255 CHAR), - content_tenantid NUMBER(19, 0) NOT NULL, - content_id NUMBER(19, 0) NOT NULL, - PRIMARY KEY (tenantId, id), - CONSTRAINT UK_Process_Definition UNIQUE (tenantId, name, version) -); -CREATE TABLE process_content ( - tenantId NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - content CLOB NOT NULL, - PRIMARY KEY (tenantid, id) -); -CREATE TABLE arch_document_mapping ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - sourceObjectId NUMBER(19, 0), - processinstanceid NUMBER(19, 0) NOT NULL, - documentid NUMBER(19, 0) NOT NULL, - name VARCHAR2(50 CHAR) NOT NULL, - description VARCHAR2(1024 CHAR), - version VARCHAR2(50 CHAR) NOT NULL, - index_ INT NOT NULL, - archiveDate NUMBER(19, 0) NOT NULL, - PRIMARY KEY (tenantid, id) -); -CREATE INDEX idx_a_doc_mp_pr_id ON arch_document_mapping (processinstanceid, tenantid); -CREATE TABLE document ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - author NUMBER(19, 0), - creationdate NUMBER(19, 0) NOT NULL, - hascontent NUMBER(1) NOT NULL, - filename VARCHAR2(255 CHAR), - mimetype VARCHAR2(255 CHAR), - url VARCHAR2(1024 CHAR), - content BLOB, - PRIMARY KEY (tenantid, id) -); -CREATE TABLE document_mapping ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - processinstanceid NUMBER(19, 0) NOT NULL, - documentid NUMBER(19, 0) NOT NULL, - name VARCHAR2(50 CHAR) NOT NULL, - description VARCHAR2(1024 CHAR), - version VARCHAR2(50 CHAR) NOT NULL, - index_ INT NOT NULL, - PRIMARY KEY (tenantid, id) -); -CREATE TABLE arch_process_instance ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - name VARCHAR2(75 CHAR) NOT NULL, - processDefinitionId NUMBER(19, 0) NOT NULL, - description VARCHAR2(255 CHAR), - startDate NUMBER(19, 0) NOT NULL, - startedBy NUMBER(19, 0) NOT NULL, - startedBySubstitute NUMBER(19, 0) NOT NULL, - endDate NUMBER(19, 0) NOT NULL, - archiveDate NUMBER(19, 0) NOT NULL, - stateId INT NOT NULL, - lastUpdate NUMBER(19, 0) NOT NULL, - rootProcessInstanceId NUMBER(19, 0), - callerId NUMBER(19, 0), - sourceObjectId NUMBER(19, 0) NOT NULL, - stringIndex1 VARCHAR2(255 CHAR), - stringIndex2 VARCHAR2(255 CHAR), - stringIndex3 VARCHAR2(255 CHAR), - stringIndex4 VARCHAR2(255 CHAR), - stringIndex5 VARCHAR2(255 CHAR), - PRIMARY KEY (tenantid, id) -); -CREATE INDEX idx1_arch_process_instance ON arch_process_instance (tenantId, sourceObjectId, rootProcessInstanceId, callerId); -CREATE INDEX idx2_arch_process_instance ON arch_process_instance (tenantId, processDefinitionId, archiveDate); -CREATE INDEX idx3_arch_process_instance ON arch_process_instance (tenantId, sourceObjectId, callerId, stateId); - -CREATE TABLE arch_flownode_instance ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - flownodeDefinitionId NUMBER(19, 0) NOT NULL, - kind VARCHAR2(25 CHAR) NOT NULL, - sourceObjectId NUMBER(19, 0), - archiveDate NUMBER(19, 0) NOT NULL, - rootContainerId NUMBER(19, 0) NOT NULL, - parentContainerId NUMBER(19, 0) NOT NULL, - name VARCHAR2(255 CHAR) NOT NULL, - displayName VARCHAR2(255 CHAR), - displayDescription VARCHAR2(255 CHAR), - stateId INT NOT NULL, - stateName VARCHAR2(50 CHAR), - terminal NUMBER(1) NOT NULL, - stable NUMBER(1) , - actorId NUMBER(19, 0) NULL, - assigneeId NUMBER(19, 0) DEFAULT 0 NOT NULL, - reachedStateDate NUMBER(19, 0), - lastUpdateDate NUMBER(19, 0), - expectedEndDate NUMBER(19, 0), - claimedDate NUMBER(19, 0), - priority SMALLINT, - gatewayType VARCHAR2(50 CHAR), - hitBys VARCHAR2(255 CHAR), - logicalGroup1 NUMBER(19, 0) NOT NULL, - logicalGroup2 NUMBER(19, 0) NOT NULL, - logicalGroup3 NUMBER(19, 0), - logicalGroup4 NUMBER(19, 0) NOT NULL, - loop_counter INT, - loop_max INT, - loopCardinality INT, - loopDataInputRef VARCHAR2(255 CHAR), - loopDataOutputRef VARCHAR2(255 CHAR), - description VARCHAR2(255 CHAR), - sequential NUMBER(1), - dataInputItemRef VARCHAR2(255 CHAR), - dataOutputItemRef VARCHAR2(255 CHAR), - nbActiveInst INT, - nbCompletedInst INT, - nbTerminatedInst INT, - executedBy NUMBER(19, 0), - executedBySubstitute NUMBER(19, 0), - activityInstanceId NUMBER(19, 0), - aborting NUMBER(1) NOT NULL, - triggeredByEvent NUMBER(1), - interrupting NUMBER(1), - PRIMARY KEY (tenantid, id) -); -CREATE INDEX idx_afi_kind_lg2_executedBy ON arch_flownode_instance(logicalGroup2, tenantId, kind, executedBy); -CREATE INDEX idx_afi_kind_lg3 ON arch_flownode_instance(tenantId, kind, logicalGroup3); -CREATE INDEX idx_afi_kind_lg4 ON arch_flownode_instance(tenantId, logicalGroup4); -CREATE INDEX idx_afi_sourceId_tenantid_kind ON arch_flownode_instance (sourceObjectId, tenantid, kind); -CREATE INDEX idx1_arch_flownode_instance ON arch_flownode_instance (tenantId, rootContainerId, parentContainerId); -CREATE INDEX idx_lg4_lg2 on arch_flownode_instance(tenantid, logicalGroup4, logicalGroup2); - -CREATE TABLE arch_connector_instance ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - containerId NUMBER(19, 0) NOT NULL, - containerType VARCHAR2(10 CHAR) NOT NULL, - connectorId VARCHAR2(255 CHAR) NOT NULL, - version VARCHAR2(50 CHAR) NOT NULL, - name VARCHAR2(255 CHAR) NOT NULL, - activationEvent VARCHAR2(30 CHAR), - state VARCHAR2(50 CHAR), - sourceObjectId NUMBER(19, 0), - archiveDate NUMBER(19, 0) NOT NULL, - PRIMARY KEY (tenantid, id) -); - -CREATE INDEX idx1_arch_connector_instance ON arch_connector_instance (tenantId, containerId, containerType); -CREATE TABLE process_instance ( - id NUMBER(19, 0) NOT NULL, - name VARCHAR2(75 CHAR) NOT NULL, - processDefinitionId NUMBER(19, 0) NOT NULL, - description VARCHAR2(255 CHAR), - startDate NUMBER(19, 0) NOT NULL, - startedBy NUMBER(19, 0) NOT NULL, - startedBySubstitute NUMBER(19, 0) NOT NULL, - endDate NUMBER(19, 0) NOT NULL, - stateId INT NOT NULL, - stateCategory VARCHAR2(50 CHAR) NOT NULL, - lastUpdate NUMBER(19, 0) NOT NULL, - containerId NUMBER(19, 0), - rootProcessInstanceId NUMBER(19, 0), - callerId NUMBER(19, 0), - callerType VARCHAR2(50 CHAR), - interruptingEventId NUMBER(19, 0), - stringIndex1 VARCHAR2(255 CHAR), - stringIndex2 VARCHAR2(255 CHAR), - stringIndex3 VARCHAR2(255 CHAR), - stringIndex4 VARCHAR2(255 CHAR), - stringIndex5 VARCHAR2(255 CHAR), - PRIMARY KEY (id) -); - -CREATE INDEX idx1_proc_inst_pdef_state ON process_instance (processdefinitionid, stateid); - -CREATE TABLE flownode_instance ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - flownodeDefinitionId NUMBER(19, 0) NOT NULL, - kind VARCHAR2(25 CHAR) NOT NULL, - rootContainerId NUMBER(19, 0) NOT NULL, - parentContainerId NUMBER(19, 0) NOT NULL, - name VARCHAR2(255 CHAR) NOT NULL, - displayName VARCHAR2(255 CHAR), - displayDescription VARCHAR2(255 CHAR), - stateId INT NOT NULL, - stateName VARCHAR2(50 CHAR), - prev_state_id INT NOT NULL, - terminal NUMBER(1) NOT NULL, - stable NUMBER(1) , - actorId NUMBER(19, 0) NULL, - assigneeId NUMBER(19, 0) DEFAULT 0 NOT NULL, - reachedStateDate NUMBER(19, 0), - lastUpdateDate NUMBER(19, 0), - expectedEndDate NUMBER(19, 0), - claimedDate NUMBER(19, 0), - priority SMALLINT, - gatewayType VARCHAR2(50 CHAR), - hitBys VARCHAR2(255 CHAR), - stateCategory VARCHAR2(50 CHAR) NOT NULL, - logicalGroup1 NUMBER(19, 0) NOT NULL, - logicalGroup2 NUMBER(19, 0) NOT NULL, - logicalGroup3 NUMBER(19, 0), - logicalGroup4 NUMBER(19, 0) NOT NULL, - loop_counter INT, - loop_max INT, - description VARCHAR2(255 CHAR), - sequential NUMBER(1), - loopDataInputRef VARCHAR2(255 CHAR), - loopDataOutputRef VARCHAR2(255 CHAR), - dataInputItemRef VARCHAR2(255 CHAR), - dataOutputItemRef VARCHAR2(255 CHAR), - loopCardinality INT, - nbActiveInst INT, - nbCompletedInst INT, - nbTerminatedInst INT, - executedBy NUMBER(19, 0), - executedBySubstitute NUMBER(19, 0), - activityInstanceId NUMBER(19, 0), - state_executing NUMBER(1) DEFAULT 0, - abortedByBoundary NUMBER(19, 0), - triggeredByEvent NUMBER(1), - interrupting NUMBER(1), - tokenCount INT NOT NULL, - PRIMARY KEY (tenantid, id) -); -CREATE INDEX idx_fni_rootcontid ON flownode_instance (rootContainerId); -CREATE INDEX idx_fni_loggroup4 ON flownode_instance (logicalGroup4); -CREATE INDEX idx_fni_loggroup3_terminal ON flownode_instance(logicalgroup3, terminal, tenantid); -CREATE INDEX idx_fn_lg2_state_tenant_del ON flownode_instance (logicalGroup2, stateName, tenantid); -CREATE INDEX idx_fni_activity_instance_id_kind ON flownode_instance(activityInstanceId, kind, tenantid); - -CREATE TABLE connector_instance ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - containerId NUMBER(19, 0) NOT NULL, - containerType VARCHAR2(10 CHAR) NOT NULL, - connectorId VARCHAR2(255 CHAR) NOT NULL, - version VARCHAR2(50 CHAR) NOT NULL, - name VARCHAR2(255 CHAR) NOT NULL, - activationEvent VARCHAR2(30 CHAR), - state VARCHAR2(50 CHAR), - executionOrder INT, - exceptionMessage VARCHAR2(255 CHAR), - stackTrace CLOB, - PRIMARY KEY (tenantid, id) -); -CREATE INDEX idx_ci_container_activation ON connector_instance (tenantid, containerId, containerType, activationEvent); - -CREATE TABLE event_trigger_instance ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - eventInstanceId NUMBER(19, 0) NOT NULL, - eventInstanceName VARCHAR2(50 CHAR), - executionDate NUMBER(19, 0), - jobTriggerName VARCHAR2(255 CHAR), - PRIMARY KEY (tenantid, id) -); - -CREATE TABLE waiting_event ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - kind VARCHAR2(15 CHAR) NOT NULL, - eventType VARCHAR2(50 CHAR), - messageName VARCHAR2(255 CHAR), - signalName VARCHAR2(255 CHAR), - errorCode VARCHAR2(255 CHAR), - processName VARCHAR2(150 CHAR), - flowNodeName VARCHAR2(50 CHAR), - flowNodeDefinitionId NUMBER(19, 0), - subProcessId NUMBER(19, 0), - processDefinitionId NUMBER(19, 0), - rootProcessInstanceId NUMBER(19, 0), - parentProcessInstanceId NUMBER(19, 0), - flowNodeInstanceId NUMBER(19, 0), - relatedActivityInstanceId NUMBER(19, 0), - locked NUMBER(1), - active NUMBER(1), - progress SMALLINT, - correlation1 VARCHAR2(128 CHAR), - correlation2 VARCHAR2(128 CHAR), - correlation3 VARCHAR2(128 CHAR), - correlation4 VARCHAR2(128 CHAR), - correlation5 VARCHAR2(128 CHAR), - PRIMARY KEY (tenantid, id) -); -CREATE INDEX idx_waiting_event ON waiting_event (progress, tenantid, kind, locked, active); -CREATE INDEX idx_waiting_event_correl ON waiting_event (correlation1, correlation2, correlation3, correlation4, correlation5); - -CREATE TABLE message_instance ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - messageName VARCHAR2(255 CHAR) NOT NULL, - targetProcess VARCHAR2(255 CHAR) NOT NULL, - targetFlowNode VARCHAR2(255 CHAR) NULL, - locked NUMBER(1) NOT NULL, - handled NUMBER(1) NOT NULL, - processDefinitionId NUMBER(19, 0) NOT NULL, - flowNodeName VARCHAR2(255 CHAR), - correlation1 VARCHAR2(128 CHAR), - correlation2 VARCHAR2(128 CHAR), - correlation3 VARCHAR2(128 CHAR), - correlation4 VARCHAR2(128 CHAR), - correlation5 VARCHAR2(128 CHAR), - creationDate NUMBER(19, 0) NOT NULL, - PRIMARY KEY (tenantid, id) -); -CREATE INDEX idx_message_instance ON message_instance (messageName, targetProcess, correlation1, correlation2, correlation3); -CREATE INDEX idx_message_instance_correl ON message_instance (correlation1, correlation2, correlation3, correlation4, correlation5); - -CREATE TABLE pending_mapping ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - activityId NUMBER(19, 0) NOT NULL, - actorId NUMBER(19, 0), - userId NUMBER(19, 0), - PRIMARY KEY (tenantid, id) -); -CREATE UNIQUE INDEX idx_UQ_pending_mapping ON pending_mapping (tenantid, activityId, userId, actorId); - - -CREATE TABLE ref_biz_data_inst ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - kind VARCHAR2(15 CHAR) NOT NULL, - name VARCHAR2(255 CHAR) NOT NULL, - proc_inst_id NUMBER(19, 0), - fn_inst_id NUMBER(19, 0), - data_id NUMBER(19, 0), - data_classname VARCHAR2(255 CHAR) NOT NULL -); - -CREATE INDEX idx_biz_data_inst1 ON ref_biz_data_inst (tenantid, proc_inst_id); -CREATE INDEX idx_biz_data_inst2 ON ref_biz_data_inst (tenantid, fn_inst_id); -CREATE INDEX idx_biz_data_inst3 ON ref_biz_data_inst (proc_inst_id); -ALTER TABLE ref_biz_data_inst ADD CONSTRAINT pk_ref_biz_data_inst PRIMARY KEY (tenantid, id); -ALTER TABLE ref_biz_data_inst ADD CONSTRAINT fk_ref_biz_data_proc FOREIGN KEY (proc_inst_id) REFERENCES process_instance(id) ON DELETE CASCADE; -ALTER TABLE ref_biz_data_inst ADD CONSTRAINT fk_ref_biz_data_fn FOREIGN KEY (tenantid, fn_inst_id) REFERENCES flownode_instance(tenantid, id) ON DELETE CASCADE; - -CREATE TABLE multi_biz_data ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - idx NUMBER(19, 0) NOT NULL, - data_id NUMBER(19, 0) NOT NULL, - PRIMARY KEY (tenantid, id, data_id) -); - -ALTER TABLE multi_biz_data ADD CONSTRAINT fk_rbdi_mbd FOREIGN KEY (tenantid, id) REFERENCES ref_biz_data_inst(tenantid, id) ON DELETE CASCADE; - -CREATE TABLE arch_ref_biz_data_inst ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - kind VARCHAR2(15 CHAR) NOT NULL, - name VARCHAR2(255 CHAR) NOT NULL, - orig_proc_inst_id NUMBER(19, 0), - orig_fn_inst_id NUMBER(19, 0), - data_id NUMBER(19, 0), - data_classname VARCHAR2(255 CHAR) NOT NULL -); -CREATE INDEX idx_arch_biz_data_inst1 ON arch_ref_biz_data_inst (tenantid, orig_proc_inst_id); -CREATE INDEX idx_arch_biz_data_inst2 ON arch_ref_biz_data_inst (tenantid, orig_fn_inst_id); -ALTER TABLE arch_ref_biz_data_inst ADD CONSTRAINT pk_arch_ref_biz_data_inst PRIMARY KEY (tenantid, id); - -CREATE TABLE arch_multi_biz_data ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - idx NUMBER(19, 0) NOT NULL, - data_id NUMBER(19, 0) NOT NULL -); -ALTER TABLE arch_multi_biz_data ADD CONSTRAINT pk_arch_rbdi_mbd PRIMARY KEY (tenantid, id, data_id); -ALTER TABLE arch_multi_biz_data ADD CONSTRAINT fk_arch_rbdi_mbd FOREIGN KEY (tenantid, id) REFERENCES arch_ref_biz_data_inst(tenantid, id) ON DELETE CASCADE; - -CREATE TABLE processsupervisor ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - processDefId NUMBER(19, 0) NOT NULL, - userId NUMBER(19, 0) NOT NULL, - groupId NUMBER(19, 0) NOT NULL, - roleId NUMBER(19, 0) NOT NULL, - UNIQUE (tenantid, processDefId, userId, groupId, roleId), - PRIMARY KEY (tenantid, id) -); - -CREATE TABLE business_app ( - tenantId NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - token VARCHAR2(50 CHAR) NOT NULL, - version VARCHAR2(50 CHAR) NOT NULL, - description VARCHAR2(1024 CHAR), - iconPath VARCHAR2(255 CHAR), - creationDate NUMBER(19, 0) NOT NULL, - createdBy NUMBER(19, 0) NOT NULL, - lastUpdateDate NUMBER(19, 0) NOT NULL, - updatedBy NUMBER(19, 0) NOT NULL, - state VARCHAR2(30 CHAR) NOT NULL, - homePageId NUMBER(19, 0), - profileId NUMBER(19, 0), - layoutId NUMBER(19, 0), - themeId NUMBER(19, 0), - iconMimeType VARCHAR2(255 CHAR), - iconContent BLOB, - displayName VARCHAR2(255 CHAR) NOT NULL, - editable NUMBER(1), - internalProfile VARCHAR2(255 CHAR) -); - -ALTER TABLE business_app ADD CONSTRAINT pk_business_app PRIMARY KEY (tenantid, id); -ALTER TABLE business_app ADD CONSTRAINT UK_Business_app UNIQUE (tenantId, token, version); - -CREATE INDEX idx_app_token ON business_app (token, tenantid); -CREATE INDEX idx_app_profile ON business_app (profileId, tenantid); -CREATE INDEX idx_app_homepage ON business_app (homePageId, tenantid); - -CREATE TABLE business_app_page ( - tenantId NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - applicationId NUMBER(19, 0) NOT NULL, - pageId NUMBER(19, 0) NOT NULL, - token VARCHAR2(255 CHAR) NOT NULL -); - -ALTER TABLE business_app_page ADD CONSTRAINT pk_business_app_page PRIMARY KEY (tenantid, id); -ALTER TABLE business_app_page ADD CONSTRAINT UK_Business_app_page UNIQUE (tenantId, applicationId, token); - -CREATE INDEX idx_app_page_token ON business_app_page (applicationId, token, tenantid); -CREATE INDEX idx_app_page_pageId ON business_app_page (pageId, tenantid); - -CREATE TABLE business_app_menu ( - tenantId NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - displayName VARCHAR2(255 CHAR) NOT NULL, - applicationId NUMBER(19, 0) NOT NULL, - applicationPageId NUMBER(19, 0), - parentId NUMBER(19, 0), - index_ NUMBER(19, 0) -); - -ALTER TABLE business_app_menu ADD CONSTRAINT pk_business_app_menu PRIMARY KEY (tenantid, id); - -CREATE INDEX idx_app_menu_app ON business_app_menu (applicationId, tenantid); -CREATE INDEX idx_app_menu_page ON business_app_menu (applicationPageId, tenantid); -CREATE INDEX idx_app_menu_parent ON business_app_menu (parentId, tenantid); - -CREATE TABLE command ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - name VARCHAR2(50 CHAR) NOT NULL, - description VARCHAR2(1024 CHAR), - IMPLEMENTATION VARCHAR2(100 CHAR) NOT NULL, - isSystem NUMBER(1), - CONSTRAINT UK_Command UNIQUE (tenantid, name), - PRIMARY KEY (tenantid, id) -); -CREATE TABLE arch_data_instance ( - tenantId NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - name VARCHAR2(50 CHAR), - description VARCHAR2(50 CHAR), - transientData NUMBER(1), - className VARCHAR2(100 CHAR), - containerId NUMBER(19, 0), - containerType VARCHAR2(60 CHAR), - namespace VARCHAR2(100 CHAR), - element VARCHAR2(60 CHAR), - intValue INT, - longValue NUMBER(19, 0), - shortTextValue VARCHAR2(255 CHAR), - booleanValue NUMBER(1), - doubleValue NUMERIC(19,5), - floatValue REAL, - blobValue BLOB, - clobValue CLOB, - discriminant VARCHAR2(50 CHAR) NOT NULL, - archiveDate NUMBER(19, 0) NOT NULL, - sourceObjectId NUMBER(19, 0) NOT NULL, - PRIMARY KEY (tenantid, id) -); - -CREATE INDEX idx1_arch_data_instance ON arch_data_instance (tenantId, containerId, containerType, archiveDate, name, sourceObjectId); -CREATE INDEX idx2_arch_data_instance ON arch_data_instance (sourceObjectId, containerId, archiveDate, id, tenantId); - -CREATE TABLE data_instance ( - tenantId NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - name VARCHAR2(50 CHAR), - description VARCHAR2(50 CHAR), - transientData NUMBER(1), - className VARCHAR2(100 CHAR), - containerId NUMBER(19, 0), - containerType VARCHAR2(60 CHAR), - namespace VARCHAR2(100 CHAR), - element VARCHAR2(60 CHAR), - intValue INT, - longValue NUMBER(19, 0), - shortTextValue VARCHAR2(255 CHAR), - booleanValue NUMBER(1), - doubleValue NUMERIC(19,5), - floatValue REAL, - blobValue BLOB, - clobValue CLOB, - discriminant VARCHAR2(50 CHAR) NOT NULL, - PRIMARY KEY (tenantid, id) -); -CREATE INDEX idx_datai_container ON data_instance (tenantId, containerId, containerType, name); - -CREATE TABLE dependency ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - name VARCHAR2(150 CHAR) NOT NULL, - description VARCHAR2(1024 CHAR), - filename VARCHAR2(255 CHAR) NOT NULL, - value_ BLOB NOT NULL, - CONSTRAINT UK_Dependency UNIQUE (tenantId, name), - PRIMARY KEY (tenantid, id) -); -CREATE INDEX idx_dependency_name ON dependency (name); - -CREATE TABLE dependencymapping ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - artifactid NUMBER(19, 0) NOT NULL, - artifacttype VARCHAR2(50 CHAR) NOT NULL, - dependencyid NUMBER(19, 0) NOT NULL, - CONSTRAINT UK_Dependency_Mapping UNIQUE (tenantid, dependencyid, artifactid, artifacttype), - PRIMARY KEY (tenantid, id) -); -CREATE INDEX idx_dependencymapping_depid ON dependencymapping (dependencyid); -ALTER TABLE dependencymapping ADD CONSTRAINT fk_depmapping_depid FOREIGN KEY (tenantid, dependencyid) REFERENCES dependency(tenantid, id) ON DELETE CASCADE; -CREATE TABLE pdependency ( - id NUMBER(19, 0) NOT NULL, - name VARCHAR2(50 CHAR) NOT NULL UNIQUE, - description VARCHAR2(1024 CHAR), - filename VARCHAR2(255 CHAR) NOT NULL, - value_ BLOB NOT NULL, - PRIMARY KEY (id) -); - -CREATE TABLE pdependencymapping ( - id NUMBER(19, 0) NOT NULL, - artifactid NUMBER(19, 0) NOT NULL, - artifacttype VARCHAR2(50 CHAR) NOT NULL, - dependencyid NUMBER(19, 0) NOT NULL, - CONSTRAINT UK_PDependency_Mapping UNIQUE (dependencyid, artifactid, artifacttype), - PRIMARY KEY (id) -); -ALTER TABLE pdependencymapping ADD CONSTRAINT fk_pdepmapping_depid FOREIGN KEY (dependencyid) REFERENCES pdependency(id) ON DELETE CASCADE; -CREATE TABLE external_identity_mapping ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - kind VARCHAR2(25 CHAR) NOT NULL, - externalId VARCHAR2(50 CHAR) NOT NULL, - userId NUMBER(19, 0) NOT NULL, - groupId NUMBER(19, 0) NOT NULL, - roleId NUMBER(19, 0) NOT NULL, - CONSTRAINT UK_External_Identity_Mapping UNIQUE (tenantid, kind, externalId, userId, groupId, roleId), - PRIMARY KEY (tenantid, id) -); -CREATE TABLE group_ ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - name VARCHAR2(125 CHAR) NOT NULL, - parentPath VARCHAR2(255 CHAR), - displayName VARCHAR2(255 CHAR), - description VARCHAR2(1024 CHAR), - createdBy NUMBER(19, 0), - creationDate NUMBER(19, 0), - lastUpdate NUMBER(19, 0), - iconid NUMBER(19, 0), - PRIMARY KEY (tenantid, id) -); -CREATE INDEX idx_group_name ON group_ (tenantid, parentPath, name); - -CREATE TABLE role ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - name VARCHAR2(255 CHAR) NOT NULL, - displayName VARCHAR2(255 CHAR), - description VARCHAR2(1024 CHAR), - createdBy NUMBER(19, 0), - creationDate NUMBER(19, 0), - lastUpdate NUMBER(19, 0), - iconid NUMBER(19, 0), - CONSTRAINT UK_Role UNIQUE (tenantId, name), - PRIMARY KEY (tenantid, id) -); - - -CREATE TABLE user_ ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - enabled NUMBER(1) NOT NULL, - userName VARCHAR2(255 CHAR) NOT NULL, - password VARCHAR2(60 CHAR), - firstName VARCHAR2(255 CHAR), - lastName VARCHAR2(255 CHAR), - title VARCHAR2(50 CHAR), - jobTitle VARCHAR2(255 CHAR), - managerUserId NUMBER(19, 0), - createdBy NUMBER(19, 0), - creationDate NUMBER(19, 0), - lastUpdate NUMBER(19, 0), - iconid NUMBER(19, 0), - CONSTRAINT UK_User UNIQUE (tenantid, userName), - PRIMARY KEY (tenantid, id) -); - - -CREATE TABLE user_login ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - lastConnection NUMBER(19, 0), - PRIMARY KEY (tenantid, id) -); - -CREATE TABLE user_contactinfo ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - userId NUMBER(19, 0) NOT NULL, - email VARCHAR2(255 CHAR), - phone VARCHAR2(50 CHAR), - mobile VARCHAR2(50 CHAR), - fax VARCHAR2(50 CHAR), - building VARCHAR2(50 CHAR), - room VARCHAR2(50 CHAR), - address VARCHAR2(255 CHAR), - zipCode VARCHAR2(50 CHAR), - city VARCHAR2(255 CHAR), - state VARCHAR2(255 CHAR), - country VARCHAR2(255 CHAR), - website VARCHAR2(255 CHAR), - personal NUMBER(1) NOT NULL, - UNIQUE (tenantid, userId, personal), - PRIMARY KEY (tenantid, id) -); -ALTER TABLE user_contactinfo ADD CONSTRAINT fk_contact_user FOREIGN KEY (tenantid, userId) REFERENCES user_ (tenantid, id) ON DELETE CASCADE; - - -CREATE TABLE custom_usr_inf_def ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - name VARCHAR2(75 CHAR) NOT NULL, - description VARCHAR2(1024 CHAR), - CONSTRAINT UK_Custom_Usr_Inf_Def UNIQUE (tenantId, name), - PRIMARY KEY (tenantid, id) -); - - -CREATE TABLE custom_usr_inf_val ( - id NUMBER(19, 0) NOT NULL, - tenantid NUMBER(19, 0) NOT NULL, - definitionId NUMBER(19, 0) NOT NULL, - userId NUMBER(19, 0) NOT NULL, - value VARCHAR2(255 CHAR), - UNIQUE (tenantid, definitionId, userId), - PRIMARY KEY (tenantid, id) -); -ALTER TABLE custom_usr_inf_val ADD CONSTRAINT fk_user_id FOREIGN KEY (tenantid, userId) REFERENCES user_ (tenantid, id) ON DELETE CASCADE; -ALTER TABLE custom_usr_inf_val ADD CONSTRAINT fk_definition_id FOREIGN KEY (tenantid, definitionId) REFERENCES custom_usr_inf_def (tenantid, id) ON DELETE CASCADE; - -CREATE TABLE user_membership ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - userId NUMBER(19, 0) NOT NULL, - roleId NUMBER(19, 0) NOT NULL, - groupId NUMBER(19, 0) NOT NULL, - assignedBy NUMBER(19, 0), - assignedDate NUMBER(19, 0), - UNIQUE (tenantid, userId, roleId, groupId), - PRIMARY KEY (tenantid, id) -); -CREATE TABLE queriable_log ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - log_timestamp NUMBER(19, 0) NOT NULL, - whatYear SMALLINT NOT NULL, - whatMonth SMALLINT NOT NULL, - dayOfYear SMALLINT NOT NULL, - weekOfYear SMALLINT NOT NULL, - userId VARCHAR2(255 CHAR) NOT NULL, - threadNumber NUMBER(19, 0) NOT NULL, - clusterNode VARCHAR2(50 CHAR), - productVersion VARCHAR2(50 CHAR) NOT NULL, - severity VARCHAR2(50 CHAR) NOT NULL, - actionType VARCHAR2(50 CHAR) NOT NULL, - actionScope VARCHAR2(100 CHAR), - actionStatus SMALLINT NOT NULL, - rawMessage VARCHAR2(255 CHAR) NOT NULL, - callerClassName VARCHAR2(200 CHAR), - callerMethodName VARCHAR2(80 CHAR), - numericIndex1 NUMBER(19, 0), - numericIndex2 NUMBER(19, 0), - numericIndex3 NUMBER(19, 0), - numericIndex4 NUMBER(19, 0), - numericIndex5 NUMBER(19, 0), - PRIMARY KEY (tenantid, id) -); - -CREATE TABLE queriablelog_p ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - queriableLogId NUMBER(19, 0) NOT NULL, - name VARCHAR2(50 CHAR) NOT NULL, - stringValue VARCHAR2(255 CHAR), - blobId NUMBER(19, 0), - valueType VARCHAR2(30 CHAR), - PRIMARY KEY (tenantid, id) -); - -CREATE INDEX idx_queriablelog ON queriablelog_p (queriableLogId); -ALTER TABLE queriablelog_p ADD CONSTRAINT fk_queriableLogId FOREIGN KEY (tenantid, queriableLogId) REFERENCES queriable_log(tenantid, id); - -CREATE TABLE page ( - tenantId NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - name VARCHAR2(255 CHAR) NOT NULL, - displayName VARCHAR2(255 CHAR) NOT NULL, - description VARCHAR2(1024 CHAR), - installationDate NUMBER(19, 0) NOT NULL, - installedBy NUMBER(19, 0) NOT NULL, - provided NUMBER(1), - editable NUMBER(1), - removable NUMBER(1), - lastModificationDate NUMBER(19, 0) NOT NULL, - lastUpdatedBy NUMBER(19, 0) NOT NULL, - contentName VARCHAR2(280 CHAR) NOT NULL, - content BLOB, - contentType VARCHAR2(50 CHAR), - processDefinitionId NUMBER(19, 0) NOT NULL, - pageHash VARCHAR2(32 CHAR) -); - -ALTER TABLE page ADD CONSTRAINT pk_page PRIMARY KEY (tenantid, id); - -ALTER TABLE page ADD CONSTRAINT uk_page UNIQUE (tenantId, name, processDefinitionId); - -CREATE TABLE sequence ( - tenantid NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - nextid NUMBER(19, 0) NOT NULL, - PRIMARY KEY (tenantid, id) -); -CREATE TABLE blob_ ( - tenantId NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - blobValue BLOB, - PRIMARY KEY (tenantid, id) -); - -CREATE TABLE platform ( - id NUMBER(19, 0) NOT NULL, - version VARCHAR2(50 CHAR) NOT NULL, - initial_bonita_version VARCHAR2(50 CHAR) NOT NULL, - application_version VARCHAR2(50 CHAR) NOT NULL, - maintenance_message VARCHAR2(1024 CHAR), - maintenance_message_active NUMBER(1) NOT NULL, - created NUMBER(19, 0) NOT NULL, - created_by VARCHAR2(50 CHAR) NOT NULL, - information CLOB, - PRIMARY KEY (id) -); - -CREATE TABLE tenant ( - id NUMBER(19, 0) NOT NULL, - created NUMBER(19, 0) NOT NULL, - createdBy VARCHAR2(50 CHAR) NOT NULL, - description VARCHAR2(255 CHAR), - defaultTenant NUMBER(1) NOT NULL, - iconname VARCHAR2(50 CHAR), - iconpath VARCHAR2(255 CHAR), - name VARCHAR2(50 CHAR) NOT NULL, - status VARCHAR2(15 CHAR) NOT NULL, - PRIMARY KEY (id) -); -CREATE TABLE platformCommand ( - id NUMBER(19, 0) PRIMARY KEY, - name VARCHAR2(50 CHAR) NOT NULL UNIQUE, - description VARCHAR2(1024 CHAR), - IMPLEMENTATION VARCHAR2(100 CHAR) NOT NULL -); -CREATE TABLE profile ( - tenantId NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - isDefault NUMBER(1) NOT NULL, - name VARCHAR2(50 CHAR) NOT NULL, - description VARCHAR2(1024 CHAR), - creationDate NUMBER(19, 0) NOT NULL, - createdBy NUMBER(19, 0) NOT NULL, - lastUpdateDate NUMBER(19, 0) NOT NULL, - lastUpdatedBy NUMBER(19, 0) NOT NULL, - CONSTRAINT UK_Profile UNIQUE (tenantId, name), - PRIMARY KEY (tenantId, id) -); - -CREATE TABLE profilemember ( - tenantId NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - profileId NUMBER(19, 0) NOT NULL, - userId NUMBER(19, 0) NOT NULL, - groupId NUMBER(19, 0) NOT NULL, - roleId NUMBER(19, 0) NOT NULL, - UNIQUE (tenantId, profileId, userId, groupId, roleId), - PRIMARY KEY (tenantId, id) -); -CREATE TABLE job_desc ( - tenantId NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - jobclassname VARCHAR2(100 CHAR) NOT NULL, - jobname VARCHAR2(100 CHAR) NOT NULL, - description VARCHAR2(50 CHAR), - PRIMARY KEY (tenantId, id) -); - -CREATE TABLE job_param ( - tenantId NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - jobDescriptorId NUMBER(19, 0) NOT NULL, - key_ VARCHAR2(50 CHAR) NOT NULL, - value_ BLOB NOT NULL, - PRIMARY KEY (tenantId, id) -); -CREATE INDEX idx_job_param_tenant_jobid ON job_param (tenantid, jobDescriptorId); - -CREATE TABLE job_log ( - tenantId NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - jobDescriptorId NUMBER(19, 0) NOT NULL, - retryNumber NUMBER(19, 0), - lastUpdateDate NUMBER(19, 0), - lastMessage CLOB, - UNIQUE (tenantId, jobDescriptorId), - PRIMARY KEY (tenantId, id) -); - -ALTER TABLE job_param ADD CONSTRAINT fk_job_param_jobid FOREIGN KEY (tenantid, jobDescriptorId) REFERENCES job_desc(tenantid, id) ON DELETE CASCADE; -ALTER TABLE job_log ADD CONSTRAINT fk_job_log_jobid FOREIGN KEY (tenantid, jobDescriptorId) REFERENCES job_desc(tenantid, id) ON DELETE CASCADE; - -CREATE TABLE form_mapping ( - tenantId NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - process NUMBER(19, 0) NOT NULL, - type INT NOT NULL, - task VARCHAR2(255 CHAR), - page_mapping_tenant_id NUMBER(19, 0), - page_mapping_id NUMBER(19, 0), - lastUpdateDate NUMBER(19, 0), - lastUpdatedBy NUMBER(19, 0), - target VARCHAR2(16 CHAR) NOT NULL, - PRIMARY KEY (tenantId, id) -); - -CREATE TABLE page_mapping ( - tenantId NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - key_ VARCHAR2(255 CHAR) NOT NULL, - pageId NUMBER(19, 0) NULL, - url VARCHAR2(1024 CHAR) NULL, - urladapter VARCHAR2(255 CHAR) NULL, - page_authoriz_rules VARCHAR2(1024 CHAR) NULL, - lastUpdateDate NUMBER(19, 0) NULL, - lastUpdatedBy NUMBER(19, 0) NULL, - CONSTRAINT UK_page_mapping UNIQUE (tenantId, key_), - PRIMARY KEY (tenantId, id) -); - -ALTER TABLE form_mapping ADD CONSTRAINT fk_form_mapping_key FOREIGN KEY (page_mapping_tenant_id, page_mapping_id) REFERENCES page_mapping(tenantId, id); - -CREATE TABLE proc_parameter ( - tenantId NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - process_id NUMBER(19, 0) NOT NULL, - name VARCHAR2(255 CHAR) NOT NULL, - value CLOB NULL, - PRIMARY KEY (tenantId, id) -); - -CREATE TABLE bar_resource ( - tenantId NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - process_id NUMBER(19, 0) NOT NULL, - name VARCHAR2(255) NOT NULL, - type VARCHAR2(16) NOT NULL, - content BLOB NOT NULL, - UNIQUE (tenantId, process_id, name, type), - PRIMARY KEY (tenantId, id) -); -CREATE INDEX idx_bar_resource ON bar_resource (tenantId, process_id, type, name); - -CREATE TABLE temporary_content ( - id NUMBER(19, 0) NOT NULL, - creationDate NUMBER(19, 0) NOT NULL, - key_ VARCHAR2(255) NOT NULL, - fileName VARCHAR2(255) NOT NULL, - mimeType VARCHAR2(255) NOT NULL, - content BLOB NOT NULL, - UNIQUE (key_), - PRIMARY KEY (id) -); - -CREATE TABLE tenant_resource ( - tenantId NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - name VARCHAR2(255) NOT NULL, - type VARCHAR2(16) NOT NULL, - content BLOB NOT NULL, - lastUpdatedBy NUMBER(19,0) NOT NULL, - lastUpdateDate NUMBER(19,0), - state VARCHAR2(50) NOT NULL, - CONSTRAINT UK_tenant_resource UNIQUE (tenantId, name, type), - PRIMARY KEY (tenantId, id) -); -CREATE INDEX idx_tenant_resource ON tenant_resource (tenantId, type, name); - -CREATE TABLE icon ( - tenantId NUMBER(19, 0) NOT NULL, - id NUMBER(19, 0) NOT NULL, - mimetype VARCHAR2(255) NOT NULL, - content BLOB NOT NULL, - CONSTRAINT pk_icon PRIMARY KEY (tenantId, id) -); diff --git a/platform/platform-resources/src/main/resources/sql/oracle/dropQuartzTables.sql b/platform/platform-resources/src/main/resources/sql/oracle/dropQuartzTables.sql deleted file mode 100644 index c67a1cd69f9..00000000000 --- a/platform/platform-resources/src/main/resources/sql/oracle/dropQuartzTables.sql +++ /dev/null @@ -1,11 +0,0 @@ -DROP TABLE QRTZ_FIRED_TRIGGERS cascade constraints purge; -DROP TABLE QRTZ_PAUSED_TRIGGER_GRPS cascade constraints purge; -DROP TABLE QRTZ_SCHEDULER_STATE cascade constraints purge; -DROP TABLE QRTZ_LOCKS cascade constraints purge; -DROP TABLE QRTZ_SIMPLE_TRIGGERS cascade constraints purge; -DROP TABLE QRTZ_SIMPROP_TRIGGERS cascade constraints purge; -DROP TABLE QRTZ_CRON_TRIGGERS cascade constraints purge; -DROP TABLE QRTZ_BLOB_TRIGGERS cascade constraints purge; -DROP TABLE QRTZ_TRIGGERS cascade constraints purge; -DROP TABLE QRTZ_JOB_DETAILS cascade constraints purge; -DROP TABLE QRTZ_CALENDARS cascade constraints purge; diff --git a/platform/platform-resources/src/main/resources/sql/oracle/dropTables.sql b/platform/platform-resources/src/main/resources/sql/oracle/dropTables.sql deleted file mode 100644 index 6c683d039d6..00000000000 --- a/platform/platform-resources/src/main/resources/sql/oracle/dropTables.sql +++ /dev/null @@ -1,68 +0,0 @@ -DROP TABLE configuration cascade constraints purge; -DROP TABLE arch_contract_data cascade constraints purge; -DROP TABLE contract_data cascade constraints purge; -DROP TABLE actormember cascade constraints purge; -DROP TABLE actor cascade constraints purge; -DROP TABLE processcategorymapping cascade constraints purge; -DROP TABLE category cascade constraints purge; -DROP TABLE arch_process_comment cascade constraints purge; -DROP TABLE process_comment cascade constraints purge; -DROP TABLE process_definition cascade constraints purge; -DROP TABLE arch_document_mapping cascade constraints purge; -DROP TABLE document_mapping cascade constraints purge; -DROP TABLE document cascade constraints purge; -DROP TABLE arch_flownode_instance cascade constraints purge; -DROP TABLE arch_process_instance cascade constraints purge; -DROP TABLE arch_connector_instance cascade constraints purge; -DROP TABLE arch_multi_biz_data cascade constraints purge; -DROP TABLE arch_ref_biz_data_inst cascade constraints purge; -DROP TABLE multi_biz_data cascade constraints purge; -DROP TABLE ref_biz_data_inst cascade constraints purge; -DROP TABLE pending_mapping cascade constraints purge; -DROP TABLE connector_instance cascade constraints purge; -DROP TABLE flownode_instance cascade constraints purge; -DROP TABLE process_instance cascade constraints purge; -DROP TABLE event_trigger_instance cascade constraints purge; -DROP TABLE waiting_event cascade constraints purge; -DROP TABLE message_instance cascade constraints purge; -DROP TABLE processsupervisor cascade constraints purge; -DROP TABLE business_app_menu cascade constraints purge; -DROP TABLE business_app_page cascade constraints purge; -DROP TABLE business_app cascade constraints purge; -DROP TABLE command cascade constraints purge; -DROP TABLE arch_data_instance cascade constraints purge; -DROP TABLE data_instance cascade constraints purge; -DROP TABLE dependencymapping cascade constraints purge; -DROP TABLE dependency cascade constraints purge; -DROP TABLE pdependencymapping cascade constraints purge; -DROP TABLE pdependency cascade constraints purge; -DROP TABLE external_identity_mapping cascade constraints purge; -DROP TABLE user_membership cascade constraints purge; -DROP TABLE custom_usr_inf_val cascade constraints purge; -DROP TABLE custom_usr_inf_def cascade constraints purge; -DROP TABLE user_contactinfo cascade constraints purge; -DROP TABLE user_login cascade constraints purge; -DROP TABLE user_ cascade constraints purge; -DROP TABLE role cascade constraints purge; -DROP TABLE group_ cascade constraints purge; -DROP TABLE queriablelog_p cascade constraints purge; -DROP TABLE queriable_log cascade constraints purge; -DROP TABLE page cascade constraints purge; -DROP TABLE blob_ cascade constraints purge; -DROP TABLE profilemember cascade constraints purge; -DROP TABLE profile cascade constraints purge; -DROP TABLE job_log cascade constraints purge; -DROP TABLE job_param cascade constraints purge; -DROP TABLE job_desc cascade constraints purge; -DROP TABLE sequence cascade constraints purge; -DROP TABLE tenant cascade constraints purge; -DROP TABLE platform cascade constraints purge; -DROP TABLE platformCommand cascade constraints purge; -DROP TABLE form_mapping cascade constraints purge; -DROP TABLE page_mapping cascade constraints purge; -DROP TABLE process_content cascade constraints purge; -DROP TABLE proc_parameter cascade constraints purge; -DROP TABLE bar_resource cascade constraints purge; -DROP TABLE temporary_content cascade constraints purge; -DROP TABLE tenant_resource cascade constraints purge; -DROP TABLE icon cascade constraints purge; \ No newline at end of file diff --git a/platform/platform-resources/src/main/resources/sql/oracle/initTables.sql b/platform/platform-resources/src/main/resources/sql/oracle/initTables.sql deleted file mode 100644 index 7e3d54500e5..00000000000 --- a/platform/platform-resources/src/main/resources/sql/oracle/initTables.sql +++ /dev/null @@ -1,65 +0,0 @@ -INSERT INTO sequence VALUES (-1, 1, 1); -INSERT INTO sequence VALUES (-1, 2, 1); -INSERT INTO sequence VALUES (-1, 3, 1); -INSERT INTO sequence VALUES (-1, 4, 1); -INSERT INTO sequence VALUES (-1, 5, 1); -INSERT INTO sequence VALUES(1, 10, 1); -INSERT INTO sequence VALUES(1, 11, 1); -INSERT INTO sequence VALUES(1, 20, 1); -INSERT INTO sequence VALUES(1, 21, 1); -INSERT INTO sequence VALUES(1, 22, 1); -INSERT INTO sequence VALUES(1, 23, 1); -INSERT INTO sequence VALUES(1, 24, 1); -INSERT INTO sequence VALUES(1, 25, 1); -INSERT INTO sequence VALUES(1, 26, 1); -INSERT INTO sequence VALUES(1, 27, 1); -INSERT INTO sequence VALUES(1, 30, 1); -INSERT INTO sequence VALUES(1, 31, 1); -INSERT INTO sequence VALUES(1, 70, 1); -INSERT INTO sequence VALUES(1, 71, 1); -INSERT INTO sequence VALUES(1, 72, 1); -INSERT INTO sequence VALUES(1, 90, 1); -INSERT INTO sequence VALUES(1, 9990, 1); -INSERT INTO sequence VALUES(1, 9992, 1); -INSERT INTO sequence VALUES(1, 10000, 1); -INSERT INTO sequence VALUES(1, 10001, 1); -INSERT INTO sequence VALUES(1, 10010, 1); -INSERT INTO sequence VALUES(1, 10011, 1); -INSERT INTO sequence VALUES(1, 10012, 1); -INSERT INTO sequence VALUES(1, 10014, 1); -INSERT INTO sequence VALUES(1, 10015, 1); -INSERT INTO sequence VALUES(1, 10016, 1); -INSERT INTO sequence VALUES(1, 10017, 1); -INSERT INTO sequence VALUES(1, 10018, 1); -INSERT INTO sequence VALUES(1, 10020, 1); -INSERT INTO sequence VALUES(1, 10021, 1); -INSERT INTO sequence VALUES(1, 10030, 1); -INSERT INTO sequence VALUES(1, 10031, 1); -INSERT INTO sequence VALUES(1, 10040, 1); -INSERT INTO sequence VALUES(1, 20051, 1); -INSERT INTO sequence VALUES(1, 10050, 1); -INSERT INTO sequence VALUES(1, 10060, 1); -INSERT INTO sequence VALUES(1, 10070, 1); -INSERT INTO sequence VALUES(1, 10080, 1); -INSERT INTO sequence VALUES(1, 10090, 1); -INSERT INTO sequence VALUES(1, 10096, 1); -INSERT INTO sequence VALUES(1, 10120, 1); -INSERT INTO sequence VALUES(1, 10121, 1); -INSERT INTO sequence VALUES(1, 10200, 1); -INSERT INTO sequence VALUES(1, 10201, 1); -INSERT INTO sequence VALUES(1, 10202, 1); -INSERT INTO sequence VALUES(1, 10210, 1); -INSERT INTO sequence VALUES(1, 10220, 1); -INSERT INTO sequence VALUES(1, 10300, 1); -INSERT INTO sequence VALUES(1, 10310, 1); -INSERT INTO sequence VALUES(1, 10400, 1); -INSERT INTO sequence VALUES(1, 10500, 1); -INSERT INTO sequence VALUES(1, 10501, 1); -INSERT INTO sequence VALUES(1, 20010, 1); -INSERT INTO sequence VALUES(1, 20011, 1); -INSERT INTO sequence VALUES(1, 20013, 1); -INSERT INTO sequence VALUES(1, 20040, 1); -INSERT INTO sequence VALUES(1, 20050, 1); -INSERT INTO sequence VALUES(1, 20210, 1); -INSERT INTO sequence VALUES(1, 20220, 1); -INSERT INTO sequence VALUES(1, 20096, 1); diff --git a/platform/platform-resources/src/main/resources/sql/oracle/postCreateStructure.sql b/platform/platform-resources/src/main/resources/sql/oracle/postCreateStructure.sql deleted file mode 100755 index 2974f0fa582..00000000000 --- a/platform/platform-resources/src/main/resources/sql/oracle/postCreateStructure.sql +++ /dev/null @@ -1,35 +0,0 @@ -ALTER TABLE actormember ADD CONSTRAINT fk_actormember_actorId FOREIGN KEY (tenantid, actorId) REFERENCES actor(tenantid, id); -ALTER TABLE queriablelog_p ADD CONSTRAINT fk_queriablelog_p_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE document ADD CONSTRAINT fk_document_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE document_mapping ADD CONSTRAINT fk_docmap_docid FOREIGN KEY (tenantid, documentid) REFERENCES document(tenantid, id) ON DELETE CASCADE; -ALTER TABLE event_trigger_instance ADD CONSTRAINT fk_EvtTrig_tenId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE external_identity_mapping ADD CONSTRAINT fk_extIdMap_tenId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE custom_usr_inf_def ADD CONSTRAINT fk_custom_usr_inf_def_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE custom_usr_inf_val ADD CONSTRAINT fk_custom_usr_inf_val_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE pending_mapping ADD CONSTRAINT fk_pMap_flnId FOREIGN KEY (tenantid, activityId) REFERENCES flownode_instance(tenantid, id); -ALTER TABLE processcategorymapping ADD CONSTRAINT fk_procCatMap_tenId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE multi_biz_data ADD CONSTRAINT fk_multi_biz_data_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE ref_biz_data_inst ADD CONSTRAINT fk_ref_biz_data_inst_tenantId FOREIGN KEY (tenantId) REFERENCES tenant(id); -ALTER TABLE process_definition ADD CONSTRAINT fk_process_definition_content FOREIGN KEY (content_tenantid, content_id) REFERENCES process_content(tenantid, id); - - -ALTER TABLE business_app ADD CONSTRAINT fk_app_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE business_app ADD CONSTRAINT fk_app_profileId FOREIGN KEY (tenantid, profileId) REFERENCES profile (tenantid, id); -ALTER TABLE business_app ADD CONSTRAINT fk_app_layoutId FOREIGN KEY (tenantid, layoutId) REFERENCES page (tenantid, id); -ALTER TABLE business_app ADD CONSTRAINT fk_app_themeId FOREIGN KEY (tenantid, themeId) REFERENCES page (tenantid, id); -ALTER TABLE business_app_page ADD CONSTRAINT fk_app_page_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE business_app_page ADD CONSTRAINT fk_bus_app_id FOREIGN KEY (tenantid, applicationId) REFERENCES business_app (tenantid, id) ON DELETE CASCADE; -ALTER TABLE business_app_page ADD CONSTRAINT fk_page_id FOREIGN KEY (tenantid, pageId) REFERENCES page (tenantid, id); - -ALTER TABLE business_app_menu ADD CONSTRAINT fk_app_menu_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id); - -ALTER TABLE business_app_menu ADD CONSTRAINT fk_app_menu_appId FOREIGN KEY (tenantid, applicationId) REFERENCES business_app (tenantid, id); -ALTER TABLE business_app_menu ADD CONSTRAINT fk_app_menu_pageId FOREIGN KEY (tenantid, applicationPageId) REFERENCES business_app_page (tenantid, id); - -ALTER TABLE business_app_menu ADD CONSTRAINT fk_app_menu_parentId FOREIGN KEY (tenantid, parentId) REFERENCES business_app_menu (tenantid, id); - -ALTER TABLE arch_document_mapping ADD CONSTRAINT fk_ADocMap_tenId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE arch_document_mapping ADD CONSTRAINT fk_archdocmap_docid FOREIGN KEY (tenantid, documentid) REFERENCES document(tenantid, id) ON DELETE CASCADE; -ALTER TABLE arch_flownode_instance ADD CONSTRAINT fk_AFln_tenId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE arch_process_comment ADD CONSTRAINT fk_AProcCom_tenId FOREIGN KEY (tenantid) REFERENCES tenant(id); -ALTER TABLE arch_process_instance ADD CONSTRAINT fk_AProc_tenId FOREIGN KEY (tenantid) REFERENCES tenant(id); diff --git a/platform/platform-resources/src/main/resources/sql/oracle/preDropStructure.sql b/platform/platform-resources/src/main/resources/sql/oracle/preDropStructure.sql deleted file mode 100755 index e37f799f6d3..00000000000 --- a/platform/platform-resources/src/main/resources/sql/oracle/preDropStructure.sql +++ /dev/null @@ -1,33 +0,0 @@ -ALTER TABLE actormember DROP CONSTRAINT fk_actormember_actorId; -ALTER TABLE queriablelog_p DROP CONSTRAINT fk_queriablelog_p_tenantId; -ALTER TABLE document DROP CONSTRAINT fk_document_tenantId; -ALTER TABLE document_mapping DROP CONSTRAINT fk_docmap_docid; -ALTER TABLE event_trigger_instance DROP CONSTRAINT fk_EvtTrig_tenId; -ALTER TABLE external_identity_mapping DROP CONSTRAINT fk_extIdMap_tenId; -ALTER TABLE custom_usr_inf_def DROP CONSTRAINT fk_custom_usr_inf_def_tenantId; -ALTER TABLE custom_usr_inf_val DROP CONSTRAINT fk_custom_usr_inf_val_tenantId; -ALTER TABLE pending_mapping DROP CONSTRAINT fk_pMap_flnId; -ALTER TABLE processcategorymapping DROP CONSTRAINT fk_procCatMap_tenId; -ALTER TABLE multi_biz_data DROP CONSTRAINT fk_multi_biz_data_tenantId; -ALTER TABLE ref_biz_data_inst DROP CONSTRAINT fk_ref_biz_data_inst_tenantId; -ALTER TABLE process_definition DROP CONSTRAINT fk_process_definition_content; - - -ALTER TABLE business_app_menu DROP CONSTRAINT fk_app_menu_tenantId; -ALTER TABLE business_app_menu DROP CONSTRAINT fk_app_menu_appId; -ALTER TABLE business_app_menu DROP CONSTRAINT fk_app_menu_pageId; -ALTER TABLE business_app_menu DROP CONSTRAINT fk_app_menu_parentId; -ALTER TABLE business_app_page DROP CONSTRAINT fk_app_page_tenantId; -ALTER TABLE business_app_page DROP CONSTRAINT fk_bus_app_id; -ALTER TABLE business_app_page DROP CONSTRAINT fk_page_id; -ALTER TABLE business_app DROP CONSTRAINT fk_app_profileId; -ALTER TABLE business_app DROP CONSTRAINT fk_app_tenantId; -ALTER TABLE business_app DROP CONSTRAINT fk_app_layoutId; -ALTER TABLE business_app DROP CONSTRAINT fk_app_themeId; - - -ALTER TABLE arch_document_mapping DROP CONSTRAINT fk_ADocMap_tenId; -ALTER TABLE arch_document_mapping DROP CONSTRAINT fk_archdocmap_docid; -ALTER TABLE arch_flownode_instance DROP CONSTRAINT fk_AFln_tenId; -ALTER TABLE arch_process_comment DROP CONSTRAINT fk_AProcCom_tenId; -ALTER TABLE arch_process_instance DROP CONSTRAINT fk_AProc_tenId; diff --git a/platform/platform-resources/src/main/resources/sql/postgres/createTables.sql b/platform/platform-resources/src/main/resources/sql/postgres/createTables.sql index 260f0c199da..909a8d57413 100644 --- a/platform/platform-resources/src/main/resources/sql/postgres/createTables.sql +++ b/platform/platform-resources/src/main/resources/sql/postgres/createTables.sql @@ -524,7 +524,8 @@ CREATE TABLE business_app ( iconContent BYTEA, displayName VARCHAR(255) NOT NULL, editable BOOLEAN, - internalProfile VARCHAR(255) + internalProfile VARCHAR(255), + isLink BOOLEAN DEFAULT FALSE ); ALTER TABLE business_app ADD CONSTRAINT pk_business_app PRIMARY KEY (tenantid, id); diff --git a/platform/platform-resources/src/main/resources/sql/postgres/preDropStructure.sql b/platform/platform-resources/src/main/resources/sql/postgres/preDropStructure.sql old mode 100755 new mode 100644 diff --git a/platform/platform-resources/src/main/resources/sql/sqlserver/cleanTables.sql b/platform/platform-resources/src/main/resources/sql/sqlserver/cleanTables.sql deleted file mode 100644 index 7eefc126b07..00000000000 --- a/platform/platform-resources/src/main/resources/sql/sqlserver/cleanTables.sql +++ /dev/null @@ -1,119 +0,0 @@ -DELETE FROM arch_contract_data -GO -DELETE FROM contract_data -GO -DELETE FROM actormember -GO -DELETE FROM actor -GO -DELETE FROM processcategorymapping -GO -DELETE FROM category -GO -DELETE FROM arch_process_comment -GO -DELETE FROM process_comment -GO -DELETE FROM process_definition -GO -DELETE FROM arch_document_mapping -GO -DELETE FROM document -GO -DELETE FROM document_mapping -GO -DELETE FROM arch_flownode_instance -GO -DELETE FROM arch_process_instance -GO -DELETE FROM arch_connector_instance -GO -DELETE FROM arch_multi_biz_data -GO -DELETE FROM arch_ref_biz_data_inst -GO -DELETE FROM multi_biz_data -GO -DELETE FROM ref_biz_data_inst -GO -DELETE FROM pending_mapping -GO -DELETE FROM message_instance -GO -DELETE FROM waiting_event -GO -DELETE FROM event_trigger_instance -GO -DELETE FROM connector_instance -GO -DELETE FROM flownode_instance -GO -DELETE FROM process_instance -GO -DELETE FROM processsupervisor -GO -DELETE FROM business_app_menu -GO -DELETE FROM business_app_page -GO -DELETE FROM business_app -GO -DELETE FROM command -GO -DELETE FROM arch_data_instance -GO -DELETE FROM data_instance -GO -DELETE FROM dependencymapping -GO -DELETE FROM dependency -GO -DELETE FROM external_identity_mapping -GO -DELETE FROM user_membership -GO -DELETE FROM custom_usr_inf_val -GO -DELETE FROM custom_usr_inf_def -GO -DELETE FROM user_contactinfo -GO -DELETE FROM user_login -GO -DELETE FROM user_ -GO -DELETE FROM role -GO -DELETE FROM group_ -GO -DELETE FROM queriablelog_p -GO -DELETE FROM queriable_log -GO -DELETE FROM page -GO -DELETE FROM sequence WHERE tenantId <> -1 -GO -DELETE FROM profilemember -GO -DELETE FROM profile -GO -DELETE FROM job_log -GO -DELETE FROM job_param -GO -DELETE FROM job_desc -GO -DELETE FROM tenant -GO -DELETE FROM platformCommand -GO -DELETE FROM form_mapping -GO -DELETE FROM page_mapping -GO -DELETE FROM proc_parameter -GO - --- do NOT clear directly PLATFORM table, Hibernate needs to update its cache to know the platform has been deleted - \ No newline at end of file diff --git a/platform/platform-resources/src/main/resources/sql/sqlserver/createQuartzTables.sql b/platform/platform-resources/src/main/resources/sql/sqlserver/createQuartzTables.sql deleted file mode 100644 index da71a0072a0..00000000000 --- a/platform/platform-resources/src/main/resources/sql/sqlserver/createQuartzTables.sql +++ /dev/null @@ -1,409 +0,0 @@ ---# thanks to George Papastamatopoulos for submitting this ... and Marko Lahma for ---# updating it. ---# ---# In your Quartz properties file, you'll need to set ---# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.MSSQLDelegate ---# ---# you shouse enter your DB instance's name on the next line in place of "enter_db_name_here" ---# ---# ---# From a helpful (but anonymous) Quartz user: ---# ---# Regarding this error message: ---# ---# [Microsoft][SQLServer 2000 Driver for JDBC]Can't start a cloned connection while in manual transaction mode. ---# ---# ---# I added "SelectMethod=cursor;" to my Connection URL in the config file. ---# It Seems to work, hopefully no side effects. ---# ---# example: ---# "jdbc:microsoft:sqlserver://dbmachine:1433;SelectMethod=cursor"; ---# ---# Another user has pointed out that you will probably need to use the ---# JTDS driver ---# - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1) -ALTER TABLE [dbo].[QRTZ_TRIGGERS] DROP CONSTRAINT FK_QRTZ_TRIGGERS -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_CRON_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1) -ALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] DROP CONSTRAINT FK_QRTZ_CRON_TRIGGERS -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_SIMPLE_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1) -ALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] DROP CONSTRAINT FK_QRTZ_SIMPLE_TRIGGERS -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_SIMPROP_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1) -ALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] DROP CONSTRAINT FK_QRTZ_SIMPROP_TRIGGERS -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_CALENDARS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_CALENDARS] -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_CRON_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_CRON_TRIGGERS] -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_BLOB_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_BLOB_TRIGGERS] -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_FIRED_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_FIRED_TRIGGERS] -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_PAUSED_TRIGGER_GRPS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_SCHEDULER_STATE]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_SCHEDULER_STATE] -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_LOCKS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_LOCKS] -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_JOB_DETAILS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_JOB_DETAILS] -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_SIMPLE_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_SIMPROP_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_TRIGGERS] -GO - -CREATE TABLE [dbo].[QRTZ_CALENDARS] ( - [SCHED_NAME] [VARCHAR] (120) NOT NULL , - [CALENDAR_NAME] [VARCHAR] (200) NOT NULL , - [CALENDAR] [IMAGE] NOT NULL -) ON [PRIMARY] -GO - -CREATE TABLE [dbo].[QRTZ_CRON_TRIGGERS] ( - [SCHED_NAME] [VARCHAR] (120) NOT NULL , - [TRIGGER_NAME] [VARCHAR] (200) NOT NULL , - [TRIGGER_GROUP] [VARCHAR] (200) NOT NULL , - [CRON_EXPRESSION] [VARCHAR] (120) NOT NULL , - [TIME_ZONE_ID] [VARCHAR] (80) -) ON [PRIMARY] -GO - -CREATE TABLE [dbo].[QRTZ_FIRED_TRIGGERS] ( - [SCHED_NAME] [VARCHAR] (120) NOT NULL , - [ENTRY_ID] [VARCHAR] (95) NOT NULL , - [TRIGGER_NAME] [VARCHAR] (200) NOT NULL , - [TRIGGER_GROUP] [VARCHAR] (200) NOT NULL , - [INSTANCE_NAME] [VARCHAR] (200) NOT NULL , - [FIRED_TIME] [BIGINT] NOT NULL , - [SCHED_TIME] [BIGINT] NOT NULL , - [PRIORITY] [INTEGER] NOT NULL , - [STATE] [VARCHAR] (16) NOT NULL, - [JOB_NAME] [VARCHAR] (200) NULL , - [JOB_GROUP] [VARCHAR] (200) NULL , - [IS_NONCONCURRENT] [VARCHAR] (1) NULL , - [REQUESTS_RECOVERY] [VARCHAR] (1) NULL -) ON [PRIMARY] -GO - -CREATE TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] ( - [SCHED_NAME] [VARCHAR] (120) NOT NULL , - [TRIGGER_GROUP] [VARCHAR] (200) NOT NULL -) ON [PRIMARY] -GO - -CREATE TABLE [dbo].[QRTZ_SCHEDULER_STATE] ( - [SCHED_NAME] [VARCHAR] (120) NOT NULL , - [INSTANCE_NAME] [VARCHAR] (200) NOT NULL , - [LAST_CHECKIN_TIME] [BIGINT] NOT NULL , - [CHECKIN_INTERVAL] [BIGINT] NOT NULL -) ON [PRIMARY] -GO - -CREATE TABLE [dbo].[QRTZ_LOCKS] ( - [SCHED_NAME] [VARCHAR] (120) NOT NULL , - [LOCK_NAME] [VARCHAR] (40) NOT NULL -) ON [PRIMARY] -GO - -CREATE TABLE [dbo].[QRTZ_JOB_DETAILS] ( - [SCHED_NAME] [VARCHAR] (120) NOT NULL , - [JOB_NAME] [VARCHAR] (200) NOT NULL , - [JOB_GROUP] [VARCHAR] (200) NOT NULL , - [DESCRIPTION] [VARCHAR] (250) NULL , - [JOB_CLASS_NAME] [VARCHAR] (250) NOT NULL , - [IS_DURABLE] [VARCHAR] (1) NOT NULL , - [IS_NONCONCURRENT] [VARCHAR] (1) NOT NULL , - [IS_UPDATE_DATA] [VARCHAR] (1) NOT NULL , - [REQUESTS_RECOVERY] [VARCHAR] (1) NOT NULL , - [JOB_DATA] [IMAGE] NULL -) ON [PRIMARY] -GO - -CREATE TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] ( - [SCHED_NAME] [VARCHAR] (120) NOT NULL , - [TRIGGER_NAME] [VARCHAR] (200) NOT NULL , - [TRIGGER_GROUP] [VARCHAR] (200) NOT NULL , - [REPEAT_COUNT] [BIGINT] NOT NULL , - [REPEAT_INTERVAL] [BIGINT] NOT NULL , - [TIMES_TRIGGERED] [BIGINT] NOT NULL -) ON [PRIMARY] -GO - -CREATE TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] ( - [SCHED_NAME] [VARCHAR] (120) NOT NULL , - [TRIGGER_NAME] [VARCHAR] (200) NOT NULL , - [TRIGGER_GROUP] [VARCHAR] (200) NOT NULL , - [STR_PROP_1] [VARCHAR] (512) NULL, - [STR_PROP_2] [VARCHAR] (512) NULL, - [STR_PROP_3] [VARCHAR] (512) NULL, - [INT_PROP_1] [INT] NULL, - [INT_PROP_2] [INT] NULL, - [LONG_PROP_1] [BIGINT] NULL, - [LONG_PROP_2] [BIGINT] NULL, - [DEC_PROP_1] [NUMERIC] (13,4) NULL, - [DEC_PROP_2] [NUMERIC] (13,4) NULL, - [BOOL_PROP_1] [VARCHAR] (1) NULL, - [BOOL_PROP_2] [VARCHAR] (1) NULL, -) ON [PRIMARY] -GO - -CREATE TABLE [dbo].[QRTZ_BLOB_TRIGGERS] ( - [SCHED_NAME] [VARCHAR] (120) NOT NULL , - [TRIGGER_NAME] [VARCHAR] (200) NOT NULL , - [TRIGGER_GROUP] [VARCHAR] (200) NOT NULL , - [BLOB_DATA] [IMAGE] NULL -) ON [PRIMARY] -GO - -CREATE TABLE [dbo].[QRTZ_TRIGGERS] ( - [SCHED_NAME] [VARCHAR] (120) NOT NULL , - [TRIGGER_NAME] [VARCHAR] (200) NOT NULL , - [TRIGGER_GROUP] [VARCHAR] (200) NOT NULL , - [JOB_NAME] [VARCHAR] (200) NOT NULL , - [JOB_GROUP] [VARCHAR] (200) NOT NULL , - [DESCRIPTION] [VARCHAR] (250) NULL , - [NEXT_FIRE_TIME] [BIGINT] NULL , - [PREV_FIRE_TIME] [BIGINT] NULL , - [PRIORITY] [INTEGER] NULL , - [TRIGGER_STATE] [VARCHAR] (16) NOT NULL , - [TRIGGER_TYPE] [VARCHAR] (8) NOT NULL , - [START_TIME] [BIGINT] NOT NULL , - [END_TIME] [BIGINT] NULL , - [CALENDAR_NAME] [VARCHAR] (200) NULL , - [MISFIRE_INSTR] [SMALLINT] NULL , - [JOB_DATA] [IMAGE] NULL -) ON [PRIMARY] -GO - -ALTER TABLE [dbo].[QRTZ_CALENDARS] WITH NOCHECK ADD - CONSTRAINT [PK_QRTZ_CALENDARS] PRIMARY KEY CLUSTERED - ( - [SCHED_NAME], - [CALENDAR_NAME] - ) ON [PRIMARY] -GO - -ALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] WITH NOCHECK ADD - CONSTRAINT [PK_QRTZ_CRON_TRIGGERS] PRIMARY KEY CLUSTERED - ( - [SCHED_NAME], - [TRIGGER_NAME], - [TRIGGER_GROUP] - ) ON [PRIMARY] -GO - -ALTER TABLE [dbo].[QRTZ_FIRED_TRIGGERS] WITH NOCHECK ADD - CONSTRAINT [PK_QRTZ_FIRED_TRIGGERS] PRIMARY KEY CLUSTERED - ( - [SCHED_NAME], - [ENTRY_ID] - ) ON [PRIMARY] -GO - -ALTER TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] WITH NOCHECK ADD - CONSTRAINT [PK_QRTZ_PAUSED_TRIGGER_GRPS] PRIMARY KEY CLUSTERED - ( - [SCHED_NAME], - [TRIGGER_GROUP] - ) ON [PRIMARY] -GO - -ALTER TABLE [dbo].[QRTZ_SCHEDULER_STATE] WITH NOCHECK ADD - CONSTRAINT [PK_QRTZ_SCHEDULER_STATE] PRIMARY KEY CLUSTERED - ( - [SCHED_NAME], - [INSTANCE_NAME] - ) ON [PRIMARY] -GO - -ALTER TABLE [dbo].[QRTZ_LOCKS] WITH NOCHECK ADD - CONSTRAINT [PK_QRTZ_LOCKS] PRIMARY KEY CLUSTERED - ( - [SCHED_NAME], - [LOCK_NAME] - ) ON [PRIMARY] -GO - -ALTER TABLE [dbo].[QRTZ_JOB_DETAILS] WITH NOCHECK ADD - CONSTRAINT [PK_QRTZ_JOB_DETAILS] PRIMARY KEY CLUSTERED - ( - [SCHED_NAME], - [JOB_NAME], - [JOB_GROUP] - ) ON [PRIMARY] -GO - -ALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] WITH NOCHECK ADD - CONSTRAINT [PK_QRTZ_SIMPLE_TRIGGERS] PRIMARY KEY CLUSTERED - ( - [SCHED_NAME], - [TRIGGER_NAME], - [TRIGGER_GROUP] - ) ON [PRIMARY] -GO - -ALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] WITH NOCHECK ADD - CONSTRAINT [PK_QRTZ_SIMPROP_TRIGGERS] PRIMARY KEY CLUSTERED - ( - [SCHED_NAME], - [TRIGGER_NAME], - [TRIGGER_GROUP] - ) ON [PRIMARY] -GO - -ALTER TABLE [dbo].[QRTZ_TRIGGERS] WITH NOCHECK ADD - CONSTRAINT [PK_QRTZ_TRIGGERS] PRIMARY KEY CLUSTERED - ( - [SCHED_NAME], - [TRIGGER_NAME], - [TRIGGER_GROUP] - ) ON [PRIMARY] -GO - -ALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] ADD - CONSTRAINT [FK_QRTZ_CRON_TRIGGERS] FOREIGN KEY - ( - [SCHED_NAME], - [TRIGGER_NAME], - [TRIGGER_GROUP] - ) REFERENCES [dbo].[QRTZ_TRIGGERS] ( - [SCHED_NAME], - [TRIGGER_NAME], - [TRIGGER_GROUP] - ) ON DELETE CASCADE -GO - -ALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] ADD - CONSTRAINT [FK_QRTZ_SIMPLE_TRIGGERS] FOREIGN KEY - ( - [SCHED_NAME], - [TRIGGER_NAME], - [TRIGGER_GROUP] - ) REFERENCES [dbo].[QRTZ_TRIGGERS] ( - [SCHED_NAME], - [TRIGGER_NAME], - [TRIGGER_GROUP] - ) ON DELETE CASCADE -GO - -ALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] ADD - CONSTRAINT [FK_QRTZ_SIMPROP_TRIGGERS] FOREIGN KEY - ( - [SCHED_NAME], - [TRIGGER_NAME], - [TRIGGER_GROUP] - ) REFERENCES [dbo].[QRTZ_TRIGGERS] ( - [SCHED_NAME], - [TRIGGER_NAME], - [TRIGGER_GROUP] - ) ON DELETE CASCADE -GO - -ALTER TABLE [dbo].[QRTZ_TRIGGERS] ADD - CONSTRAINT [FK_QRTZ_TRIGGERS] FOREIGN KEY - ( - [SCHED_NAME], - [JOB_NAME], - [JOB_GROUP] - ) REFERENCES [dbo].[QRTZ_JOB_DETAILS] ( - [SCHED_NAME], - [JOB_NAME], - [JOB_GROUP] - ) -GO - - - -CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY) -GO - -CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP) -GO - - -CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP) -GO - -CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP) -GO - -CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME) -GO - -CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP) -GO - -CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE) -GO - -CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE) -GO - -CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE) -GO - -CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME) -GO - -CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME) -GO - -CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME) -GO - -CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE) -GO - -CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE) -GO - - -CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME) -GO - -CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY) -GO - -CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP) -GO - -CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP) -GO - -CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) -GO - -CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP) -GO \ No newline at end of file diff --git a/platform/platform-resources/src/main/resources/sql/sqlserver/createTables.sql b/platform/platform-resources/src/main/resources/sql/sqlserver/createTables.sql deleted file mode 100644 index 360fdaafdcc..00000000000 --- a/platform/platform-resources/src/main/resources/sql/sqlserver/createTables.sql +++ /dev/null @@ -1,1191 +0,0 @@ -CREATE TABLE configuration ( - tenant_id NUMERIC(19, 0) NOT NULL, - content_type NVARCHAR(50) NOT NULL, - resource_name NVARCHAR(120) NOT NULL, - resource_content VARBINARY(MAX) NOT NULL -) -GO -ALTER TABLE configuration ADD CONSTRAINT pk_configuration PRIMARY KEY (tenant_id, content_type, resource_name) -GO -CREATE INDEX idx_configuration ON configuration (tenant_id, content_type) -GO - -CREATE TABLE contract_data ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - kind NVARCHAR(20) NOT NULL, - scopeId NUMERIC(19, 0) NOT NULL, - name NVARCHAR(50) NOT NULL, - val NVARCHAR(MAX) -) -GO -ALTER TABLE contract_data ADD CONSTRAINT pk_contract_data PRIMARY KEY (tenantid, id, scopeId) -GO -ALTER TABLE contract_data ADD CONSTRAINT uc_cd_scope_name UNIQUE (kind, scopeId, name, tenantid) -GO -CREATE INDEX idx_cd_scope_name ON contract_data (kind, scopeId, name, tenantid) -GO - -CREATE TABLE arch_contract_data ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - kind NVARCHAR(20) NOT NULL, - scopeId NUMERIC(19, 0) NOT NULL, - name NVARCHAR(50) NOT NULL, - val NVARCHAR(MAX), - archiveDate NUMERIC(19, 0) NOT NULL, - sourceObjectId NUMERIC(19, 0) NOT NULL -) -GO -ALTER TABLE arch_contract_data ADD CONSTRAINT pk_arch_contract_data PRIMARY KEY (tenantid, id, scopeId) -GO -ALTER TABLE arch_contract_data ADD CONSTRAINT uc_acd_scope_name UNIQUE (kind, scopeId, name, tenantid) -GO -CREATE INDEX idx_acd_scope_name ON arch_contract_data (kind, scopeId, name, tenantid) -GO - -CREATE TABLE actor ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - scopeId NUMERIC(19, 0) NOT NULL, - name NVARCHAR(50) NOT NULL, - displayName NVARCHAR(75), - description NVARCHAR(MAX), - initiator BIT, - UNIQUE (tenantid, id, scopeId, name), - PRIMARY KEY (tenantid, id) -) -GO - -CREATE TABLE actormember ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - actorId NUMERIC(19, 0) NOT NULL, - userId NUMERIC(19, 0) NOT NULL, - groupId NUMERIC(19, 0) NOT NULL, - roleId NUMERIC(19, 0) NOT NULL, - UNIQUE (tenantid, actorid, userId, groupId, roleId), - PRIMARY KEY (tenantid, id) -) -GO -CREATE TABLE category ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - name NVARCHAR(50) NOT NULL, - creator NUMERIC(19, 0), - description NVARCHAR(MAX), - creationDate NUMERIC(19, 0) NOT NULL, - lastUpdateDate NUMERIC(19, 0) NOT NULL, - UNIQUE (tenantid, name), - PRIMARY KEY (tenantid, id) -) -GO - -CREATE TABLE processcategorymapping ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - categoryid NUMERIC(19, 0) NOT NULL, - processid NUMERIC(19, 0) NOT NULL, - UNIQUE (tenantid, categoryid, processid), - PRIMARY KEY (tenantid, id) -) -GO - -ALTER TABLE processcategorymapping ADD CONSTRAINT fk_catmapping_catid FOREIGN KEY (tenantid, categoryid) REFERENCES category(tenantid, id) ON DELETE CASCADE -GO -CREATE TABLE arch_process_comment( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - userId NUMERIC(19, 0), - processInstanceId NUMERIC(19, 0) NOT NULL, - postDate NUMERIC(19, 0) NOT NULL, - content NVARCHAR(512) NOT NULL, - archiveDate NUMERIC(19, 0) NOT NULL, - sourceObjectId NUMERIC(19, 0) NOT NULL, - PRIMARY KEY (tenantid, id) -) -GO - -CREATE INDEX idx1_arch_process_comment on arch_process_comment (sourceobjectid, tenantid) -GO -CREATE INDEX idx2_arch_process_comment on arch_process_comment (processInstanceId, archivedate, tenantid) -GO -CREATE TABLE process_comment ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - kind NVARCHAR(25) NOT NULL, - userId NUMERIC(19, 0), - processInstanceId NUMERIC(19, 0) NOT NULL, - postDate NUMERIC(19, 0) NOT NULL, - content NVARCHAR(512) NOT NULL, - PRIMARY KEY (tenantid, id) -) -GO -CREATE INDEX idx1_process_comment on process_comment (processInstanceId, tenantid) -GO -CREATE TABLE process_definition ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - processId NUMERIC(19, 0) NOT NULL, - name NVARCHAR(150) NOT NULL, - version NVARCHAR(50) NOT NULL, - description NVARCHAR(255), - deploymentDate NUMERIC(19, 0) NOT NULL, - deployedBy NUMERIC(19, 0) NOT NULL, - activationState NVARCHAR(30) NOT NULL, - configurationState NVARCHAR(30) NOT NULL, - displayName NVARCHAR(75), - displayDescription NVARCHAR(255), - lastUpdateDate NUMERIC(19, 0), - categoryId NUMERIC(19, 0), - iconPath NVARCHAR(255), - content_tenantid NUMERIC(19, 0) NOT NULL, - content_id NUMERIC(19, 0) NOT NULL, - PRIMARY KEY (tenantid, id), - UNIQUE (tenantid, name, version) -) -GO -CREATE TABLE process_content ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - content NVARCHAR(MAX) NOT NULL, - PRIMARY KEY (tenantid, id) -) -GO -CREATE TABLE arch_document_mapping ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - sourceObjectId NUMERIC(19, 0), - processinstanceid NUMERIC(19, 0) NOT NULL, - documentid NUMERIC(19, 0) NOT NULL, - name NVARCHAR(50) NOT NULL, - description NVARCHAR(MAX), - version NVARCHAR(50) NOT NULL, - index_ INT NOT NULL, - archiveDate NUMERIC(19, 0) NOT NULL, - PRIMARY KEY (tenantid, ID) -) -GO -CREATE INDEX idx_a_doc_mp_pr_id ON arch_document_mapping (processinstanceid, tenantid) -GO -CREATE TABLE document ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - author NUMERIC(19, 0), - creationdate NUMERIC(19, 0) NOT NULL, - hascontent BIT NOT NULL, - filename NVARCHAR(255), - mimetype NVARCHAR(255), - url NVARCHAR(1024), - content VARBINARY(MAX), - PRIMARY KEY (tenantid, id) -) -GO -CREATE TABLE document_mapping ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - processinstanceid NUMERIC(19, 0) NOT NULL, - documentid NUMERIC(19, 0) NOT NULL, - name NVARCHAR(50) NOT NULL, - description NVARCHAR(MAX), - version NVARCHAR(50) NOT NULL, - index_ INT NOT NULL, - PRIMARY KEY (tenantid, ID) -) -GO -CREATE TABLE arch_process_instance ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - name NVARCHAR(75) NOT NULL, - processDefinitionId NUMERIC(19, 0) NOT NULL, - description NVARCHAR(255), - startDate NUMERIC(19, 0) NOT NULL, - startedBy NUMERIC(19, 0) NULL, - startedBySubstitute NUMERIC(19, 0) NOT NULL, - endDate NUMERIC(19, 0) NOT NULL, - archiveDate NUMERIC(19, 0) NOT NULL, - stateId INT NOT NULL, - lastUpdate NUMERIC(19, 0) NOT NULL, - rootProcessInstanceId NUMERIC(19, 0), - callerId NUMERIC(19, 0), - sourceObjectId NUMERIC(19, 0) NOT NULL, - stringIndex1 NVARCHAR(255), - stringIndex2 NVARCHAR(255), - stringIndex3 NVARCHAR(255), - stringIndex4 NVARCHAR(255), - stringIndex5 NVARCHAR(255), - PRIMARY KEY (tenantid, id) -) -GO -CREATE INDEX idx1_arch_process_instance ON arch_process_instance (tenantId, sourceObjectId, rootProcessInstanceId, callerId) -GO -CREATE INDEX idx2_arch_process_instance ON arch_process_instance (tenantId, processDefinitionId, archiveDate) -GO -CREATE INDEX idx3_arch_process_instance ON arch_process_instance (tenantId, sourceObjectId, callerId, stateId) -GO - -CREATE TABLE arch_flownode_instance ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - flownodeDefinitionId NUMERIC(19, 0) NOT NULL, - kind NVARCHAR(25) NOT NULL, - sourceObjectId NUMERIC(19, 0), - archiveDate NUMERIC(19, 0) NOT NULL, - rootContainerId NUMERIC(19, 0) NOT NULL, - parentContainerId NUMERIC(19, 0) NOT NULL, - name NVARCHAR(255) NOT NULL, - displayName NVARCHAR(255), - displayDescription NVARCHAR(255), - stateId INT NOT NULL, - stateName NVARCHAR(50), - terminal BIT NOT NULL, - stable BIT , - actorId NUMERIC(19, 0) NULL, - assigneeId NUMERIC(19, 0) DEFAULT 0 NOT NULL, - reachedStateDate NUMERIC(19, 0), - lastUpdateDate NUMERIC(19, 0), - expectedEndDate NUMERIC(19, 0), - claimedDate NUMERIC(19, 0), - priority TINYINT, - gatewayType NVARCHAR(50), - hitBys NVARCHAR(255), - logicalGroup1 NUMERIC(19, 0) NOT NULL, - logicalGroup2 NUMERIC(19, 0) NOT NULL, - logicalGroup3 NUMERIC(19, 0), - logicalGroup4 NUMERIC(19, 0) NOT NULL, - loop_counter INT, - loop_max INT, - loopCardinality INT, - loopDataInputRef NVARCHAR(255), - loopDataOutputRef NVARCHAR(255), - description NVARCHAR(255), - sequential BIT, - dataInputItemRef NVARCHAR(255), - dataOutputItemRef NVARCHAR(255), - nbActiveInst INT, - nbCompletedInst INT, - nbTerminatedInst INT, - executedBy NUMERIC(19, 0), - executedBySubstitute NUMERIC(19, 0), - activityInstanceId NUMERIC(19, 0), - aborting BIT NOT NULL, - triggeredByEvent BIT, - interrupting BIT, - PRIMARY KEY (tenantid, id) -) -GO -CREATE INDEX idx_afi_kind_lg2_executedBy ON arch_flownode_instance(logicalGroup2, tenantId, kind, executedBy) -GO -CREATE INDEX idx_afi_kind_lg3 ON arch_flownode_instance(tenantId, kind, logicalGroup3) -GO -CREATE INDEX idx_afi_kind_lg4 ON arch_flownode_instance(tenantId, logicalGroup4) -GO -CREATE INDEX idx_afi_sourceId_tenantid_kind ON arch_flownode_instance (sourceObjectId, tenantid, kind) -GO -CREATE INDEX idx1_arch_flownode_instance ON arch_flownode_instance (tenantId, rootContainerId, parentContainerId) -GO -CREATE INDEX idx_lg4_lg2 on arch_flownode_instance(tenantid, logicalGroup4, logicalGroup2); -GO - -CREATE TABLE arch_connector_instance ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - containerId NUMERIC(19, 0) NOT NULL, - containerType NVARCHAR(10) NOT NULL, - connectorId NVARCHAR(255) NOT NULL, - version NVARCHAR(50) NOT NULL, - name NVARCHAR(255) NOT NULL, - activationEvent NVARCHAR(30), - state NVARCHAR(50), - sourceObjectId NUMERIC(19, 0), - archiveDate NUMERIC(19, 0) NOT NULL, - PRIMARY KEY (tenantid, id) -) -GO - -CREATE INDEX idx1_arch_connector_instance ON arch_connector_instance (tenantId, containerId, containerType) -GO -CREATE TABLE process_instance ( - id NUMERIC(19, 0) NOT NULL, - name NVARCHAR(75) NOT NULL, - processDefinitionId NUMERIC(19, 0) NOT NULL, - description NVARCHAR(255), - startDate NUMERIC(19, 0) NOT NULL, - startedBy NUMERIC(19, 0) NOT NULL, - startedBySubstitute NUMERIC(19, 0) NOT NULL, - endDate NUMERIC(19, 0) NOT NULL, - stateId INT NOT NULL, - stateCategory NVARCHAR(50) NOT NULL, - lastUpdate NUMERIC(19, 0) NOT NULL, - containerId NUMERIC(19, 0), - rootProcessInstanceId NUMERIC(19, 0), - callerId NUMERIC(19, 0), - callerType NVARCHAR(50), - interruptingEventId NUMERIC(19, 0), - stringIndex1 NVARCHAR(255), - stringIndex2 NVARCHAR(255), - stringIndex3 NVARCHAR(255), - stringIndex4 NVARCHAR(255), - stringIndex5 NVARCHAR(255), - PRIMARY KEY (id) -) -GO - -CREATE INDEX idx1_proc_inst_pdef_state ON process_instance (processdefinitionid, stateid) -GO - -CREATE TABLE flownode_instance ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - flownodeDefinitionId NUMERIC(19, 0) NOT NULL, - kind NVARCHAR(25) NOT NULL, - rootContainerId NUMERIC(19, 0) NOT NULL, - parentContainerId NUMERIC(19, 0) NOT NULL, - name NVARCHAR(255) NOT NULL, - displayName NVARCHAR(255), - displayDescription NVARCHAR(255), - stateId INT NOT NULL, - stateName NVARCHAR(50), - prev_state_id INT NOT NULL, - terminal BIT NOT NULL, - stable BIT , - actorId NUMERIC(19, 0) NULL, - assigneeId NUMERIC(19, 0) DEFAULT 0 NOT NULL, - reachedStateDate NUMERIC(19, 0), - lastUpdateDate NUMERIC(19, 0), - expectedEndDate NUMERIC(19, 0), - claimedDate NUMERIC(19, 0), - priority TINYINT, - gatewayType NVARCHAR(50), - hitBys NVARCHAR(255), - stateCategory NVARCHAR(50) NOT NULL, - logicalGroup1 NUMERIC(19, 0) NOT NULL, - logicalGroup2 NUMERIC(19, 0) NOT NULL, - logicalGroup3 NUMERIC(19, 0), - logicalGroup4 NUMERIC(19, 0) NOT NULL, - loop_counter INT, - loop_max INT, - description NVARCHAR(255), - sequential BIT, - loopDataInputRef NVARCHAR(255), - loopDataOutputRef NVARCHAR(255), - dataInputItemRef NVARCHAR(255), - dataOutputItemRef NVARCHAR(255), - loopCardinality INT, - nbActiveInst INT, - nbCompletedInst INT, - nbTerminatedInst INT, - executedBy NUMERIC(19, 0), - executedBySubstitute NUMERIC(19, 0), - activityInstanceId NUMERIC(19, 0), - state_executing BIT DEFAULT 0, - abortedByBoundary NUMERIC(19, 0), - triggeredByEvent BIT, - interrupting BIT, - tokenCount INT NOT NULL, - PRIMARY KEY (tenantid, id) -) -GO -CREATE INDEX idx_fni_rootcontid ON flownode_instance (rootContainerId) -GO -CREATE INDEX idx_fni_loggroup4 ON flownode_instance (logicalGroup4) -GO -CREATE INDEX idx_fni_loggroup3_terminal ON flownode_instance(logicalgroup3, terminal, tenantid) -GO -CREATE INDEX idx_fn_lg2_state_tenant_del ON flownode_instance (logicalGroup2, stateName, tenantid) -GO -CREATE INDEX idx_fni_activity_instance_id_kind ON flownode_instance(activityInstanceId, kind, tenantid) -GO - -CREATE TABLE connector_instance ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - containerId NUMERIC(19, 0) NOT NULL, - containerType NVARCHAR(10) NOT NULL, - connectorId NVARCHAR(255) NOT NULL, - version NVARCHAR(50) NOT NULL, - name NVARCHAR(255) NOT NULL, - activationEvent NVARCHAR(30), - state NVARCHAR(50), - executionOrder INT, - exceptionMessage NVARCHAR(255), - stackTrace NVARCHAR(MAX), - PRIMARY KEY (tenantid, id) -) -GO -CREATE INDEX idx_ci_container_activation ON connector_instance (tenantid, containerId, containerType, activationEvent) -GO - -CREATE TABLE event_trigger_instance ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - eventInstanceId NUMERIC(19, 0) NOT NULL, - eventInstanceName NVARCHAR(50), - executionDate NUMERIC(19, 0), - jobTriggerName NVARCHAR(255), - PRIMARY KEY (tenantid, id) -) -GO - -CREATE TABLE waiting_event ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - kind NVARCHAR(15) NOT NULL, - eventType NVARCHAR(50), - messageName NVARCHAR(255), - signalName NVARCHAR(255), - errorCode NVARCHAR(255), - processName NVARCHAR(150), - flowNodeName NVARCHAR(50), - flowNodeDefinitionId NUMERIC(19, 0), - subProcessId NUMERIC(19, 0), - processDefinitionId NUMERIC(19, 0), - rootProcessInstanceId NUMERIC(19, 0), - parentProcessInstanceId NUMERIC(19, 0), - flowNodeInstanceId NUMERIC(19, 0), - relatedActivityInstanceId NUMERIC(19, 0), - locked BIT, - active BIT, - progress TINYINT, - correlation1 NVARCHAR(128), - correlation2 NVARCHAR(128), - correlation3 NVARCHAR(128), - correlation4 NVARCHAR(128), - correlation5 NVARCHAR(128), - PRIMARY KEY (tenantid, id) -) -GO -CREATE INDEX idx_waiting_event ON waiting_event (progress, tenantid, kind, locked, active) -GO -CREATE INDEX idx_waiting_event_correl ON waiting_event (correlation1, correlation2, correlation3, correlation4, correlation5) -GO - -CREATE TABLE message_instance ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - messageName NVARCHAR(255) NOT NULL, - targetProcess NVARCHAR(255) NOT NULL, - targetFlowNode NVARCHAR(255) NULL, - locked BIT NOT NULL, - handled BIT NOT NULL, - processDefinitionId NUMERIC(19, 0) NOT NULL, - flowNodeName NVARCHAR(255), - correlation1 NVARCHAR(128), - correlation2 NVARCHAR(128), - correlation3 NVARCHAR(128), - correlation4 NVARCHAR(128), - correlation5 NVARCHAR(128), - creationDate NUMERIC(19, 0) NOT NULL, - PRIMARY KEY (tenantid, id) -) -GO -CREATE INDEX idx_message_instance ON message_instance (messageName, targetProcess, correlation1, correlation2, correlation3) -GO -CREATE INDEX idx_message_instance_correl ON message_instance (correlation1, correlation2, correlation3, correlation4, correlation5) -GO - -CREATE TABLE pending_mapping ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - activityId NUMERIC(19, 0) NOT NULL, - actorId NUMERIC(19, 0), - userId NUMERIC(19, 0), - PRIMARY KEY (tenantid, id) -) -GO -CREATE UNIQUE INDEX idx_UQ_pending_mapping ON pending_mapping (tenantid, activityId, userId, actorId) -GO - -CREATE TABLE ref_biz_data_inst ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - kind NVARCHAR(15) NOT NULL, - name NVARCHAR(255) NOT NULL, - proc_inst_id NUMERIC(19, 0), - fn_inst_id NUMERIC(19, 0), - data_id NUMERIC(19, 0), - data_classname NVARCHAR(255) NOT NULL -) -GO - -CREATE INDEX idx_biz_data_inst1 ON ref_biz_data_inst (tenantid, proc_inst_id) -GO -CREATE INDEX idx_biz_data_inst2 ON ref_biz_data_inst (tenantid, fn_inst_id) -GO -CREATE INDEX idx_biz_data_inst3 ON ref_biz_data_inst (proc_inst_id) -GO -ALTER TABLE ref_biz_data_inst ADD CONSTRAINT pk_ref_biz_data PRIMARY KEY (tenantid, id) -GO -ALTER TABLE ref_biz_data_inst ADD CONSTRAINT fk_ref_biz_data_proc FOREIGN KEY (proc_inst_id) REFERENCES process_instance(id) ON DELETE CASCADE -GO -ALTER TABLE ref_biz_data_inst ADD CONSTRAINT fk_ref_biz_data_fn FOREIGN KEY (tenantid, fn_inst_id) REFERENCES flownode_instance(tenantid, id) ON DELETE CASCADE -GO - -CREATE TABLE multi_biz_data ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - idx NUMERIC(19, 0) NOT NULL, - data_id NUMERIC(19, 0) NOT NULL, - PRIMARY KEY (tenantid, id, data_id) -) -GO - -ALTER TABLE multi_biz_data ADD CONSTRAINT fk_rbdi_mbd FOREIGN KEY (tenantid, id) REFERENCES ref_biz_data_inst(tenantid, id) ON DELETE CASCADE -GO - -CREATE TABLE arch_ref_biz_data_inst ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - kind NVARCHAR(15) NOT NULL, - name NVARCHAR(255) NOT NULL, - orig_proc_inst_id NUMERIC(19, 0), - orig_fn_inst_id NUMERIC(19, 0), - data_id NUMERIC(19, 0), - data_classname NVARCHAR(255) NOT NULL -) -GO -CREATE INDEX idx_arch_biz_data_inst1 ON arch_ref_biz_data_inst (tenantid, orig_proc_inst_id) -GO -CREATE INDEX idx_arch_biz_data_inst2 ON arch_ref_biz_data_inst (tenantid, orig_fn_inst_id) -GO -ALTER TABLE arch_ref_biz_data_inst ADD CONSTRAINT pk_arch_ref_biz_data_inst PRIMARY KEY (tenantid, id) -GO - -CREATE TABLE arch_multi_biz_data ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - idx NUMERIC(19, 0) NOT NULL, - data_id NUMERIC(19, 0) NOT NULL -) -GO -ALTER TABLE arch_multi_biz_data ADD CONSTRAINT pk_arch_rbdi_mbd PRIMARY KEY (tenantid, id, data_id) -GO -ALTER TABLE arch_multi_biz_data ADD CONSTRAINT fk_arch_rbdi_mbd FOREIGN KEY (tenantid, id) REFERENCES arch_ref_biz_data_inst(tenantid, id) ON DELETE CASCADE -GO - -CREATE TABLE processsupervisor ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - processDefId NUMERIC(19, 0) NOT NULL, - userId NUMERIC(19, 0) NOT NULL, - groupId NUMERIC(19, 0) NOT NULL, - roleId NUMERIC(19, 0) NOT NULL, - UNIQUE (tenantid, processDefId, userId, groupId, roleId), - PRIMARY KEY (tenantid, id) -) -GO - -CREATE TABLE business_app ( - tenantId NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - token NVARCHAR(50) NOT NULL, - version NVARCHAR(50) NOT NULL, - description NVARCHAR(MAX), - iconPath NVARCHAR(255), - creationDate NUMERIC(19, 0) NOT NULL, - createdBy NUMERIC(19, 0) NOT NULL, - lastUpdateDate NUMERIC(19, 0) NOT NULL, - updatedBy NUMERIC(19, 0) NOT NULL, - state NVARCHAR(30) NOT NULL, - homePageId NUMERIC(19, 0), - profileId NUMERIC(19, 0), - layoutId NUMERIC(19, 0), - themeId NUMERIC(19, 0), - iconMimeType NVARCHAR(255), - iconContent VARBINARY(MAX), - displayName NVARCHAR(255) NOT NULL, - editable BIT, - internalProfile NVARCHAR(255) -) -GO - -ALTER TABLE business_app ADD CONSTRAINT pk_business_app PRIMARY KEY (tenantid, id) -GO -ALTER TABLE business_app ADD CONSTRAINT uk_app_token_version UNIQUE (tenantId, token, version) -GO - -CREATE INDEX idx_app_token ON business_app (token, tenantid) -GO -CREATE INDEX idx_app_profile ON business_app (profileId, tenantid) -GO -CREATE INDEX idx_app_homepage ON business_app (homePageId, tenantid) -GO - -CREATE TABLE business_app_page ( - tenantId NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - applicationId NUMERIC(19, 0) NOT NULL, - pageId NUMERIC(19, 0) NOT NULL, - token NVARCHAR(255) NOT NULL -) -GO - -ALTER TABLE business_app_page ADD CONSTRAINT pk_business_app_page PRIMARY KEY (tenantid, id) -GO -ALTER TABLE business_app_page ADD CONSTRAINT uk_app_page_appId_token UNIQUE (tenantId, applicationId, token) -GO - -CREATE INDEX idx_app_page_token ON business_app_page (applicationId, token, tenantid) -GO -CREATE INDEX idx_app_page_pageId ON business_app_page (pageId, tenantid) -GO - -CREATE TABLE business_app_menu ( - tenantId NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - displayName NVARCHAR(255) NOT NULL, - applicationId NUMERIC(19, 0) NOT NULL, - applicationPageId NUMERIC(19, 0), - parentId NUMERIC(19, 0), - index_ NUMERIC(19, 0) -) -GO - -ALTER TABLE business_app_menu ADD CONSTRAINT pk_business_app_menu PRIMARY KEY (tenantid, id) -GO - -CREATE INDEX idx_app_menu_app ON business_app_menu (applicationId, tenantid) -GO -CREATE INDEX idx_app_menu_page ON business_app_menu (applicationPageId, tenantid) -GO -CREATE INDEX idx_app_menu_parent ON business_app_menu (parentId, tenantid) -GO - -CREATE TABLE command ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - name NVARCHAR(50) NOT NULL, - description NVARCHAR(MAX), - IMPLEMENTATION NVARCHAR(100) NOT NULL, - isSystem BIT, - UNIQUE (tenantid, name), - PRIMARY KEY (tenantid, id) -) -GO -CREATE TABLE arch_data_instance ( - tenantId NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - name NVARCHAR(50), - description NVARCHAR(50), - transientData BIT, - className NVARCHAR(100), - containerId NUMERIC(19, 0), - containerType NVARCHAR(60), - namespace NVARCHAR(100), - element NVARCHAR(60), - intValue INT, - longValue NUMERIC(19, 0), - shortTextValue NVARCHAR(255), - booleanValue BIT, - doubleValue NUMERIC(19,5), - floatValue REAL, - blobValue VARBINARY(MAX), - clobValue NVARCHAR(MAX), - discriminant NVARCHAR(50) NOT NULL, - archiveDate NUMERIC(19, 0) NOT NULL, - sourceObjectId NUMERIC(19, 0) NOT NULL, - PRIMARY KEY (tenantid, id) -) -GO - -CREATE INDEX idx1_arch_data_instance ON arch_data_instance (tenantId, containerId, containerType, archiveDate, name, sourceObjectId) -GO -CREATE INDEX idx2_arch_data_instance ON arch_data_instance (sourceObjectId, containerId, archiveDate, id, tenantId) -GO - -CREATE TABLE data_instance ( - tenantId NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - name NVARCHAR(50), - description NVARCHAR(50), - transientData BIT, - className NVARCHAR(100), - containerId NUMERIC(19, 0), - containerType NVARCHAR(60), - namespace NVARCHAR(100), - element NVARCHAR(60), - intValue INT, - longValue NUMERIC(19, 0), - shortTextValue NVARCHAR(255), - booleanValue BIT, - doubleValue NUMERIC(19,5), - floatValue REAL, - blobValue VARBINARY(MAX), - clobValue NVARCHAR(MAX), - discriminant NVARCHAR(50) NOT NULL, - PRIMARY KEY (tenantid, id) -) -GO -CREATE INDEX idx_datai_container ON data_instance (tenantId, containerId, containerType, name) -GO - -CREATE TABLE dependency ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - name NVARCHAR(150) NOT NULL, - description NVARCHAR(MAX), - filename NVARCHAR(255) NOT NULL, - value_ VARBINARY(MAX) NOT NULL, - UNIQUE (tenantId, name), - PRIMARY KEY (tenantid, id) -) -GO -CREATE INDEX idx_dependency_name ON dependency (name, id) -GO - -CREATE TABLE dependencymapping ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - artifactid NUMERIC(19, 0) NOT NULL, - artifacttype NVARCHAR(50) NOT NULL, - dependencyid NUMERIC(19, 0) NOT NULL, - UNIQUE (tenantid, dependencyid, artifactid, artifacttype), - PRIMARY KEY (tenantid, id) -) -GO -CREATE INDEX idx_dependencymapping_depid ON dependencymapping (dependencyid, id) -GO -ALTER TABLE dependencymapping ADD CONSTRAINT fk_depmapping_depid FOREIGN KEY (tenantid, dependencyid) REFERENCES dependency(tenantid, id) ON DELETE CASCADE -GO -CREATE TABLE pdependency ( - id NUMERIC(19, 0) NOT NULL, - name NVARCHAR(50) NOT NULL UNIQUE, - description NVARCHAR(MAX), - filename NVARCHAR(255) NOT NULL, - value_ VARBINARY(MAX) NOT NULL, - PRIMARY KEY (id) -) -GO -CREATE INDEX idx_pdependency_name ON pdependency (name, id) -GO - -CREATE TABLE pdependencymapping ( - id NUMERIC(19, 0) NOT NULL, - artifactid NUMERIC(19, 0) NOT NULL, - artifacttype NVARCHAR(50) NOT NULL, - dependencyid NUMERIC(19, 0) NOT NULL, - UNIQUE (dependencyid, artifactid, artifacttype), - PRIMARY KEY (id) -) -GO -CREATE INDEX idx_pdependencymapping_depid ON pdependencymapping (dependencyid, id) -GO -ALTER TABLE pdependencymapping ADD CONSTRAINT fk_pdepmapping_depid FOREIGN KEY (dependencyid) REFERENCES pdependency(id) ON DELETE CASCADE -GO -CREATE TABLE external_identity_mapping ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - kind NVARCHAR(25) NOT NULL, - externalId NVARCHAR(50) NOT NULL, - userId NUMERIC(19, 0) NOT NULL, - groupId NUMERIC(19, 0) NOT NULL, - roleId NUMERIC(19, 0) NOT NULL, - UNIQUE (tenantid, kind, externalId, userId, groupId, roleId), - PRIMARY KEY (tenantid, id) -) -GO -CREATE TABLE group_ ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - name NVARCHAR(125) NOT NULL, - parentPath NVARCHAR(255), - displayName NVARCHAR(255), - description NVARCHAR(MAX), - createdBy NUMERIC(19, 0), - creationDate NUMERIC(19, 0), - lastUpdate NUMERIC(19, 0), - iconid NUMERIC(19, 0), - PRIMARY KEY (tenantid, id) -) -GO -CREATE INDEX idx_group_name ON group_ (tenantid, parentPath, name); -GO -CREATE TABLE role ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - name NVARCHAR(255) NOT NULL, - displayName NVARCHAR(255), - description NVARCHAR(MAX), - createdBy NUMERIC(19, 0), - creationDate NUMERIC(19, 0), - lastUpdate NUMERIC(19, 0), - iconid NUMERIC(19, 0), - UNIQUE (tenantid, name), - PRIMARY KEY (tenantid, id) -) -GO - -CREATE INDEX idx_role_name ON role (tenantid, name) -GO - -CREATE TABLE user_ ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - enabled BIT NOT NULL, - userName NVARCHAR(255) NOT NULL, - password NVARCHAR(60), - firstName NVARCHAR(255), - lastName NVARCHAR(255), - title NVARCHAR(50), - jobTitle NVARCHAR(255), - managerUserId NUMERIC(19, 0), - createdBy NUMERIC(19, 0), - creationDate NUMERIC(19, 0), - lastUpdate NUMERIC(19, 0), - iconid NUMERIC(19, 0), - UNIQUE (tenantid, userName), - PRIMARY KEY (tenantid, id) -) -GO - -CREATE INDEX idx_user_name ON user_ (tenantid, userName) -GO - -CREATE TABLE user_login ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - lastConnection NUMERIC(19, 0), - PRIMARY KEY (tenantid, id) -) -GO - -CREATE TABLE user_contactinfo ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - userId NUMERIC(19, 0) NOT NULL, - email NVARCHAR(255), - phone NVARCHAR(50), - mobile NVARCHAR(50), - fax NVARCHAR(50), - building NVARCHAR(50), - room NVARCHAR(50), - address NVARCHAR(255), - zipCode NVARCHAR(50), - city NVARCHAR(255), - state NVARCHAR(255), - country NVARCHAR(255), - website NVARCHAR(255), - personal BIT NOT NULL, - UNIQUE (tenantid, userId, personal), - PRIMARY KEY (tenantid, id) -) -GO -ALTER TABLE user_contactinfo ADD CONSTRAINT fk_contact_user FOREIGN KEY (tenantid, userId) REFERENCES user_ (tenantid, id) ON DELETE CASCADE -GO -CREATE INDEX idx_user_contactinfo ON user_contactinfo (userId, tenantid, personal) -GO - - -CREATE TABLE custom_usr_inf_def ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - name NVARCHAR(75) NOT NULL, - description NVARCHAR(MAX), - UNIQUE (tenantid, name), - PRIMARY KEY (tenantid, id) -) -GO - -CREATE INDEX idx_custom_usr_inf_def_name ON custom_usr_inf_def (tenantid, name) -GO - -CREATE TABLE custom_usr_inf_val ( - id NUMERIC(19, 0) NOT NULL, - tenantid NUMERIC(19, 0) NOT NULL, - definitionId NUMERIC(19, 0) NOT NULL, - userId NUMERIC(19, 0) NOT NULL, - value NVARCHAR(255), - UNIQUE (tenantid, definitionId, userId), - PRIMARY KEY (tenantid, id) -) -GO -ALTER TABLE custom_usr_inf_val ADD CONSTRAINT fk_user_id FOREIGN KEY (tenantid, userId) REFERENCES user_ (tenantid, id) ON DELETE CASCADE -GO -ALTER TABLE custom_usr_inf_val ADD CONSTRAINT fk_definition_id FOREIGN KEY (tenantid, definitionId) REFERENCES custom_usr_inf_def (tenantid, id) ON DELETE CASCADE -GO - -CREATE TABLE user_membership ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - userId NUMERIC(19, 0) NOT NULL, - roleId NUMERIC(19, 0) NOT NULL, - groupId NUMERIC(19, 0) NOT NULL, - assignedBy NUMERIC(19, 0), - assignedDate NUMERIC(19, 0), - UNIQUE (tenantid, userId, roleId, groupId), - PRIMARY KEY (tenantid, id) -) -GO -CREATE TABLE queriable_log ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - log_timestamp NUMERIC(19, 0) NOT NULL, - whatYear SMALLINT NOT NULL, - whatMonth TINYINT NOT NULL, - dayOfYear SMALLINT NOT NULL, - weekOfYear TINYINT NOT NULL, - userId NVARCHAR(255) NOT NULL, - threadNumber NUMERIC(19, 0) NOT NULL, - clusterNode NVARCHAR(50), - productVersion NVARCHAR(50) NOT NULL, - severity NVARCHAR(50) NOT NULL, - actionType NVARCHAR(50) NOT NULL, - actionScope NVARCHAR(100), - actionStatus TINYINT NOT NULL, - rawMessage NVARCHAR(255) NOT NULL, - callerClassName NVARCHAR(200), - callerMethodName NVARCHAR(80), - numericIndex1 NUMERIC(19, 0), - numericIndex2 NUMERIC(19, 0), - numericIndex3 NUMERIC(19, 0), - numericIndex4 NUMERIC(19, 0), - numericIndex5 NUMERIC(19, 0), - PRIMARY KEY (tenantid, id) -) -GO - -CREATE TABLE queriablelog_p ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - queriableLogId NUMERIC(19, 0) NOT NULL, - name NVARCHAR(50) NOT NULL, - stringValue NVARCHAR(255), - blobId NUMERIC(19, 0), - valueType NVARCHAR(30), - PRIMARY KEY (tenantid, id) -) -GO - -CREATE INDEX idx_queriablelog ON queriablelog_p (queriableLogId, id) -GO -ALTER TABLE queriablelog_p ADD CONSTRAINT fk_queriableLogId FOREIGN KEY (tenantid, queriableLogId) REFERENCES queriable_log(tenantid, id) -GO -CREATE TABLE page ( - tenantId NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - name NVARCHAR(255) NOT NULL, - displayName NVARCHAR(255) NOT NULL, - description NVARCHAR(MAX), - installationDate NUMERIC(19, 0) NOT NULL, - installedBy NUMERIC(19, 0) NOT NULL, - provided BIT, - editable BIT, - removable BIT, - lastModificationDate NUMERIC(19, 0) NOT NULL, - lastUpdatedBy NUMERIC(19, 0) NOT NULL, - contentName NVARCHAR(280) NOT NULL, - content VARBINARY(MAX), - contentType NVARCHAR(50) NOT NULL, - processDefinitionId NUMERIC(19,0) NOT NULL, - pageHash NVARCHAR(32) -) -GO - -ALTER TABLE page ADD CONSTRAINT pk_page PRIMARY KEY (tenantid, id) -GO - -ALTER TABLE page ADD CONSTRAINT uk_page UNIQUE (tenantId, name, processDefinitionId) -GO - -CREATE TABLE sequence ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - nextid NUMERIC(19, 0) NOT NULL, - PRIMARY KEY (tenantid, id) -) -GO -CREATE TABLE blob_ ( - tenantId NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - blobValue VARBINARY(MAX), - PRIMARY KEY (tenantid, id) -) -GO - -CREATE TABLE platform ( - id NUMERIC(19, 0) NOT NULL, - version NVARCHAR(50) NOT NULL, - initial_bonita_version NVARCHAR(50) NOT NULL, - application_version NVARCHAR(50) NOT NULL, - maintenance_message NVARCHAR(MAX), - maintenance_message_active BIT NOT NULL, - created NUMERIC(19, 0) NOT NULL, - created_by NVARCHAR(50) NOT NULL, - information NVARCHAR(MAX), - PRIMARY KEY (id) -) -GO - -CREATE TABLE tenant ( - id NUMERIC(19, 0) NOT NULL, - created NUMERIC(19, 0) NOT NULL, - createdBy NVARCHAR(50) NOT NULL, - description NVARCHAR(255), - defaultTenant BIT NOT NULL, - iconname NVARCHAR(50), - iconpath NVARCHAR(255), - name NVARCHAR(50) NOT NULL, - status NVARCHAR(15) NOT NULL, - PRIMARY KEY (id) -) -GO -CREATE TABLE platformCommand ( - id NUMERIC(19, 0) PRIMARY KEY, - name NVARCHAR(50) NOT NULL UNIQUE, - description NVARCHAR(MAX), - IMPLEMENTATION NVARCHAR(100) NOT NULL -) -GO -CREATE TABLE profile ( - tenantId NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - isDefault BIT NOT NULL, - name NVARCHAR(50) NOT NULL, - description NVARCHAR(MAX), - creationDate NUMERIC(19, 0) NOT NULL, - createdBy NUMERIC(19, 0) NOT NULL, - lastUpdateDate NUMERIC(19, 0) NOT NULL, - lastUpdatedBy NUMERIC(19, 0) NOT NULL, - UNIQUE (tenantId, name), - PRIMARY KEY (tenantId, id) -) -GO - -CREATE TABLE profilemember ( - tenantId NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - profileId NUMERIC(19, 0) NOT NULL, - userId NUMERIC(19, 0) NOT NULL, - groupId NUMERIC(19, 0) NOT NULL, - roleId NUMERIC(19, 0) NOT NULL, - UNIQUE (tenantId, profileId, userId, groupId, roleId), - PRIMARY KEY (tenantId, id) -) -GO -CREATE TABLE job_desc ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - jobclassname NVARCHAR(100) NOT NULL, - jobname NVARCHAR(100) NOT NULL, - description NVARCHAR(50), - PRIMARY KEY (tenantid, id) -) -GO - -CREATE TABLE job_param ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - jobDescriptorId NUMERIC(19, 0) NOT NULL, - key_ NVARCHAR(50) NOT NULL, - value_ VARBINARY(MAX) NOT NULL, - PRIMARY KEY (tenantid, id) -) -GO -CREATE INDEX idx_job_param_tenant_jobid ON job_param (tenantid, jobDescriptorId) -GO - - -CREATE TABLE job_log ( - tenantid NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - jobDescriptorId NUMERIC(19, 0) NOT NULL, - retryNumber NUMERIC(19, 0), - lastUpdateDate NUMERIC(19, 0), - lastMessage NVARCHAR(MAX), - UNIQUE (tenantId, jobDescriptorId), - PRIMARY KEY (tenantid, id) -) -GO - -ALTER TABLE job_param ADD CONSTRAINT fk_job_param_jobid FOREIGN KEY (tenantid, jobDescriptorId) REFERENCES job_desc(tenantid, id) ON DELETE CASCADE -GO -ALTER TABLE job_log ADD CONSTRAINT fk_job_log_jobid FOREIGN KEY (tenantid, jobDescriptorId) REFERENCES job_desc(tenantid, id) ON DELETE CASCADE -GO -CREATE TABLE form_mapping ( - tenantId NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - process NUMERIC(19, 0) NOT NULL, - type INT NOT NULL, - task NVARCHAR(255), - page_mapping_tenant_id NUMERIC(19, 0), - page_mapping_id NUMERIC(19, 0), - lastUpdateDate NUMERIC(19, 0), - lastUpdatedBy NUMERIC(19, 0), - target NVARCHAR(16) NOT NULL, - PRIMARY KEY (tenantId, id) -) -GO -CREATE TABLE page_mapping ( - tenantId NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - key_ NVARCHAR(255) NOT NULL, - pageId NUMERIC(19, 0) NULL, - url NVARCHAR(1024) NULL, - urladapter NVARCHAR(255) NULL, - page_authoriz_rules NVARCHAR(MAX) NULL, - lastUpdateDate NUMERIC(19, 0) NULL, - lastUpdatedBy NUMERIC(19, 0) NULL, - CONSTRAINT UK_page_mapping UNIQUE (tenantId, key_), - PRIMARY KEY (tenantId, id) -) -GO -ALTER TABLE form_mapping ADD CONSTRAINT fk_form_mapping_key FOREIGN KEY (page_mapping_tenant_id, page_mapping_id) REFERENCES page_mapping(tenantId, id) -GO -CREATE TABLE proc_parameter ( - tenantId NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - process_id NUMERIC(19, 0) NOT NULL, - name NVARCHAR(255) NOT NULL, - value NVARCHAR(MAX) NULL, - PRIMARY KEY (tenantId, id) -) -GO -CREATE TABLE bar_resource ( - tenantId NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - process_id NUMERIC(19, 0) NOT NULL, - name NVARCHAR(255) NOT NULL, - type NVARCHAR(16) NOT NULL, - content VARBINARY(MAX) NOT NULL, - UNIQUE (tenantId, process_id, name, type), - PRIMARY KEY (tenantId, id) -) -GO -CREATE INDEX idx_bar_resource ON bar_resource (tenantId, process_id, type, name) -GO -CREATE TABLE temporary_content ( - id NUMERIC(19, 0) NOT NULL, - creationDate NUMERIC(19, 0) NOT NULL, - key_ NVARCHAR(255) NOT NULL, - fileName NVARCHAR(255) NOT NULL, - mimeType NVARCHAR(255) NOT NULL, - content VARBINARY(MAX) NOT NULL, - UNIQUE (key_), - PRIMARY KEY (id) -); -GO -CREATE INDEX idx_temporary_content ON temporary_content (key_); -GO -CREATE TABLE tenant_resource ( - tenantId NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - name NVARCHAR(255) NOT NULL, - type NVARCHAR(16) NOT NULL, - content VARBINARY(MAX) NOT NULL, - lastUpdatedBy NUMERIC(19, 0) NOT NULL, - lastUpdateDate NUMERIC(19, 0), - state NVARCHAR(50) NOT NULL, - CONSTRAINT UK_tenant_resource UNIQUE (tenantId, name, type), - PRIMARY KEY (tenantId, id) -) -GO -CREATE INDEX idx_tenant_resource ON tenant_resource (tenantId, type, name) -GO -CREATE TABLE icon ( - tenantId NUMERIC(19, 0) NOT NULL, - id NUMERIC(19, 0) NOT NULL, - mimetype NVARCHAR(255) NOT NULL, - content VARBINARY(MAX) NOT NULL, - CONSTRAINT pk_icon PRIMARY KEY (tenantId, id) -) -GO diff --git a/platform/platform-resources/src/main/resources/sql/sqlserver/dropQuartzTables.sql b/platform/platform-resources/src/main/resources/sql/sqlserver/dropQuartzTables.sql deleted file mode 100644 index 50d7262cb3a..00000000000 --- a/platform/platform-resources/src/main/resources/sql/sqlserver/dropQuartzTables.sql +++ /dev/null @@ -1,59 +0,0 @@ -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1) -ALTER TABLE [dbo].[QRTZ_TRIGGERS] DROP CONSTRAINT FK_QRTZ_TRIGGERS -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_CRON_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1) -ALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] DROP CONSTRAINT FK_QRTZ_CRON_TRIGGERS -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_SIMPLE_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1) -ALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] DROP CONSTRAINT FK_QRTZ_SIMPLE_TRIGGERS -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_SIMPROP_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1) -ALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] DROP CONSTRAINT FK_QRTZ_SIMPROP_TRIGGERS -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_CALENDARS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_CALENDARS] -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_CRON_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_CRON_TRIGGERS] -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_BLOB_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_BLOB_TRIGGERS] -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_FIRED_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_FIRED_TRIGGERS] -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_PAUSED_TRIGGER_GRPS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_SCHEDULER_STATE]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_SCHEDULER_STATE] -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_LOCKS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_LOCKS] -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_JOB_DETAILS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_JOB_DETAILS] -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_SIMPLE_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_SIMPROP_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] -GO - -IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1) -DROP TABLE [dbo].[QRTZ_TRIGGERS] -GO diff --git a/platform/platform-resources/src/main/resources/sql/sqlserver/dropTables.sql b/platform/platform-resources/src/main/resources/sql/sqlserver/dropTables.sql deleted file mode 100644 index 27b19a8bbe3..00000000000 --- a/platform/platform-resources/src/main/resources/sql/sqlserver/dropTables.sql +++ /dev/null @@ -1,136 +0,0 @@ -DROP TABLE configuration -GO -DROP TABLE arch_contract_data -GO -DROP TABLE contract_data -GO -DROP TABLE actormember -GO -DROP TABLE actor -GO -DROP TABLE processcategorymapping -GO -DROP TABLE category -GO -DROP TABLE arch_process_comment -GO -DROP TABLE process_comment -GO -DROP TABLE process_definition -GO -DROP TABLE arch_document_mapping -GO -DROP TABLE document_mapping -GO -DROP TABLE document -GO -DROP TABLE arch_flownode_instance -GO -DROP TABLE arch_process_instance -GO -DROP TABLE arch_connector_instance -GO -DROP TABLE arch_multi_biz_data -GO -DROP TABLE arch_ref_biz_data_inst -GO -DROP TABLE multi_biz_data -GO -DROP TABLE ref_biz_data_inst -GO -DROP TABLE pending_mapping -GO -DROP TABLE connector_instance -GO -DROP TABLE flownode_instance -GO -DROP TABLE process_instance -GO -DROP TABLE event_trigger_instance -GO -DROP TABLE waiting_event -GO -DROP TABLE message_instance -GO -DROP TABLE processsupervisor -GO -DROP TABLE business_app_menu -GO -DROP TABLE business_app_page -GO -DROP TABLE business_app -GO -DROP TABLE command -GO -DROP TABLE arch_data_instance -GO -DROP TABLE data_instance -GO -DROP TABLE dependencymapping -GO -DROP TABLE dependency -GO -DROP TABLE pdependencymapping -GO -DROP TABLE pdependency -GO -DROP TABLE external_identity_mapping -GO -DROP TABLE user_membership -GO -DROP TABLE custom_usr_inf_val -GO -DROP TABLE custom_usr_inf_def -GO -DROP TABLE user_contactinfo -GO -DROP TABLE user_login -GO -DROP TABLE user_ -GO -DROP TABLE role -GO -DROP TABLE group_ -GO -DROP TABLE queriablelog_p -GO -DROP TABLE queriable_log -GO -DROP TABLE page -GO -DROP TABLE blob_ -GO -DROP TABLE profilemember -GO -DROP TABLE profile -GO -DROP TABLE job_log -GO -DROP TABLE job_param -GO -DROP TABLE job_desc -GO -DROP TABLE sequence -GO -DROP TABLE tenant -GO -DROP TABLE platform -GO -DROP TABLE platformCommand -GO -DROP TABLE form_mapping -GO -DROP TABLE page_mapping -GO -DROP TABLE process_content -GO -DROP TABLE proc_parameter -GO -DROP TABLE bar_resource -GO -DROP TABLE temporary_content -GO -DROP TABLE tenant_resource -GO -DROP TABLE icon -GO \ No newline at end of file diff --git a/platform/platform-resources/src/main/resources/sql/sqlserver/initTables.sql b/platform/platform-resources/src/main/resources/sql/sqlserver/initTables.sql deleted file mode 100644 index 531cc76337a..00000000000 --- a/platform/platform-resources/src/main/resources/sql/sqlserver/initTables.sql +++ /dev/null @@ -1,131 +0,0 @@ -INSERT INTO sequence VALUES (-1, 1, 1) -GO -INSERT INTO sequence VALUES (-1, 2, 1) -GO -INSERT INTO sequence VALUES (-1, 3, 1) -GO -INSERT INTO sequence VALUES (-1, 4, 1) -GO -INSERT INTO sequence VALUES (-1, 5, 1) -GO -INSERT INTO sequence VALUES(1, 10, 1) - GO -INSERT INTO sequence VALUES(1, 11, 1) - GO -INSERT INTO sequence VALUES(1, 20, 1) - GO -INSERT INTO sequence VALUES(1, 21, 1) - GO -INSERT INTO sequence VALUES(1, 22, 1) - GO -INSERT INTO sequence VALUES(1, 23, 1) - GO -INSERT INTO sequence VALUES(1, 24, 1) - GO -INSERT INTO sequence VALUES(1, 25, 1) - GO -INSERT INTO sequence VALUES(1, 26, 1) - GO -INSERT INTO sequence VALUES(1, 27, 1) - GO -INSERT INTO sequence VALUES(1, 30, 1) - GO -INSERT INTO sequence VALUES(1, 31, 1) - GO -INSERT INTO sequence VALUES(1, 70, 1) - GO -INSERT INTO sequence VALUES(1, 71, 1) - GO -INSERT INTO sequence VALUES(1, 72, 1) - GO -INSERT INTO sequence VALUES(1, 90, 1) - GO -INSERT INTO sequence VALUES(1, 9990, 1) - GO -INSERT INTO sequence VALUES(1, 9992, 1) - GO -INSERT INTO sequence VALUES(1, 10000, 1) - GO -INSERT INTO sequence VALUES(1, 10001, 1) - GO -INSERT INTO sequence VALUES(1, 10010, 1) - GO -INSERT INTO sequence VALUES(1, 10011, 1) - GO -INSERT INTO sequence VALUES(1, 10012, 1) - GO -INSERT INTO sequence VALUES(1, 10014, 1) - GO -INSERT INTO sequence VALUES(1, 10015, 1) - GO -INSERT INTO sequence VALUES(1, 10016, 1) - GO -INSERT INTO sequence VALUES(1, 10017, 1) - GO -INSERT INTO sequence VALUES(1, 10018, 1) - GO -INSERT INTO sequence VALUES(1, 10020, 1) - GO -INSERT INTO sequence VALUES(1, 10021, 1) - GO -INSERT INTO sequence VALUES(1, 10030, 1) - GO -INSERT INTO sequence VALUES(1, 10031, 1) - GO -INSERT INTO sequence VALUES(1, 10040, 1) - GO -INSERT INTO sequence VALUES(1, 20051, 1) - GO -INSERT INTO sequence VALUES(1, 10050, 1) - GO -INSERT INTO sequence VALUES(1, 10060, 1) - GO -INSERT INTO sequence VALUES(1, 10070, 1) - GO -INSERT INTO sequence VALUES(1, 10080, 1) - GO -INSERT INTO sequence VALUES(1, 10090, 1) - GO -INSERT INTO sequence VALUES(1, 10096, 1) - GO -INSERT INTO sequence VALUES(1, 10120, 1) - GO -INSERT INTO sequence VALUES(1, 10121, 1) - GO -INSERT INTO sequence VALUES(1, 10200, 1) - GO -INSERT INTO sequence VALUES(1, 10201, 1) - GO -INSERT INTO sequence VALUES(1, 10202, 1) - GO -INSERT INTO sequence VALUES(1, 10210, 1) - GO -INSERT INTO sequence VALUES(1, 10220, 1) - GO -INSERT INTO sequence VALUES(1, 10300, 1) - GO -INSERT INTO sequence VALUES(1, 10310, 1) - GO -INSERT INTO sequence VALUES(1, 10400, 1) - GO -INSERT INTO sequence VALUES(1, 10500, 1) - GO -INSERT INTO sequence VALUES(1, 10501, 1) - GO -INSERT INTO sequence VALUES(1, 20010, 1) - GO -INSERT INTO sequence VALUES(1, 20011, 1) - GO -INSERT INTO sequence VALUES(1, 20013, 1) - GO -INSERT INTO sequence VALUES(1, 20040, 1) - GO -INSERT INTO sequence VALUES(1, 20050, 1) - GO -INSERT INTO sequence VALUES(1, 20210, 1) - GO -INSERT INTO sequence VALUES(1, 20220, 1) - GO -INSERT INTO sequence VALUES(1, 20096, 1) - GO - diff --git a/platform/platform-resources/src/main/resources/sql/sqlserver/postCreateStructure.sql b/platform/platform-resources/src/main/resources/sql/sqlserver/postCreateStructure.sql deleted file mode 100755 index 95a3ff97c3f..00000000000 --- a/platform/platform-resources/src/main/resources/sql/sqlserver/postCreateStructure.sql +++ /dev/null @@ -1,127 +0,0 @@ --- ------------------------------------------------ Foreign Keys ----------------------------------------------- -ALTER TABLE actor ADD CONSTRAINT fk_actor_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE actormember ADD CONSTRAINT fk_actormember_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE actormember ADD CONSTRAINT fk_actormember_actorId FOREIGN KEY (tenantid, actorId) REFERENCES actor(tenantid, id) -GO --- ALTER TABLE queriable_log ADD CONSTRAINT fk_queriable_log_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE queriablelog_p ADD CONSTRAINT fk_queriablelog_p_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE category ADD CONSTRAINT fk_category_tenantId FOREIGN KEY (tenantid) REFERENCES tenant (id) -GO -ALTER TABLE command ADD CONSTRAINT fk_command_tenantId FOREIGN KEY (tenantid) REFERENCES tenant (id) -GO -ALTER TABLE connector_instance ADD CONSTRAINT fk_connector_instance_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE data_instance ADD CONSTRAINT fk_data_instance_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE dependency ADD CONSTRAINT fk_dependency_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE dependencymapping ADD CONSTRAINT fk_dependencymapping_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE document ADD CONSTRAINT fk_document_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE document_mapping ADD CONSTRAINT fk_document_mapping_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE document_mapping ADD CONSTRAINT fk_docmap_docid FOREIGN KEY (tenantid, documentid) REFERENCES document(tenantid, id) ON DELETE CASCADE -GO -ALTER TABLE event_trigger_instance ADD CONSTRAINT fk_event_trigger_instance_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE external_identity_mapping ADD CONSTRAINT fk_external_identity_mapping_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE flownode_instance ADD CONSTRAINT fk_flownode_instance_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE group_ ADD CONSTRAINT fk_group__tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE job_desc ADD CONSTRAINT fk_job_desc_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE job_param ADD CONSTRAINT fk_job_param_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE message_instance ADD CONSTRAINT fk_message_instance_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE custom_usr_inf_def ADD CONSTRAINT fk_custom_usr_inf_def_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE custom_usr_inf_val ADD CONSTRAINT fk_custom_usr_inf_val_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE pending_mapping ADD CONSTRAINT fk_pending_mapping_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE pending_mapping ADD CONSTRAINT fk_pending_mapping_flownode_instanceId FOREIGN KEY (tenantid, activityId) REFERENCES flownode_instance(tenantid, id) -GO -ALTER TABLE processcategorymapping ADD CONSTRAINT fk_processcategorymapping_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE process_comment ADD CONSTRAINT fk_process_comment_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE process_definition ADD CONSTRAINT fk_process_definition_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE process_definition ADD CONSTRAINT fk_process_definition_content FOREIGN KEY (content_tenantid, content_id) REFERENCES process_content(tenantid, id) -GO -ALTER TABLE processsupervisor ADD CONSTRAINT fk_processsupervisor_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE profile ADD CONSTRAINT fk_profile_tenantId FOREIGN KEY (tenantId) REFERENCES tenant(id) -GO -ALTER TABLE profilemember ADD CONSTRAINT fk_profilemember_tenantId FOREIGN KEY (tenantId) REFERENCES tenant(id) -GO -ALTER TABLE multi_biz_data ADD CONSTRAINT fk_multi_biz_data_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE ref_biz_data_inst ADD CONSTRAINT fk_ref_biz_data_inst_tenantId FOREIGN KEY (tenantId) REFERENCES tenant(id) -GO -ALTER TABLE role ADD CONSTRAINT fk_role_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE user_ ADD CONSTRAINT fk_user__tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE user_membership ADD CONSTRAINT fk_user_membership_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE waiting_event ADD CONSTRAINT fk_waiting_event_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO - -ALTER TABLE profilemember ADD CONSTRAINT fk_profilemember_profileId FOREIGN KEY (tenantId, profileId) REFERENCES profile(tenantId, id) -GO --- ALTER TABLE process_comment ADD CONSTRAINT fk_process_comment_process_instanceId FOREIGN KEY (processInstanceId) REFERENCES process_instance(id) -GO - --- business application -ALTER TABLE business_app ADD CONSTRAINT fk_app_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE business_app ADD CONSTRAINT fk_app_profileId FOREIGN KEY (tenantid, profileId) REFERENCES profile (tenantid, id) -GO -ALTER TABLE business_app ADD CONSTRAINT fk_app_layoutId FOREIGN KEY (tenantid, layoutId) REFERENCES page (tenantid, id) -GO -ALTER TABLE business_app ADD CONSTRAINT fk_app_themeId FOREIGN KEY (tenantid, themeId) REFERENCES page (tenantid, id) -GO -ALTER TABLE business_app_page ADD CONSTRAINT fk_app_page_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE business_app_page ADD CONSTRAINT fk_bus_app_id FOREIGN KEY (tenantid, applicationId) REFERENCES business_app (tenantid, id) ON DELETE CASCADE -GO -ALTER TABLE business_app_page ADD CONSTRAINT fk_page_id FOREIGN KEY (tenantid, pageId) REFERENCES page (tenantid, id) -GO - -ALTER TABLE business_app_menu ADD CONSTRAINT fk_app_menu_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO - --- cannot have both fk_app_menu_appId and fk_app_menu_pageId because this create to path for deletion of business_app_menu elements: --- business_app -> business_app_menu --- business_app -> business_app_page -> business_app_menu --- this is not allowed in SQL Server -ALTER TABLE business_app_menu ADD CONSTRAINT fk_app_menu_appId FOREIGN KEY (tenantid, applicationId) REFERENCES business_app (tenantid, id) -GO -ALTER TABLE business_app_menu ADD CONSTRAINT fk_app_menu_pageId FOREIGN KEY (tenantid, applicationPageId) REFERENCES business_app_page (tenantid, id) -GO - -ALTER TABLE business_app_menu ADD CONSTRAINT fk_app_menu_parentId FOREIGN KEY (tenantid, parentId) REFERENCES business_app_menu (tenantid, id) -GO - --- ------------------------ Foreign Keys to disable if archiving is on another BD ------------------ -ALTER TABLE arch_document_mapping ADD CONSTRAINT fk_arch_document_mapping_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE arch_document_mapping ADD CONSTRAINT fk_archdocmap_docid FOREIGN KEY (tenantid, documentid) REFERENCES document(tenantid, id) ON DELETE CASCADE -GO -ALTER TABLE arch_flownode_instance ADD CONSTRAINT fk_arch_flownode_instance_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE arch_process_comment ADD CONSTRAINT fk_arch_process_comment_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE arch_process_instance ADD CONSTRAINT fk_arch_process_instance_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO -ALTER TABLE arch_data_instance ADD CONSTRAINT fk_arch_data_instance_tenantId FOREIGN KEY (tenantid) REFERENCES tenant(id) -GO diff --git a/platform/platform-resources/src/main/resources/sql/sqlserver/preDropStructure.sql b/platform/platform-resources/src/main/resources/sql/sqlserver/preDropStructure.sql deleted file mode 100755 index 127cbb6f603..00000000000 --- a/platform/platform-resources/src/main/resources/sql/sqlserver/preDropStructure.sql +++ /dev/null @@ -1,120 +0,0 @@ --- ------------------------------------------------ Foreign Keys ----------------------------------------------- -ALTER TABLE actor DROP CONSTRAINT fk_actor_tenantId -GO -ALTER TABLE actormember DROP CONSTRAINT fk_actormember_tenantId -GO -ALTER TABLE actormember DROP CONSTRAINT fk_actormember_actorId -GO --- ALTER TABLE queriable_log DROP CONSTRAINT fk_queriable_log_tenantId -GO -ALTER TABLE queriablelog_p DROP CONSTRAINT fk_queriablelog_p_tenantId -GO -ALTER TABLE category DROP CONSTRAINT fk_category_tenantId -GO -ALTER TABLE command DROP CONSTRAINT fk_command_tenantId -GO -ALTER TABLE connector_instance DROP CONSTRAINT fk_connector_instance_tenantId -GO -ALTER TABLE data_instance DROP CONSTRAINT fk_data_instance_tenantId -GO -ALTER TABLE dependency DROP CONSTRAINT fk_dependency_tenantId -GO -ALTER TABLE dependencymapping DROP CONSTRAINT fk_dependencymapping_tenantId -GO -ALTER TABLE document DROP CONSTRAINT fk_document_tenantId -GO -ALTER TABLE document_mapping DROP CONSTRAINT fk_document_mapping_tenantId -GO -ALTER TABLE document_mapping DROP CONSTRAINT fk_docmap_docid -GO -ALTER TABLE event_trigger_instance DROP CONSTRAINT fk_event_trigger_instance_tenantId -GO -ALTER TABLE external_identity_mapping DROP CONSTRAINT fk_external_identity_mapping_tenantId -GO -ALTER TABLE flownode_instance DROP CONSTRAINT fk_flownode_instance_tenantId -GO -ALTER TABLE group_ DROP CONSTRAINT fk_group__tenantId -GO -ALTER TABLE job_desc DROP CONSTRAINT fk_job_desc_tenantId -GO -ALTER TABLE job_param DROP CONSTRAINT fk_job_param_tenantId -GO -ALTER TABLE message_instance DROP CONSTRAINT fk_message_instance_tenantId -GO -ALTER TABLE custom_usr_inf_def DROP CONSTRAINT fk_custom_usr_inf_def_tenantId -GO -ALTER TABLE custom_usr_inf_val DROP CONSTRAINT fk_custom_usr_inf_val_tenantId -GO -ALTER TABLE pending_mapping DROP CONSTRAINT fk_pending_mapping_tenantId -GO -ALTER TABLE pending_mapping DROP CONSTRAINT fk_pending_mapping_flownode_instanceId -GO -ALTER TABLE processcategorymapping DROP CONSTRAINT fk_processcategorymapping_tenantId -GO -ALTER TABLE process_comment DROP CONSTRAINT fk_process_comment_tenantId -GO -ALTER TABLE process_definition DROP CONSTRAINT fk_process_definition_tenantId -GO -ALTER TABLE process_definition DROP CONSTRAINT fk_process_definition_content -GO -ALTER TABLE processsupervisor DROP CONSTRAINT fk_processsupervisor_tenantId -GO -ALTER TABLE profile DROP CONSTRAINT fk_profile_tenantId -GO -ALTER TABLE profilemember DROP CONSTRAINT fk_profilemember_tenantId -GO -ALTER TABLE multi_biz_data DROP CONSTRAINT fk_multi_biz_data_tenantId -GO -ALTER TABLE ref_biz_data_inst DROP CONSTRAINT fk_ref_biz_data_inst_tenantId -GO -ALTER TABLE role DROP CONSTRAINT fk_role_tenantId -GO -ALTER TABLE user_ DROP CONSTRAINT fk_user__tenantId -GO -ALTER TABLE user_membership DROP CONSTRAINT fk_user_membership_tenantId -GO -ALTER TABLE waiting_event DROP CONSTRAINT fk_waiting_event_tenantId -GO - -ALTER TABLE profilemember DROP CONSTRAINT fk_profilemember_profileId -GO --- ALTER TABLE process_comment DROP CONSTRAINT fk_process_comment_process_instanceId -GO - --- business application -ALTER TABLE business_app_menu DROP CONSTRAINT fk_app_menu_tenantId -GO -ALTER TABLE business_app_menu DROP CONSTRAINT fk_app_menu_appId -GO -ALTER TABLE business_app_menu DROP CONSTRAINT fk_app_menu_pageId -GO -ALTER TABLE business_app_menu DROP CONSTRAINT fk_app_menu_parentId -GO -ALTER TABLE business_app_page DROP CONSTRAINT fk_app_page_tenantId -GO -ALTER TABLE business_app_page DROP CONSTRAINT fk_bus_app_id -GO -ALTER TABLE business_app_page DROP CONSTRAINT fk_page_id -GO -ALTER TABLE business_app DROP CONSTRAINT fk_app_profileId -GO -ALTER TABLE business_app DROP CONSTRAINT fk_app_tenantId -GO -ALTER TABLE business_app DROP CONSTRAINT fk_app_layoutId -GO -ALTER TABLE business_app DROP CONSTRAINT fk_app_themeId -GO - --- ------------------------ Foreign Keys to disable if archiving is on another BD ------------------ -ALTER TABLE arch_document_mapping DROP CONSTRAINT fk_arch_document_mapping_tenantId -GO -ALTER TABLE arch_document_mapping DROP CONSTRAINT fk_archdocmap_docid -GO -ALTER TABLE arch_flownode_instance DROP CONSTRAINT fk_arch_flownode_instance_tenantId -GO -ALTER TABLE arch_process_comment DROP CONSTRAINT fk_arch_process_comment_tenantId -GO -ALTER TABLE arch_process_instance DROP CONSTRAINT fk_arch_process_instance_tenantId -GO -ALTER TABLE arch_data_instance DROP CONSTRAINT fk_arch_data_instance_tenantId -GO diff --git a/platform/platform-resources/src/main/resources/tenant_template_portal/compound-permissions-mapping.properties b/platform/platform-resources/src/main/resources/tenant_template_portal/compound-permissions-mapping.properties index b537e8557b1..8b790ac33be 100644 --- a/platform/platform-resources/src/main/resources/tenant_template_portal/compound-permissions-mapping.properties +++ b/platform/platform-resources/src/main/resources/tenant_template_portal/compound-permissions-mapping.properties @@ -27,7 +27,7 @@ custompage_adminBDMBonita=[bdm_access_control, bdm_management, bdm_visualization custompage_adminResourceListBonita=[application_visualization, form_visualization, page_management, profile_management, profile_visualization] custompage_adminApplicationListBonita=[application_management, application_visualization, organization_visualization, profile_visualization, tenant_platform_visualization] custompage_adminApplicationDetailsBonita=[application_management, application_visualization, organization_visualization, page_management, profile_visualization, tenant_platform_visualization] -custompage_adminLicenseBonita=[platform_management, tenant_platform_visualization] +custompage_adminLicenseBonita=[tenant_platform_visualization] custompage_tenantStatusBonita=[license, tenant_platform_management, tenant_platform_visualization] custompage_applicationDirectoryBonita=[application_visualization, organization_visualization, tenant_platform_visualization] custompage_home=[] diff --git a/platform/platform-resources/src/main/resources/tenant_template_portal/resources-permissions-mapping.properties b/platform/platform-resources/src/main/resources/tenant_template_portal/resources-permissions-mapping.properties index f8e8abd5378..fa6e6494ff8 100644 --- a/platform/platform-resources/src/main/resources/tenant_template_portal/resources-permissions-mapping.properties +++ b/platform/platform-resources/src/main/resources/tenant_template_portal/resources-permissions-mapping.properties @@ -174,6 +174,7 @@ GET|platform/systemProperty=[tenant_platform_visualization] GET|platform/license=[platform_management] POST|tenant/bdm=[bdm_management] GET|tenant/bdm=[bdm_management] +GET|system/information=[tenant_platform_visualization] # Living apps GET|living/application=[application_visualization] diff --git a/platform/platform-setup-test/src/main/java/org/bonitasoft/platform/setup/PlatformSetupTestUtils.java b/platform/platform-setup-test/src/main/java/org/bonitasoft/platform/setup/PlatformSetupTestUtils.java index 11e853da39a..efe75b8981f 100644 --- a/platform/platform-setup-test/src/main/java/org/bonitasoft/platform/setup/PlatformSetupTestUtils.java +++ b/platform/platform-setup-test/src/main/java/org/bonitasoft/platform/setup/PlatformSetupTestUtils.java @@ -159,4 +159,13 @@ public static CommandLine createCommandLine() { return oCmdLine; } } + + public static boolean isCommunityEdition(Class clazz) { + try { + return clazz.getClassLoader().loadClass("com.bonitasoft.platform.setup.PlatformSetupSP") == null; + } catch (ClassNotFoundException e) { + return true; + } + } + } diff --git a/platform/platform-setup/bin/.gitignore b/platform/platform-setup/bin/.gitignore new file mode 100644 index 00000000000..7eed456bec8 --- /dev/null +++ b/platform/platform-setup/bin/.gitignore @@ -0,0 +1,2 @@ +/main/ +/test/ diff --git a/platform/platform-setup/build.gradle b/platform/platform-setup/build.gradle index 15e143f0d36..c88ec1106a4 100644 --- a/platform/platform-setup/build.gradle +++ b/platform/platform-setup/build.gradle @@ -1,9 +1,11 @@ import org.apache.tools.ant.filters.ReplaceTokens import org.bonitasoft.engine.gradle.PomUtils +import org.gradle.internal.os.OperatingSystem plugins { id 'distribution' id 'bonita-tests' + id 'bonita-docker-database' } configurations { @@ -12,6 +14,7 @@ configurations { } dependencies { + api project(':platform:platform-resources') api libs.commonsText api libs.slf4jApi api(libs.springBootStarter) { @@ -19,28 +22,16 @@ dependencies { exclude(module: 'log4j-to-slf4j') exclude(module: 'snakeyaml') } - api libs.snakeyaml api libs.springBootStarterJdbc - api libs.postgresql - api(libs.mysql) { - exclude(module: 'protobuf-java') - } - api libs.msSqlServer api libs.h2 - api(libs.oracle) { - exclude(module: "ons") - exclude(module: "oraclepki") - exclude(module: "osdt_cert") - exclude(module: "osdt_core") - exclude(module: "ucp") - exclude(module: "simplefan") - } + api libs.postgresql api libs.commonsCLI + annotationProcessor libs.lombok compileOnly libs.lombok - api(project(":platform:platform-resources")) + runtimeOnly libs.logback - testImplementation libs.junit4 + testImplementation libs.assertj testImplementation libs.mockitoCore testImplementation libs.systemRules @@ -77,6 +68,7 @@ processResources { } distTar.enabled = false + distributions { main { distributionBaseName = "Bonita-platform-setup" @@ -101,20 +93,21 @@ distributions { exclude(module: 'commons-logging') exclude(module: 'log4j-api') exclude(module: 'log4j-to-slf4j') + exclude(module: 'snakeyaml') } } - configurations.inDistrib.resolvedConfiguration.resolvedArtifacts.each { - from(zipTree(it.file)) { + configurations.inDistrib.resolvedConfiguration.resolvedArtifacts.each { artifact -> + // Copy all sql files under the distrib zip folder /platform_conf/sql/ + from(zipTree(artifact.file)) { include '**/sql/**' eachFile { fcp -> fcp.path = fcp.path.replaceAll(".*/sql/", "/platform_conf/sql/") } } - } - configurations.inDistrib.resolvedConfiguration.resolvedArtifacts.each { - from(zipTree(it.file)) { + // Copy all files excepting sql and classes under the distrib zip folder /platform_conf/initial/ + from(zipTree(artifact.file)) { exclude '**/sql/**' - exclude '**/org/**' + exclude '**/*.class' eachFile { fcp -> fcp.path = fcp.path.replaceAll(".*${version}/", "/platform_conf/initial/") } @@ -125,21 +118,34 @@ distributions { } } - tasks.distZip.dependsOn configurations.inDistrib artifacts { distributionZip distZip } -test { include '**/*Test.class' } +databaseIntegrationTest { + include '**/*IT.class' + // No need to execute PlatformSetupDistributionIT on databases + exclude '**/PlatformSetupDistributionIT.class' +} + +tasks.matching { task -> task.name == "integrationTest" || task.name.endsWith("DatabaseTest") } + .configureEach { task -> + def testDir = new File(buildDir, task.name) + doFirst { + testDir.mkdirs() + systemProperty "bonita.distribution.path", distZip.outputs.files.first() + } + workingDir testDir + dependsOn distZip + } -def iT = tasks.getByName("integrationTest") -iT.configure { - def testDir = new File(buildDir, "integrationTest") - doFirst { - testDir.mkdirs() - systemProperty "bonita.distribution.path", distZip.outputs.files.first() - } - workingDir testDir +def setupE2e = tasks.register('setup-e2e', Exec) { + commandLine 'sh', 'src/test/e2e/e2e-postgres-bos.sh' + dependsOn distZip + onlyIf { OperatingSystem.current().isLinux() } } -tasks.integrationTest.dependsOn distZip + +integrationTest.configure { + dependsOn setupE2e +} \ No newline at end of file diff --git a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/PlatformSetupApplication.java b/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/PlatformSetupApplication.java index 968d990dfe4..358676ee983 100644 --- a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/PlatformSetupApplication.java +++ b/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/PlatformSetupApplication.java @@ -47,7 +47,7 @@ */ @SpringBootApplication @ComponentScan(basePackages = { "org.bonitasoft.platform.setup", "org.bonitasoft.platform.configuration", - "org.bonitasoft.platform.version" }) + "org.bonitasoft.platform.version", "com.bonitasoft.platform.setup" }) public class PlatformSetupApplication { // /!\ Leave this logger NON-STATIC, so that DEBUG property may be set before it is initialized: diff --git a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/command/configure/BundleConfigurator.java b/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/command/configure/BundleConfigurator.java index e636bcb1d2c..872cb0e165d 100644 --- a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/command/configure/BundleConfigurator.java +++ b/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/command/configure/BundleConfigurator.java @@ -22,13 +22,17 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.text.SimpleDateFormat; -import java.util.*; +import java.util.Collection; +import java.util.Date; +import java.util.Map; +import java.util.Properties; import java.util.regex.Matcher; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOCase; import org.apache.commons.io.filefilter.RegexFileFilter; import org.apache.commons.text.StringEscapeUtils; +import org.bonitasoft.platform.database.DatabaseVendor; import org.bonitasoft.platform.exception.PlatformException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,20 +52,16 @@ abstract class BundleConfigurator { static final Logger LOGGER = LoggerFactory.getLogger(BundleConfigurator.class); - private static final String H2 = "h2"; - private static final String ORACLE = "oracle"; - private static final String SQLSERVER = "sqlserver"; - private static final String TOMCAT_TEMPLATES_FOLDER = "tomcat-templates"; static final String APPSERVER_FOLDERNAME = "server"; - private Path rootPath; + private final Path rootPath; DatabaseConfiguration standardConfiguration; DatabaseConfiguration bdmConfiguration; private Path backupsFolder; - private String timestamp; + private final String timestamp; BundleConfigurator(Path rootPath) throws PlatformException { try { @@ -273,10 +273,10 @@ RegexFileFilter getDriverFilter(String dbVendor) { } private String getDriverPattern(String dbVendor) { - if (ORACLE.equals(dbVendor)) { + if (DatabaseVendor.ORACLE.equalsValue(dbVendor)) { return ".*(ojdbc|oracle).*\\.(jar|zip)"; } - if (SQLSERVER.equals(dbVendor)) { + if (DatabaseVendor.SQLSERVER.equalsValue(dbVendor)) { return ".*(sqlserver|mssql|sqljdbc).*\\.(jar|zip)"; } return ".*" + dbVendor + ".*"; @@ -330,7 +330,7 @@ static String getDatabaseConnectionUrlForXmlFile(DatabaseConfiguration configura static String getDatabaseConnectionUrlForPropertiesFile(DatabaseConfiguration configuration) { String url = getDatabaseConnectionUrl(configuration); - if (H2.equals(configuration.getDbVendor())) { + if (DatabaseVendor.H2.equalsValue(configuration.getDbVendor())) { url = StringEscapeUtils.escapeJava(url); } return Matcher.quoteReplacement(url); @@ -338,7 +338,7 @@ static String getDatabaseConnectionUrlForPropertiesFile(DatabaseConfiguration co private static String getDatabaseConnectionUrl(DatabaseConfiguration configuration) { String url = configuration.getUrl(); - if (H2.equals(configuration.getDbVendor())) { + if (DatabaseVendor.H2.equalsValue(configuration.getDbVendor())) { url = convertWindowsBackslashes(url); } return url; diff --git a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/command/configure/BundleResolver.java b/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/command/configure/BundleResolver.java index 6d71c7a2a0f..c6929d9c6b5 100644 --- a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/command/configure/BundleResolver.java +++ b/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/command/configure/BundleResolver.java @@ -20,20 +20,16 @@ import java.nio.file.Path; import java.nio.file.Paths; +import lombok.extern.slf4j.Slf4j; import org.bonitasoft.platform.exception.PlatformException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * This class contains the logic to determine if we are in the context of an application server that we must configure. * Only Tomcat is supported. - * - * @author Emmanuel Duchastenier */ +@Slf4j class BundleResolver { - private static final Logger LOGGER = LoggerFactory.getLogger(BundleConfigurator.class); - private final Path rootPath; BundleResolver() { @@ -48,7 +44,7 @@ class BundleResolver { private boolean fileExists(Path filePath) { final boolean exists = Files.exists(filePath); if (!exists) { - LOGGER.debug("File " + filePath.toString() + " does not exist."); + log.debug("File {} does not exist.", filePath); } return exists; } @@ -71,8 +67,8 @@ BundleConfigurator getConfigurator() throws PlatformException { if (isTomcatEnvironment()) { return new TomcatBundleConfigurator(rootPath); } else { - LOGGER.info( - "No Application Server detected. You may need to manually configure the access to the database. Only Tomcat 8.x is supported"); + log.info("No Application Server detected. You may need to manually configure the access to the database. " + + "Only Tomcat 9.0.x is supported"); return null; } } diff --git a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/command/configure/PropertyReader.java b/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/command/configure/PropertyReader.java index 83d9c7f8ec4..a28c5f4d1a4 100644 --- a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/command/configure/PropertyReader.java +++ b/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/command/configure/PropertyReader.java @@ -15,18 +15,12 @@ import java.util.Properties; +import lombok.extern.slf4j.Slf4j; import org.bonitasoft.platform.exception.PlatformException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -/** - * @author Emmanuel Duchastenier - */ +@Slf4j public class PropertyReader { - // Use BundleConfigurator logger for easier configuration (no need for a specific logger here): - private static final Logger LOGGER = LoggerFactory.getLogger(BundleConfigurator.class); - private final Properties properties; public PropertyReader(Properties properties) { @@ -37,7 +31,7 @@ public String getPropertyAndFailIfNull(String propertyName) throws PlatformExcep // Any property value can be overridden by system property with the same name: final String sysPropValue = System.getProperty(propertyName); if (sysPropValue != null) { - LOGGER.info("System property '{}' set to '{}', overriding value from file database.properties.", + log.info("System property '{}' set to '{}', overriding value from file database.properties.", propertyName, sysPropValue); return sysPropValue.trim(); } diff --git a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/command/configure/TomcatBundleConfigurator.java b/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/command/configure/TomcatBundleConfigurator.java index 26fb1c86594..f7d7c8496d9 100644 --- a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/command/configure/TomcatBundleConfigurator.java +++ b/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/command/configure/TomcatBundleConfigurator.java @@ -21,6 +21,7 @@ import java.util.regex.Matcher; import org.bonitasoft.platform.exception.PlatformException; +import org.bonitasoft.platform.setup.PlatformSetup; /** * @author Emmanuel Duchastenier @@ -55,16 +56,16 @@ public void configureApplicationServer() throws PlatformException { // 1. update setenv(.sh|.bat): String newContent = readContentFromFile(getTemplateFolderPath("setenv.bat")); - newContent = updateSetEnvFile(newContent, dbVendor, "sysprop.bonita.db.vendor"); - newContent = updateSetEnvFile(newContent, bdmDbVendor, "sysprop.bonita.bdm.db.vendor"); + newContent = updateSetEnvFile(newContent, dbVendor, PlatformSetup.BONITA_DB_VENDOR_PROPERTY); + newContent = updateSetEnvFile(newContent, bdmDbVendor, PlatformSetup.BONITA_BDM_DB_VENDOR_PROPERTY); backupAndReplaceContentIfNecessary(setEnvWindowsFile, newContent, "Setting Bonita internal database vendor to '" + dbVendor + "' and Business Data database vendor to '" + bdmDbVendor + "' in 'setenv.bat' file"); newContent = readContentFromFile(getTemplateFolderPath("setenv.sh")); - newContent = updateSetEnvFile(newContent, dbVendor, "sysprop.bonita.db.vendor"); - newContent = updateSetEnvFile(newContent, bdmDbVendor, "sysprop.bonita.bdm.db.vendor"); + newContent = updateSetEnvFile(newContent, dbVendor, PlatformSetup.BONITA_DB_VENDOR_PROPERTY); + newContent = updateSetEnvFile(newContent, bdmDbVendor, PlatformSetup.BONITA_BDM_DB_VENDOR_PROPERTY); backupAndReplaceContentIfNecessary(setEnvUnixFile, newContent, "Setting Bonita internal database vendor to '" + dbVendor + "' and Business Data database vendor to '" + bdmDbVendor diff --git a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/dbconfig/GenericDataSourceConfig.java b/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/dbconfig/DataSourceConfig.java similarity index 80% rename from platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/dbconfig/GenericDataSourceConfig.java rename to platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/dbconfig/DataSourceConfig.java index 0a5dd51587f..45fb4d9c4b0 100644 --- a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/dbconfig/GenericDataSourceConfig.java +++ b/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/dbconfig/DataSourceConfig.java @@ -13,18 +13,14 @@ **/ package org.bonitasoft.platform.setup.dbconfig; -import org.springframework.context.annotation.Profile; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Component; /** - * This is enough to get a Datasource that spring creates using parameters provided in properties. - * - * @author Emmanuel Duchastenier + * Used by Spring to create an instance of {@link javax.sql.DataSource} using parameters provided in properties. */ @Component @PropertySource(value = { "classpath:/database.properties", "classpath:/internal.properties" }) -@Profile("default") -public class GenericDataSourceConfig { +public class DataSourceConfig { } diff --git a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/dbconfig/PostgresDataSourceConfig.java b/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/dbconfig/PostgresDataSourceConfig.java deleted file mode 100644 index 0204778dbf7..00000000000 --- a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/dbconfig/PostgresDataSourceConfig.java +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (C) 2019 Bonitasoft S.A. - * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble - * This library is free software; you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Foundation - * version 2.1 of the License. - * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * You should have received a copy of the GNU Lesser General Public License along with this - * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth - * Floor, Boston, MA 02110-1301, USA. - **/ -package org.bonitasoft.platform.setup.dbconfig; - -import org.springframework.context.annotation.Profile; -import org.springframework.context.annotation.PropertySource; -import org.springframework.stereotype.Component; - -/** - * This is enough to get a Datasource that spring creates using parameters provided in properties. - * - * @author Emmanuel Duchastenier - */ -@Component -@PropertySource("classpath:/postgres.properties") -@Profile("postgres") -public class PostgresDataSourceConfig { - -} diff --git a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/dbconfig/SQLServerDataSourceConfig.java b/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/dbconfig/SQLServerDataSourceConfig.java deleted file mode 100644 index 6faae38cf9d..00000000000 --- a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/dbconfig/SQLServerDataSourceConfig.java +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (C) 2019 Bonitasoft S.A. - * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble - * This library is free software; you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Foundation - * version 2.1 of the License. - * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * You should have received a copy of the GNU Lesser General Public License along with this - * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth - * Floor, Boston, MA 02110-1301, USA. - **/ -package org.bonitasoft.platform.setup.dbconfig; - -import org.springframework.context.annotation.Profile; -import org.springframework.context.annotation.PropertySource; -import org.springframework.stereotype.Component; - -/** - * This is enough to get a Datasource that spring creates using parameters provided in properties. - * - * @author Emmanuel Duchastenier - */ -@Component -@PropertySource("classpath:/sqlserver.properties") -@Profile("sqlserver") -public class SQLServerDataSourceConfig { - -} diff --git a/platform/platform-setup/src/main/resources/application.properties b/platform/platform-setup/src/main/resources/application.properties index 5c047636960..d60f1dd57f3 100644 --- a/platform/platform-setup/src/main/resources/application.properties +++ b/platform/platform-setup/src/main/resources/application.properties @@ -1,2 +1 @@ -spring.profiles.active=h2 db.vendor=${sysprop.bonita.db.vendor:h2} diff --git a/platform/platform-setup/src/main/standalone/database.properties b/platform/platform-setup/src/main/standalone/database.properties index 22515ff88f8..eee5bb8237f 100644 --- a/platform/platform-setup/src/main/standalone/database.properties +++ b/platform/platform-setup/src/main/standalone/database.properties @@ -10,7 +10,8 @@ # Bonita database properties ######################################### -# valid values are (h2, postgres, sqlserver, oracle, mysql) +# Valid values for Community edition: h2, postgres +# Valid values for Enterprise editions: h2, postgres, sqlserver, oracle, mysql db.vendor=h2 # when using h2, no server or port setting is needed since connexion is made using file protocol mode using relative directory: db.server.name=SERVER_NAME @@ -24,7 +25,8 @@ db.password= ################################### # Business Data database properties ################################### -# valid values are (h2, postgres, sqlserver, oracle, mysql) +# Valid values for Community edition: h2, postgres +# Valid values for Enterprise editions: h2, postgres, sqlserver, oracle, mysql bdm.db.vendor=h2 bdm.db.server.name=SERVER_NAME bdm.db.server.port=SERVER_PORT diff --git a/platform/platform-setup/src/main/standalone/internal.properties b/platform/platform-setup/src/main/standalone/internal.properties index c33faa38eab..40307a094aa 100644 --- a/platform/platform-setup/src/main/standalone/internal.properties +++ b/platform/platform-setup/src/main/standalone/internal.properties @@ -15,22 +15,6 @@ postgres.nonXaDriver=org.postgresql.Driver postgres.xaDriver=org.postgresql.xa.PGXADataSource postgres.xaDSFactory=org.postgresql.xa.PGXADataSourceFactory -# use this drivers for pre-8.0 MySQL version: -# mysql.nonXaDriver=com.mysql.jdbc.Driver -# mysql.xaDriver=com.mysql.jdbc.jdbc2.optional.MysqlXADataSource -# Otherwise use MySQL 8+ new driver: -mysql.nonXaDriver=com.mysql.cj.jdbc.Driver -mysql.xaDriver=com.mysql.cj.jdbc.MysqlXADataSource -mysql.xaDSFactory=com.mysql.cj.jdbc.MysqlDataSourceFactory - -sqlserver.nonXaDriver=com.microsoft.sqlserver.jdbc.SQLServerDriver -sqlserver.xaDriver=com.microsoft.sqlserver.jdbc.SQLServerXADataSource -sqlserver.xaDSFactory=com.microsoft.sqlserver.jdbc.SQLServerDataSourceObjectFactory - -oracle.nonXaDriver=oracle.jdbc.OracleDriver -oracle.xaDriver=oracle.jdbc.xa.client.OracleXADataSource -oracle.xaDSFactory=oracle.jdbc.pool.OracleDataSourceFactory - ########################### ## Bonita database ########################### @@ -43,18 +27,6 @@ h2.testQuery=SELECT 1 postgres.url=jdbc:postgresql://${db.server.name}:${db.server.port}/${db.database.name} postgres.testQuery=SELECT 1 -# mysql properties -mysql.url=jdbc:mysql://${db.server.name}:${db.server.port}/${db.database.name}?dontTrackOpenResources=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true -mysql.testQuery=SELECT 1 - -# sqlserver properties -sqlserver.url=jdbc:sqlserver://${db.server.name}:${db.server.port};database=${db.database.name} -sqlserver.testQuery=SELECT 1 - -# oracle properties -oracle.url=jdbc:oracle:thin:@//${db.server.name}:${db.server.port}/${db.database.name}?oracle.net.disableOob=true -oracle.testQuery=SELECT 1 FROM DUAL - # spring properties spring.datasource.username=${db.user} @@ -83,18 +55,6 @@ h2.bdm.testQuery=SELECT 1 postgres.bdm.url=jdbc:postgresql://${bdm.db.server.name}:${bdm.db.server.port}/${bdm.db.database.name} postgres.bdm.testQuery=SELECT 1 -# mysql properties -mysql.bdm.url=jdbc:mysql://${bdm.db.server.name}:${bdm.db.server.port}/${bdm.db.database.name}?dontTrackOpenResources=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true -mysql.bdm.testQuery=SELECT 1 - -# sqlserver properties -sqlserver.bdm.url=jdbc:sqlserver://${bdm.db.server.name}:${bdm.db.server.port};database=${bdm.db.database.name} -sqlserver.bdm.testQuery=SELECT 1 - -# oracle properties -oracle.bdm.url=jdbc:oracle:thin:@//${bdm.db.server.name}:${bdm.db.server.port}/${bdm.db.database.name}?oracle.net.disableOob=true -oracle.bdm.testQuery=SELECT 1 FROM DUAL - # The initial number of connections when the connection pool starts. bdm.connection-pool.initialSize=4 # The maximum number of active connections that can be allocated from this pool at the same time. diff --git a/platform/platform-setup/src/main/standalone/setup.bat b/platform/platform-setup/src/main/standalone/setup.bat index d9c4303ce86..8c95d9e2e5b 100644 --- a/platform/platform-setup/src/main/standalone/setup.bat +++ b/platform/platform-setup/src/main/standalone/setup.bat @@ -1,7 +1,7 @@ @echo off setlocal EnableDelayedExpansion -:: Let's position into folder containing this script: +:: Let's position into the folder containing this script: set CURRENTDIR="%cd%" set BASEDIR=%~dp0 cd %BASEDIR% @@ -17,20 +17,49 @@ set LIB_FOLDER=%BASEDIR%\lib FOR /F "tokens=1,* delims== eol=#" %%A IN (database.properties) DO (set %%A=%%B) set BONITA_DATABASE=%db.vendor% +set BONITA_BDM_DATABASE=%bdm.db.vendor% -IF NOT "%BONITA_DATABASE%" == "h2" IF NOT "%BONITA_DATABASE%" == "postgres" IF NOT "%BONITA_DATABASE%" == "sqlserver" IF NOT "%BONITA_DATABASE%" == "oracle" IF NOT "%BONITA_DATABASE%" == "mysql" ( - echo Cannot determine database vendor valid values are [h2, postgres, sqlserver, oracle, mysql]. - echo Please configure file %BASEDIR%database.properties properly. +call :checkVendorSupported %BONITA_DATABASE% +if ERRORLEVEL 1 ( + exit /b 1 +) +call :checkVendorSupported %BONITA_BDM_DATABASE% +if ERRORLEVEL 1 ( exit /b 1 ) -"%JAVA_CMD%" -cp "%BASEDIR%;%CFG_FOLDER%;%INITIAL_CFG_FOLDER%;%LIB_FOLDER%\*" -Dspring.profiles.active=default -Dsysprop.bonita.db.vendor=%BONITA_DATABASE% org.bonitasoft.platform.setup.PlatformSetupApplication %* +"%JAVA_CMD%" -cp "%BASEDIR%;%CFG_FOLDER%;%INITIAL_CFG_FOLDER%;%LIB_FOLDER%\*" ^ + -Dsysprop.bonita.db.vendor=%BONITA_DATABASE% ^ + -Dsysprop.bonita.bdm.db.vendor=%BONITA_BDM_DATABASE% ^ + org.bonitasoft.platform.setup.PlatformSetupApplication %* -if errorlevel 1 ( +if ERRORLEVEL 1 ( exit /b 1 ) :: restore previous folder: cd %CURRENTDIR% -exit /b 0 \ No newline at end of file +:: exit script with success +exit /b 0 + + +REM Function that exits with an error message if the vendor is not supported +REM - first argument is the database vendor value to check +:checkVendorSupported +set DB_VENDOR=%1 +set IS_SUPPORTED=false +for %%d in (h2 postgres) do ( + if "%%d" == "!DB_VENDOR!" ( + set IS_SUPPORTED=true + goto :breakLoop + ) +) +:breakLoop +if "!IS_SUPPORTED!" == "false" ( + echo ERROR: Unsupported database vendor ^(valid values are h2, postgres^). + echo For access to additional databases ^(oracle, mysql, sqlserver^), please consider upgrading to the Enterprise Edition. + echo Please update file %BASEDIR%database.properties to set a valid value. + exit /b 1 +) +exit /b 0 diff --git a/platform/platform-setup/src/main/standalone/setup.sh b/platform/platform-setup/src/main/standalone/setup.sh old mode 100644 new mode 100755 index aab90fa1bd9..e9fa3aa1926 --- a/platform/platform-setup/src/main/standalone/setup.sh +++ b/platform/platform-setup/src/main/standalone/setup.sh @@ -1,7 +1,29 @@ #!/bin/sh set -e -BASEDIR=$(cd $(dirname $(dirname "$0")/..) && pwd -P) +# Function that exits with an error message if the vendor is not supported +# - first argument is the database vendor value to check +check_vendor_supported() { + db_vendor=$1 + is_supported=false + # supported databases: + set -- h2 postgres + for db in "$@"; do + if [ "$db" = "$db_vendor" ]; then + is_supported=true + break + fi + done + if [ "$is_supported" = false ]; then + echo "ERROR: Unsupported database vendor (valid values are h2, postgres)." + echo "For access to additional databases (oracle, mysql, sqlserver), please consider upgrading to the Enterprise Edition." + echo "Please update file ${BASEDIR}/database.properties to set a valid value." + exit 1 + fi +} + +# Let's position into the folder containing this script: +BASEDIR=$(cd "$(dirname "$(dirname "$0")/..")" && pwd -P) cd "${BASEDIR}" # JAVA_CMD is exported by start-bonita.sh, so that same Java command is used: @@ -15,14 +37,15 @@ for lib in lib/*.jar; do done BONITA_DATABASE=$(grep '^db.vendor=' database.properties | sed -e 's/db.vendor=//g') +check_vendor_supported "$BONITA_DATABASE" -if [ "$BONITA_DATABASE" != "h2" -a "$BONITA_DATABASE" != "postgres" -a "$BONITA_DATABASE" != "sqlserver" -a "$BONITA_DATABASE" != "oracle" -a "$BONITA_DATABASE" != "mysql" ]; then - echo "Cannot determine database vendor (valid values are h2, postgres, sqlserver, oracle, mysql)." - echo "Please configure file ${BASEDIR}/database.properties properly." - exit 1 -fi +BONITA_BDM_DATABASE=$(grep '^bdm.db.vendor=' database.properties | sed -e 's/bdm.db.vendor=//g') +check_vendor_supported "$BONITA_BDM_DATABASE" -"${JAVA_EXE}" -cp "${BASEDIR}:${CFG_FOLDER}:${INITIAL_CFG_FOLDER}${LIBS_CP}" ${JVM_OPTS} -Dspring.profiles.active=default -Dsysprop.bonita.db.vendor=${BONITA_DATABASE} org.bonitasoft.platform.setup.PlatformSetupApplication "$@" +"${JAVA_EXE}" -cp "${BASEDIR}:${CFG_FOLDER}:${INITIAL_CFG_FOLDER}${LIBS_CP}" \ + -Dsysprop.bonita.db.vendor="${BONITA_DATABASE}" \ + -Dsysprop.bonita.bdm.db.vendor="${BONITA_BDM_DATABASE}" \ + org.bonitasoft.platform.setup.PlatformSetupApplication "$@" COD_RET=$? if [ ${COD_RET} -ne 0 ]; then cd - 1>/dev/null diff --git a/platform/platform-setup/clean-postgres.sh b/platform/platform-setup/src/test/e2e/clean-postgres.sh similarity index 100% rename from platform/platform-setup/clean-postgres.sh rename to platform/platform-setup/src/test/e2e/clean-postgres.sh diff --git a/platform/platform-setup/e2e-distrib.sh b/platform/platform-setup/src/test/e2e/e2e-distrib.sh similarity index 100% rename from platform/platform-setup/e2e-distrib.sh rename to platform/platform-setup/src/test/e2e/e2e-distrib.sh diff --git a/platform/platform-setup/e2e-postgres-bos.sh b/platform/platform-setup/src/test/e2e/e2e-postgres-bos.sh similarity index 87% rename from platform/platform-setup/e2e-postgres-bos.sh rename to platform/platform-setup/src/test/e2e/e2e-postgres-bos.sh index 4505ea32ca4..152b2eb1acc 100755 --- a/platform/platform-setup/e2e-postgres-bos.sh +++ b/platform/platform-setup/src/test/e2e/e2e-postgres-bos.sh @@ -27,13 +27,9 @@ docker rm -vf bonita-postgres 2> /dev/null echo "=============================================" echo "Start the Postgres database docker container" echo "=============================================" -docker run --rm -p 5432:5432 --name bonita-postgres -d bonitasoft/bonita-postgres:11.9 +docker run --rm -p 5432:5432 --name bonita-postgres -d bonitasoft/bonita-postgres:16.4 -cd ../../.. -./gradlew build -x test -cd - - -export VERSION=`cat ../platform-resources/build/resources/main/PLATFORM_ENGINE_VERSION` +export VERSION="$(cat ../platform-resources/build/resources/main/PLATFORM_ENGINE_VERSION)" echo "========================================" echo "version: ${VERSION}" @@ -127,8 +123,8 @@ docker exec bonita-postgres psql postgresql://bonita:bpm@localhost:5432/bonita - SELECT p.id, p.version, - p.initialversion, - p.createdby, + p.initial_bonita_version, + p.created_by, TO_CHAR( TO_TIMESTAMP( p.created / 1000 @@ -168,7 +164,7 @@ INSERT resource_name, resource_content ) SELECT - 456, + 1, 'TENANT_SECURITY_SCRIPTS', c.resource_name, c.resource_content @@ -210,48 +206,6 @@ testValue $compound "compound-permissions-mapping" echo "=> Verification Ok" -echo "========================================" -echo "modify & push" -echo "========================================" - -echo "new content" > ${E2E_DIR}/platform_conf/current/tenants/456/tenant_security_scripts/SamplePermissionRule.groovy.sample -# create custom groovy script and verify it is in database -CUSTOM_FILE=${E2E_DIR}/platform_conf/current/tenants/456/tenant_security_scripts/MyCustomRule.groovy -touch ${CUSTOM_FILE} - -${E2E_DIR}/setup.sh push - -echo "============================================" -echo "Backup folder should be created when pushing" -echo "============================================" - -if [ "`ls ${E2E_DIR}/platform_conf/ | grep 'backup-'`" = "" ]; then - echo 'ERROR. Should have created backup folder'; - exit -52 -else - echo 'OK. Backup folder present.' -fi - -echo "========================================" -echo "pull & check new value" -echo "========================================" - -rm -rf ${E2E_DIR}/platform_conf/current/* - -${E2E_DIR}/setup.sh pull - -echo "========================================" -echo "------------------ Retrieved content from database should be 'new content' ---------" -echo "new content of file ${E2E_DIR}/platform_conf/current/tenants/456/tenant_security_scripts/SamplePermissionRule.groovy.sample is now:" -new_content=`cat ${E2E_DIR}/platform_conf/current/tenants/456/tenant_security_scripts/SamplePermissionRule.groovy.sample` -echo ${new_content} -testValue "${new_content}" "new content" - -echo "Custom groovy script file MyCustomRule.groovy should have been pushed and retrieved:" -ls ${E2E_DIR}/platform_conf/current/tenants/456/tenant_security_scripts/ - -echo "========================================" - echo "========================================" echo "remove some files & push" echo "========================================" @@ -271,6 +225,17 @@ echo "===========================================" ${E2E_DIR}/setup.sh push --force testReturnCode $? "setup.sh push --force should be successful" +echo "============================================" +echo "Backup folder should be created when pushing" +echo "============================================" + +if [ "`ls ${E2E_DIR}/platform_conf/ | grep 'backup-'`" = "" ]; then + echo 'ERROR. Should have created backup folder'; + exit 52 +else + echo 'OK. Backup folder present.' +fi + echo "========================================" echo "should contain only bonita-platform-custom.xml:" tree ${E2E_DIR}/platform_conf/current @@ -294,6 +259,13 @@ echo "Docker database cleanup" echo "========================================" docker rm -vf bonita-postgres +echo "========================================" +echo "Test cleanup" +echo "========================================" +echo "Cleaning up $(cd ${E2E_DIR} && pwd) and $(cd ./build/h2_database && pwd)" +rm -Rf ${E2E_DIR} +rm -Rf ./build/h2_database + echo "========================================" echo "END" echo "========================================" diff --git a/platform/platform-setup/src/test/java/org/bonitasoft/platform/configuration/impl/ConfigurationServiceImplIT.java b/platform/platform-setup/src/test/java/org/bonitasoft/platform/configuration/impl/ConfigurationServiceImplIT.java index 7d8493ca085..ccc10d4156b 100644 --- a/platform/platform-setup/src/test/java/org/bonitasoft/platform/configuration/impl/ConfigurationServiceImplIT.java +++ b/platform/platform-setup/src/test/java/org/bonitasoft/platform/configuration/impl/ConfigurationServiceImplIT.java @@ -282,7 +282,7 @@ private void createTables() throws Exception { try (Connection connection = getConnection()) { ScriptUtils.executeSqlScript(connection, new EncodedResource(new InputStreamResource(createTableResource)), false, false, - DEFAULT_COMMENT_PREFIX, getDefaultStatementSeparator(), + DEFAULT_COMMENT_PREFIX, DEFAULT_STATEMENT_SEPARATOR, DEFAULT_BLOCK_COMMENT_START_DELIMITER, DEFAULT_BLOCK_COMMENT_END_DELIMITER); } } @@ -293,20 +293,11 @@ private void dropTables() throws Exception { try (Connection connection = getConnection()) { ScriptUtils.executeSqlScript(connection, new EncodedResource(new InputStreamResource(dropTablesResource)), true, true, - DEFAULT_COMMENT_PREFIX, getDefaultStatementSeparator(), + DEFAULT_COMMENT_PREFIX, DEFAULT_STATEMENT_SEPARATOR, DEFAULT_BLOCK_COMMENT_START_DELIMITER, DEFAULT_BLOCK_COMMENT_END_DELIMITER); } } - private String getDefaultStatementSeparator() { - switch (dbVendor) { - case "sqlserver": - return "GO"; - default: - return DEFAULT_STATEMENT_SEPARATOR; - } - } - private File createLicenseFolder() throws IOException { File licenses = temporaryFolder.newFolder("licenses"); Files.write(licenses.toPath().resolve("license1.lic"), "license 1 content".getBytes(UTF_8)); diff --git a/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/ConfigurationCheckerTest.java b/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/ConfigurationCheckerTest.java index ab2ff9c29c9..e5d6a02826c 100644 --- a/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/ConfigurationCheckerTest.java +++ b/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/ConfigurationCheckerTest.java @@ -32,6 +32,8 @@ */ public class ConfigurationCheckerTest { + private static final String TEST_DATASOURCE_CONFIG_DIR = "/datasource-config/"; + @Rule public TestRule clean = new ClearSystemProperties("db.admin.user", "sysprop.bonita.db.vendor", "db.user", "db.password", "db.vendor", "db.server.name=", @@ -52,7 +54,8 @@ public void validate_should_load_class_if_present() throws Exception { @Test public void validate_should_fail_to_load_class_if_not_found() throws Exception { final ConfigurationChecker configurationChecker = new ConfigurationChecker( - new PropertyLoader("/database.properties", "/missingDriverClass_internal.properties").loadProperties()); + new PropertyLoader(TEST_DATASOURCE_CONFIG_DIR + "database.properties", + TEST_DATASOURCE_CONFIG_DIR + "missingDriverClass_internal.properties").loadProperties()); configurationChecker.loadProperties(); expectedException.expect(PlatformException.class); @@ -64,9 +67,10 @@ public void validate_should_fail_to_load_class_if_not_found() throws Exception { @Test public void validate_should_fail_mandatory_property_is_not_set() throws Exception { final String dbVendor = "dbVendor"; - System.setProperty("sysprop.bonita.db.vendor", dbVendor); - final Properties propertiesWithMissingServerName = new PropertyLoader("/incomplete_database.properties") - .loadProperties(); + System.setProperty(PlatformSetup.BONITA_DB_VENDOR_PROPERTY, dbVendor); + final Properties propertiesWithMissingServerName = new PropertyLoader( + TEST_DATASOURCE_CONFIG_DIR + "incomplete_database.properties") + .loadProperties(); expectedException.expect(PlatformException.class); expectedException.expectMessage("Mandatory property"); @@ -77,7 +81,8 @@ public void validate_should_fail_mandatory_property_is_not_set() throws Exceptio @Test public void validate_should_fail_if_class_to_load_is_not_set() throws Exception { final ConfigurationChecker configurationChecker = new ConfigurationChecker( - new PropertyLoader("/database.properties", "/incomplete_internal.properties").loadProperties()); + new PropertyLoader(TEST_DATASOURCE_CONFIG_DIR + "database.properties", + TEST_DATASOURCE_CONFIG_DIR + "incomplete_internal.properties").loadProperties()); expectedException.expect(PlatformException.class); expectedException.expectMessage("Mandatory property 'postgres.nonXaDriver'"); diff --git a/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/PlatformSetupDistributionIT.java b/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/PlatformSetupDistributionIT.java index e7521d06081..f38a14eec8f 100644 --- a/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/PlatformSetupDistributionIT.java +++ b/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/PlatformSetupDistributionIT.java @@ -15,6 +15,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.bonitasoft.platform.setup.command.configure.BundleConfiguratorTest.checkFileContains; +import static org.junit.Assert.assertNotNull; import java.io.ByteArrayInputStream; import java.io.File; @@ -58,6 +59,11 @@ public class PlatformSetupDistributionIT { public void before() throws Exception { setupFolder = temporaryFolder.newFolder(); PlatformSetupTestUtils.extractDistributionTo(setupFolder); + if (!PlatformSetupTestUtils.isCommunityEdition(getClass())) { + // Tests executed in the subscription edition need a fake license file + Files.createFile(Paths.get(setupFolder.getAbsolutePath()).resolve("platform_conf").resolve("licenses") + .resolve("some.lic")); + } } @Test @@ -72,21 +78,21 @@ public void setupSh_should_work_with_init_on_h2_and_prevent_pushing_deletion() t int iExitValue = executor.execute(oCmdLine); //then - assertThat(iExitValue).isEqualTo(0); + assertThat(iExitValue).isZero(); Connection jdbcConnection = PlatformSetupTestUtils.getJdbcConnection(setupFolder); Statement statement = jdbcConnection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT COUNT(*) AS nb FROM CONFIGURATION"); resultSet.next(); - assertThat(resultSet.getInt("nb")).isGreaterThan(0); + assertThat(resultSet.getInt("nb")).isPositive(); oCmdLine = PlatformSetupTestUtils.createCommandLine(); oCmdLine.addArgument("pull"); iExitValue = executor.execute(oCmdLine); - assertThat(iExitValue).isEqualTo(0); + assertThat(iExitValue).isZero(); - final Path platform_engine = setupFolder.toPath().resolve("platform_conf").resolve("current") + final Path platformEngine = setupFolder.toPath().resolve("platform_conf").resolve("current") .resolve("platform_engine"); - FileUtils.deleteDirectory(platform_engine.toFile()); + FileUtils.deleteDirectory(platformEngine.toFile()); oCmdLine = PlatformSetupTestUtils.createCommandLine(); oCmdLine.addArgument("push"); @@ -97,7 +103,7 @@ public void setupSh_should_work_with_init_on_h2_and_prevent_pushing_deletion() t oCmdLine.addArgument("--force"); executor.setExitValue(0); iExitValue = executor.execute(oCmdLine); - assertThat(iExitValue).isEqualTo(0); + assertThat(iExitValue).isZero(); } @Test @@ -110,12 +116,12 @@ public void setupSh_should_work_with_init_on_h2_with_overridden_system_property( //when int iExitValue = executor.execute(oCmdLine); //then - assertThat(iExitValue).isEqualTo(0); + assertThat(iExitValue).isZero(); Connection jdbcConnection = PlatformSetupTestUtils.getJdbcConnection(setupFolder, "myUser"); Statement statement = jdbcConnection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT COUNT(*) AS nb FROM CONFIGURATION"); resultSet.next(); - assertThat(resultSet.getInt("nb")).isGreaterThan(0); + assertThat(resultSet.getInt("nb")).isPositive(); } @Test @@ -155,7 +161,7 @@ public void setupSh_should_work_on_postgres_database() throws Exception { Files.write(databaseProperties, out.toByteArray()); int iExitValue = executor.execute(oCmdLine); //then - assertThat(iExitValue).isEqualTo(0); + assertThat(iExitValue).isZero(); } finally { pgServer.shutdown(); } @@ -167,7 +173,9 @@ public void commandLine_should_support_H2_path_with_space_characters() throws Ex final File temporaryFolderRoot = temporaryFolder.newFolder(); Path bundleFolder = temporaryFolderRoot.toPath().toRealPath(); Path tomcatFolder = bundleFolder.resolve("server"); - PathUtils.copyDirectory(Paths.get("../resources/test/tomcat_conf/server").toAbsolutePath(), tomcatFolder); + var tomcatServerFolder = getClass().getResource("/tomcat_conf/server"); + assertNotNull(tomcatServerFolder); + PathUtils.copyDirectory(Paths.get(tomcatServerFolder.toURI()), tomcatFolder); final File newSetupFolder = bundleFolder.resolve("setup").toFile(); FileUtils.copyDirectory(setupFolder, newSetupFolder); //given diff --git a/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/PlatformSetupIT.java b/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/PlatformSetupIT.java index c594e39df07..5ec24b5f477 100644 --- a/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/PlatformSetupIT.java +++ b/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/PlatformSetupIT.java @@ -13,14 +13,14 @@ **/ package org.bonitasoft.platform.setup; +import static java.lang.System.lineSeparator; import static org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.*; import static org.bonitasoft.platform.configuration.type.ConfigurationType.PLATFORM_ENGINE; import static org.bonitasoft.platform.configuration.type.ConfigurationType.TENANT_TEMPLATE_PORTAL; import static org.bonitasoft.platform.setup.PlatformSetup.BONITA_SETUP_FOLDER; import static org.bonitasoft.platform.setup.PlatformSetup.PLATFORM_CONF_FOLDER_NAME; -import static org.junit.Assert.fail; -import static org.junit.Assume.assumeFalse; +import static org.junit.jupiter.api.Assumptions.assumeFalse; import java.io.File; import java.nio.charset.Charset; @@ -30,7 +30,7 @@ import java.util.Arrays; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import java.util.UUID; import org.apache.commons.io.FileUtils; import org.bonitasoft.platform.configuration.model.FullBonitaConfiguration; @@ -40,40 +40,28 @@ import org.bonitasoft.platform.setup.jndi.MemoryJNDISetup; import org.bonitasoft.platform.util.ConfigurationFolderUtil; import org.bonitasoft.platform.version.VersionService; -import org.junit.After; -import org.junit.Rule; -import org.junit.Test; -import org.junit.contrib.java.lang.system.ClearSystemProperties; -import org.junit.contrib.java.lang.system.SystemOutRule; -import org.junit.rules.ExpectedException; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.boot.test.system.OutputCaptureExtension; import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.jdbc.JdbcTestUtils; /** * @author Baptiste Mesta */ -@RunWith(SpringRunner.class) +@ExtendWith({ SpringExtension.class, OutputCaptureExtension.class }) @SpringBootTest(classes = { PlatformSetupApplication.class }) -public class PlatformSetupIT { - - private static final String LINE_SEPARATOR = System.getProperty("line.separator"); - - @Rule - public final ClearSystemProperties clearSystemProperties = new ClearSystemProperties(BONITA_SETUP_FOLDER); - - @Rule - public final SystemOutRule systemOutRule = new SystemOutRule().enableLog();//.muteForSuccessfulTests(); - - @Rule - public final ExpectedException expectedException = ExpectedException.none(); +class PlatformSetupIT { @Value("${db.vendor}") private String dbVendor; @@ -92,25 +80,24 @@ public class PlatformSetupIT { private final ConfigurationFolderUtil configurationFolderUtil = new ConfigurationFolderUtil(); - @After - public void after() throws Exception { + @BeforeEach + void setUp() throws Exception { System.clearProperty(BONITA_SETUP_FOLDER); platformSetup.destroy(); } - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); - @Test - public void init_method_should_init_table_and_insert_conf() throws Exception { + @Tag("community-only") + void init_method_should_init_table_and_insert_conf() throws Exception { //when platformSetup.init(); //then final Integer sequences = jdbcTemplate.queryForObject("select count(*) from sequence", Integer.class); assertThat(sequences).isGreaterThan(1); - final int platformRows = JdbcTestUtils.countRowsInTable(jdbcTemplate, "platform"); - assertThat(platformRows).isEqualTo(1); + final List platformRows = jdbcTemplate.queryForList("SELECT information FROM platform", String.class); + assertThat(platformRows).hasSize(1); + assertThat(platformRows.get(0)).isNotBlank(); // In Community, should contain the initial case counter value for information final int tenantRows = JdbcTestUtils.countRowsInTable(jdbcTemplate, "tenant"); assertThat(tenantRows).isEqualTo(1); final int configurationFiles = JdbcTestUtils.countRowsInTable(jdbcTemplate, "configuration"); @@ -118,78 +105,78 @@ public void init_method_should_init_table_and_insert_conf() throws Exception { } @Test - public void init_method_should_init_configuration_from_folder_if_exists() throws Exception { + void init_method_should_init_configuration_from_folder_if_exists(@TempDir Path setupFolder, + CapturedOutput capturedOutput) throws Exception { //given - File setupFolder = temporaryFolder.newFolder("conf"); - System.setProperty(BONITA_SETUP_FOLDER, setupFolder.getAbsolutePath()); - FileUtils.write(setupFolder.toPath().resolve(PLATFORM_CONF_FOLDER_NAME).resolve("initial") + System.setProperty(BONITA_SETUP_FOLDER, setupFolder.toAbsolutePath().toString()); + FileUtils.write(setupFolder.resolve(PLATFORM_CONF_FOLDER_NAME).resolve("initial") .resolve("platform_engine") .resolve("whatever.properties").toFile(), "custom content", Charset.defaultCharset()); - configurationFolderUtil.buildSqlFolder(setupFolder.toPath(), dbVendor); - systemOutRule.clearLog(); + configurationFolderUtil.buildSqlFolder(setupFolder, dbVendor); //when platformSetup.init(); //then List> rows = jdbcTemplate - .queryForList("SELECT * FROM CONFIGURATION WHERE resource_name = 'whatever.properties'"); + .queryForList("SELECT * FROM configuration WHERE resource_name = 'whatever.properties'"); assertThat(rows).hasSize(1); - assertThat(rows.get(0).get("resource_content")).isEqualTo("custom content".getBytes()); - assertThat(systemOutRule.getLog()) + assertThat(rows.get(0)).containsEntry("resource_content", "custom content".getBytes()); + assertThat(capturedOutput.getOut()) .contains("Database will be initialized with configuration files from folder: " - + setupFolder.toPath().resolve(PLATFORM_CONF_FOLDER_NAME).resolve("initial").toString()); + + setupFolder.resolve(PLATFORM_CONF_FOLDER_NAME).resolve("initial")); } @Test - public void init_method_should_store_tenant_portal_resources_from_classpath() throws Exception { + @Tag("community-only") + void init_method_should_store_tenant_portal_resources_from_classpath() throws Exception { //when platformSetup.init(); //then List> rows = jdbcTemplate - .queryForList("SELECT * FROM CONFIGURATION WHERE content_type= '" + .queryForList("SELECT * FROM configuration WHERE content_type= '" + ConfigurationType.TENANT_TEMPLATE_PORTAL + "' ORDER BY resource_name"); assertThat(rows).hasSize(9); int rowId = 0; - assertThat(rows.get(rowId++).get("RESOURCE_NAME")).isEqualTo("compound-permissions-mapping-custom.properties"); - assertThat(rows.get(rowId++).get("RESOURCE_NAME")) - .isEqualTo("compound-permissions-mapping-internal.properties"); - assertThat(rows.get(rowId++).get("RESOURCE_NAME")).isEqualTo("compound-permissions-mapping.properties"); - assertThat(rows.get(rowId++).get("RESOURCE_NAME")).isEqualTo("console-config.properties"); - assertThat(rows.get(rowId++).get("RESOURCE_NAME")).isEqualTo("custom-permissions-mapping.properties"); - assertThat(rows.get(rowId++).get("RESOURCE_NAME")).isEqualTo("resources-permissions-mapping-custom.properties"); - assertThat(rows.get(rowId++).get("RESOURCE_NAME")) - .isEqualTo("resources-permissions-mapping-internal.properties"); - assertThat(rows.get(rowId++).get("RESOURCE_NAME")).isEqualTo("resources-permissions-mapping.properties"); - assertThat(rows.get(rowId++).get("RESOURCE_NAME")).isEqualTo("security-config.properties"); + assertThat(rows.get(rowId++)).containsEntry("RESOURCE_NAME", "compound-permissions-mapping-custom.properties"); + assertThat(rows.get(rowId++)).containsEntry("RESOURCE_NAME", + "compound-permissions-mapping-internal.properties"); + assertThat(rows.get(rowId++)).containsEntry("RESOURCE_NAME", "compound-permissions-mapping.properties"); + assertThat(rows.get(rowId++)).containsEntry("RESOURCE_NAME", "console-config.properties"); + assertThat(rows.get(rowId++)).containsEntry("RESOURCE_NAME", "custom-permissions-mapping.properties"); + assertThat(rows.get(rowId++)).containsEntry("RESOURCE_NAME", "resources-permissions-mapping-custom.properties"); + assertThat(rows.get(rowId++)).containsEntry("RESOURCE_NAME", + "resources-permissions-mapping-internal.properties"); + assertThat(rows.get(rowId++)).containsEntry("RESOURCE_NAME", "resources-permissions-mapping.properties"); + assertThat(rows.get(rowId)).containsEntry("RESOURCE_NAME", "security-config.properties"); } @Test - public void init_method_should_store_platform_portal_resources_from_classpath() throws Exception { + void init_method_should_store_platform_portal_resources_from_classpath() throws Exception { //when platformSetup.init(); //then List> rows = jdbcTemplate - .queryForList("SELECT * FROM CONFIGURATION WHERE content_type= '" + ConfigurationType.PLATFORM_PORTAL + .queryForList("SELECT * FROM configuration WHERE content_type= '" + ConfigurationType.PLATFORM_PORTAL + "' ORDER BY resource_name"); assertThat(rows).hasSize(3); - assertThat(rows.get(0).get("RESOURCE_NAME")).isEqualTo("cache-config.xml"); - assertThat(rows.get(1).get("RESOURCE_NAME")).isEqualTo("platform-tenant-config.properties"); - assertThat(rows.get(2).get("RESOURCE_NAME")).isEqualTo("security-config.properties"); + assertThat(rows.get(0)).containsEntry("RESOURCE_NAME", "cache-config.xml"); + assertThat(rows.get(1)).containsEntry("RESOURCE_NAME", "platform-tenant-config.properties"); + assertThat(rows.get(2)).containsEntry("RESOURCE_NAME", "security-config.properties"); } @Test - public void should_extract_configuration() throws Exception { - final File destinationFolder = temporaryFolder.newFolder("setup"); + @Tag("community-only") + void should_extract_configuration(@TempDir Path setupFolder) throws Exception { //given platformSetup.init(); //when - System.setProperty(BONITA_SETUP_FOLDER, destinationFolder.getAbsolutePath()); + System.setProperty(BONITA_SETUP_FOLDER, setupFolder.toAbsolutePath().toString()); platformSetup.pull(); //then - File folderContainingResultOfGet = destinationFolder.toPath().resolve(PLATFORM_CONF_FOLDER_NAME) + File folderContainingResultOfGet = setupFolder.resolve(PLATFORM_CONF_FOLDER_NAME) .resolve("current").toFile(); assertThat(folderContainingResultOfGet).as("should retrieve config files") .exists() @@ -198,7 +185,7 @@ public void should_extract_configuration() throws Exception { List configurations = new ArrayList<>(); AllConfigurationResourceVisitor allConfigurationResourceVisitor = new AllConfigurationResourceVisitor( configurations); - Files.walkFileTree(destinationFolder.toPath(), allConfigurationResourceVisitor); + Files.walkFileTree(setupFolder, allConfigurationResourceVisitor); assertThat(configurations).extracting("resourceName").containsOnly( "bonita-platform-community-custom.properties", @@ -219,122 +206,112 @@ public void should_extract_configuration() throws Exception { } @Test - public void init_method_should_log_when_created() throws Exception { + void init_method_should_log_when_created(CapturedOutput capturedOutput) throws Exception { //given assertThat(platformSetup.isPlatformAlreadyCreated()).isFalse(); //when - systemOutRule.clearLog(); platformSetup.init(); //then assertThat(platformSetup.isPlatformAlreadyCreated()).isTrue(); - final String log = systemOutRule.getLogWithNormalizedLineSeparator(); - assertThat(log).as("should setup log message").doesNotContain("Platform is already created. Nothing to do."); - assertThat(log).contains("Platform created.") + assertThat(capturedOutput.getOut()).as("should setup log message") + .doesNotContain("Platform is already created. Nothing to do.") + .contains("Platform created.") .contains("Initial configuration files successfully pushed to database"); } @Test - public void init_method_should_upgrade_default_configuration_when_already_created() throws Exception { + void init_method_should_upgrade_default_configuration_when_already_created(CapturedOutput capturedOutput) + throws Exception { //given platformSetup.init(); //when - systemOutRule.clearLog(); platformSetup.init(); //then assertThat(platformSetup.isPlatformAlreadyCreated()).isTrue(); - final String log = systemOutRule.getLogWithNormalizedLineSeparator(); - assertThat(log).doesNotContain("Platform created."); - assertThat(log).contains("Platform is already created."); - assertThat(log).contains("Upgrading default configuration"); - + assertThat(capturedOutput.getOut()) + .containsOnlyOnce("Platform created.") + .containsOnlyOnce("Platform is already created.") + .containsOnlyOnce("Upgrading default configuration"); } @Test - public void push_method_should_log_when_created_and_create_backup() throws Exception { + void push_method_should_log_when_created_and_create_backup(@TempDir File setupFolder, + CapturedOutput capturedOutput) throws Exception { // given platformSetup.init(); - File setupFolder = temporaryFolder.newFolder("conf"); System.setProperty(BONITA_SETUP_FOLDER, setupFolder.getAbsolutePath()); configurationFolderUtil.buildCurrentFolder(setupFolder.toPath()); // when - systemOutRule.clearLog(); platformSetup.forcePush(); // then assertThat(setupFolder.listFiles()).hasSize(1); - List backupDirectory = Arrays.stream(setupFolder.listFiles()[0].listFiles()) - .filter(it -> it.getName().contains("backup")).collect(Collectors.toList()); + List backupDirectory = Arrays.stream(setupFolder.listFiles()[0].listFiles()) + .filter(it -> it.getName().contains("backup")).toList(); assertThat(backupDirectory).hasSize(1); - final String log = systemOutRule.getLogWithNormalizedLineSeparator(); - assertThat(log).contains("Backup directory created:"); - final String[] split = log.split("\n"); - assertThat(split[split.length - 1]).as("should push new configuration and log message").contains("INFO") - .endsWith( - "Configuration files successfully pushed to database. You can now restart Bonita to reflect your changes."); + assertThat(capturedOutput.getOut()) + .contains("Backup directory created:") + .as("should push new configuration and log message") + .contains("Configuration files successfully pushed to database. " + + "You can now restart Bonita to reflect your changes."); } @Test - public void push_should_fail_if_required_folder_would_be_deleted() throws Exception { + void push_should_fail_if_required_folder_would_be_deleted(@TempDir Path temporaryFolder) throws Exception { // on windows, the test fails to delete the 'platform init engine' directory // so do not run it for now assumeFalse(IS_OS_WINDOWS); // given platformSetup.init(); - File setupFolder = temporaryFolder.newFolder("conf"); - System.setProperty(BONITA_SETUP_FOLDER, setupFolder.getAbsolutePath()); + Path setupFolder = Files.createDirectory(temporaryFolder.resolve("conf")); + System.setProperty(BONITA_SETUP_FOLDER, setupFolder.toAbsolutePath().toString()); platformSetup.pull(); - final Path platform_engine = setupFolder.toPath().resolve("platform_conf").resolve("current") + final Path platformEngine = setupFolder.resolve("platform_conf").resolve("current") .resolve("platform_engine"); - FileUtils.deleteDirectory(platform_engine.toFile()); - - // then - expectedException.expect(PlatformException.class); - expectedException.expectMessage("You are trying to remove a protected folder from configuration"); - expectedException.expectMessage(platform_engine.toString()); - expectedException.expectMessage("To restore the deleted folders"); - - // when - platformSetup.push(); + FileUtils.deleteDirectory(platformEngine.toFile()); + + // when - then + assertThatExceptionOfType(PlatformException.class) + .isThrownBy(platformSetup::push) + .withMessageStartingWith("You are trying to remove a protected folder from configuration") + .withMessageContaining(platformEngine.toString()) + .withMessageContaining("To restore the deleted folders"); } @Test - public void push_should_throw_exception_when_platform_is_not_created() throws Exception { + void push_should_throw_exception_when_platform_is_not_created() { //given assertThat(platformSetup.isPlatformAlreadyCreated()).isFalse(); - //expect - expectedException.expect(PlatformException.class); - expectedException.expectMessage("Platform is not created. Run 'setup init' first."); - - //when - platformSetup.push(); + // when - then + assertThatExceptionOfType(PlatformException.class) + .isThrownBy(platformSetup::push) + .withMessage("Platform is not created. Run 'setup init' first."); } @Test - public void clean_method_should_delete_and_log() throws Exception { + void clean_method_should_delete_and_log(@TempDir Path temporaryFolder, CapturedOutput capturedOutput) + throws Exception { //given - final Path path = temporaryFolder.newFolder("afterClean").toPath(); - final Path licensePath = temporaryFolder.newFolder("licenses").toPath(); + final Path path = Files.createDirectory(temporaryFolder.resolve("afterClean")); + final Path licensePath = Files.createDirectory(temporaryFolder.resolve("licenses")); platformSetup.init(); //when - systemOutRule.clearLog(); platformSetup.clean(); //then - final String log = systemOutRule.getLogWithNormalizedLineSeparator(); - final String[] split = log.split("\n"); - assertThat(split).as("should log message").isNotEmpty(); - assertThat(split[split.length - 1]).as("should log message").contains("DEBUG") - .endsWith("Execute DeleteAllConfigurationInTransaction transaction."); + assertThat(capturedOutput.getOut()).as("should log message") + .isNotEmpty() + .contains("Execute DeleteAllConfigurationInTransaction transaction."); platformSetup.pull(path, licensePath); List configurations = new ArrayList<>(); @@ -346,13 +323,13 @@ public void clean_method_should_delete_and_log() throws Exception { } @Test - public void push_method_should_clean_previous_config() throws Exception { + void push_method_should_clean_previous_config(@TempDir Path temporaryFolder) throws Exception { //given List configurations = new ArrayList<>(); - final Path initPath = temporaryFolder.newFolder("init").toPath(); - final Path pushPath = temporaryFolder.newFolder("push").toPath(); - final Path checkPath = temporaryFolder.newFolder("check").toPath(); - final Path licensesPath = temporaryFolder.newFolder("lic").toPath(); + final Path initPath = Files.createDirectory(temporaryFolder.resolve("init")); + final Path pushPath = Files.createDirectory(temporaryFolder.resolve("push")); + final Path checkPath = Files.createDirectory(temporaryFolder.resolve("check")); + final Path licensesPath = Files.createDirectory(temporaryFolder.resolve("lic")); FileUtils.writeByteArrayToFile( initPath.resolve(PLATFORM_CONF_FOLDER_NAME).resolve("initial") @@ -382,10 +359,10 @@ public void push_method_should_clean_previous_config() throws Exception { } @Test - public void push_method_should_throw_exception_if_no_current_folder() throws Exception { + void push_method_should_throw_exception_if_no_current_folder(@TempDir Path temporaryFolder) throws Exception { //given List configurations = new ArrayList<>(); - final Path confFolder = temporaryFolder.newFolder().toPath(); + final Path confFolder = Files.createDirectory(temporaryFolder.resolve(UUID.randomUUID().toString())); configurationFolderUtil.buildPlatformEngineFolder(confFolder); configurationFolderUtil.buildSqlFolder(confFolder, dbVendor); @@ -393,20 +370,13 @@ public void push_method_should_throw_exception_if_no_current_folder() throws Exc platformSetup.init(); Path current = confFolder.resolve("platform_conf").resolve("current"); - //when - try { - platformSetup.push(); - fail(); - } catch (PlatformException ignored) { - assertThat(ignored.getMessage()).isEqualTo("Unable to push configuration from " + - current + - ", as directory does not exists. To modify your configuration, run 'setup pull', update your configuration files from " - + - current + - " folder, and then push your new configuration."); - //ok - } - //then + //when - then + assertThatExceptionOfType(PlatformException.class).isThrownBy(platformSetup::push) + .withMessage("Unable to push configuration from %1$s, as directory does not exists. " + + "To modify your configuration, run 'setup pull', " + + "update your configuration files from %1$s folder, " + + "and then push your new configuration.", current); + platformSetup.pull(); Files.walkFileTree(current, new AllConfigurationResourceVisitor(configurations)); assertThat(configurations).as("should have kept old files").hasSize(1) @@ -414,113 +384,107 @@ public void push_method_should_throw_exception_if_no_current_folder() throws Exc } @Test - public void should_push_check_platform_version() throws Exception { + void should_push_check_platform_version(@TempDir Path temporaryFolder) throws Exception { //given platformSetup.init(); jdbcTemplate.execute("UPDATE platform SET version='bad version'"); - //then - expectedException.expect(PlatformException.class); - expectedException.expectMessage( - "The version of the platform (binaries) you are running [" + versionService.getPlatformSetupVersion() + - "] only support database schema in version [" + final Path confFolder = Files.createDirectory(temporaryFolder.resolve(UUID.randomUUID().toString())); + configurationFolderUtil.buildCurrentFolder(confFolder); + System.setProperty(BONITA_SETUP_FOLDER, confFolder.toFile().getAbsolutePath()); + + // when - then + assertThatExceptionOfType(PlatformException.class) + .isThrownBy(platformSetup::push) + .withMessage("The version of the platform (binaries) you are running [" + + versionService.getPlatformSetupVersion() + "] only support database schema in version [" + versionService.getSupportedDatabaseSchemaVersion() + "]" + " but the current database schema version is [bad version]." + " You might need to migrate your platform or use a different version of the binaries."); - - //when - final Path confFolder = temporaryFolder.newFolder().toPath(); - configurationFolderUtil.buildCurrentFolder(confFolder); - System.setProperty(BONITA_SETUP_FOLDER, confFolder.toFile().getAbsolutePath()); - platformSetup.push(); } @Test - public void should_pull_check_platform_version() throws Exception { + void should_pull_check_platform_version() throws Exception { //given platformSetup.init(); jdbcTemplate.execute("UPDATE platform SET version='bad version'"); - //then - expectedException.expect(PlatformException.class); - expectedException.expectMessage( - "The version of the platform (binaries) you are running [" + versionService.getPlatformSetupVersion() + - "] only support database schema in version [" + // when - then + assertThatExceptionOfType(PlatformException.class) + .isThrownBy(platformSetup::pull) + .withMessage("The version of the platform (binaries) you are running [" + + versionService.getPlatformSetupVersion() + "] only support database schema in version [" + versionService.getSupportedDatabaseSchemaVersion() + "]" + " but the current database schema version is [bad version]." + " You might need to migrate your platform or use a different version of the binaries."); - - //when - platformSetup.pull(); - } @Test - public void pushLicences_should_pass_if_licence_folder_does_not_exists() throws Exception { + void pushLicences_should_pass_if_licence_folder_does_not_exists() throws Exception { platformSetup.initProperties(); - platformSetup.preventFromPushingZeroLicense(); + assertThatNoException().isThrownBy(platformSetup::preventFromPushingZeroLicense); } @Test - public void should_not_fail_when_pulling_twice_in_the_same_jvm() throws Exception { - final Path setupFolder = temporaryFolder.newFolder().toPath(); + void should_not_fail_when_pulling_twice_in_the_same_jvm(@TempDir Path temporaryFolder) throws Exception { + final Path setupFolder = Files.createDirectory(temporaryFolder.resolve(UUID.randomUUID().toString())); System.setProperty(BONITA_SETUP_FOLDER, setupFolder.toString()); configurationFolderUtil.buildPlatformEngineFolder(setupFolder); configurationFolderUtil.buildSqlFolder(setupFolder, dbVendor); platformSetup.init(); platformSetup.pull(); - platformSetup.pull(); + assertThatNoException().isThrownBy(platformSetup::pull); } @Test - public void pushLicences_should_fail_if_licence_folder_exists_but_is_empty() throws Exception { - final Path setupFolder = temporaryFolder.newFolder().toPath(); + void pushLicences_should_fail_if_licence_folder_exists_but_is_empty(@TempDir Path temporaryFolder) + throws Exception { + final Path setupFolder = Files.createDirectory(temporaryFolder.resolve(UUID.randomUUID().toString())); System.setProperty(BONITA_SETUP_FOLDER, setupFolder.toString()); - final Path platform_conf = configurationFolderUtil.buildPlatformConfFolder(setupFolder); + final Path platformConf = configurationFolderUtil.buildPlatformConfFolder(setupFolder); - final Path licenseFolder = platform_conf.resolve("licenses"); + final Path licenseFolder = platformConf.resolve("licenses"); Files.createDirectories(licenseFolder); - expectedException.expect(PlatformException.class); - expectedException - .expectMessage("No license (.lic file) found." + LINE_SEPARATOR - + "This would prevent Bonita Platform subscription edition" - + " to start normally." + LINE_SEPARATOR + "Place your license file"); - platformSetup.initProperties(); - platformSetup.preventFromPushingZeroLicense(); + + assertThatExceptionOfType(PlatformException.class) + .isThrownBy(platformSetup::preventFromPushingZeroLicense) + .withMessageStartingWith("No license (.lic file) found." + lineSeparator() + + "This would prevent Bonita Platform subscription edition" + + " to start normally." + lineSeparator() + "Place your license file"); } @Test - public void pushLicences_should_fail_if_no_license_file_with_lic_extension_exists() throws Exception { - final Path setupFolder = temporaryFolder.newFolder().toPath(); + void pushLicences_should_fail_if_no_license_file_with_lic_extension_exists(@TempDir Path temporaryFolder) + throws Exception { + final Path setupFolder = Files.createDirectory(temporaryFolder.resolve(UUID.randomUUID().toString())); System.setProperty(BONITA_SETUP_FOLDER, setupFolder.toString()); - final Path platform_conf = configurationFolderUtil.buildPlatformConfFolder(setupFolder); + final Path platformConf = configurationFolderUtil.buildPlatformConfFolder(setupFolder); - final Path licenseFolder = platform_conf.resolve("licenses"); + final Path licenseFolder = platformConf.resolve("licenses"); Files.createDirectories(licenseFolder); Files.createFile(licenseFolder.resolve("bonita-file.renamed")); - expectedException.expect(PlatformException.class); - expectedException - .expectMessage("No license (.lic file) found." + LINE_SEPARATOR - + "This would prevent Bonita Platform subscription edition" - + " to start normally." + LINE_SEPARATOR + "Place your license file"); - platformSetup.initProperties(); - platformSetup.preventFromPushingZeroLicense(); + + assertThatExceptionOfType(PlatformException.class) + .isThrownBy(platformSetup::preventFromPushingZeroLicense) + .withMessageStartingWith("No license (.lic file) found." + lineSeparator() + + "This would prevent Bonita Platform subscription edition" + + " to start normally." + lineSeparator() + "Place your license file"); } @Test - public void init_method_should_update_configuration_files() throws Exception { + void init_method_should_update_configuration_files(@TempDir Path temporaryFolder) throws Exception { //given - File setupFolder = temporaryFolder.newFolder("conf"); - System.setProperty(BONITA_SETUP_FOLDER, setupFolder.getAbsolutePath()); - final File permissionFile = setupFolder.toPath().resolve(PLATFORM_CONF_FOLDER_NAME).resolve("initial") + Path setupFolder = Files.createDirectory(temporaryFolder.resolve("conf")); + System.setProperty(BONITA_SETUP_FOLDER, setupFolder.toAbsolutePath().toString()); + final File permissionFile = setupFolder.resolve(PLATFORM_CONF_FOLDER_NAME).resolve("initial") .resolve("tenant_template_portal") .resolve("resources-permissions-mapping.properties").toFile(); FileUtils.write(permissionFile, "default 7.5.4 content", Charset.defaultCharset()); - configurationFolderUtil.buildSqlFolder(setupFolder.toPath(), dbVendor); + configurationFolderUtil.buildSqlFolder(setupFolder, dbVendor); platformSetup.init(); // Simulate new 7.6.0 configuration file content: @@ -533,16 +497,16 @@ public void init_method_should_update_configuration_files() throws Exception { //then List> rows = jdbcTemplate .queryForList( - "SELECT * FROM CONFIGURATION WHERE resource_name = 'resources-permissions-mapping.properties'"); + "SELECT * FROM configuration WHERE resource_name = 'resources-permissions-mapping.properties'"); assertThat(rows).hasSize(2) - .allSatisfy(row -> assertThat(row.get("RESOURCE_CONTENT")).isEqualTo(new_7_6_0_content.getBytes())); + .allSatisfy(row -> assertThat(row).containsEntry("RESOURCE_CONTENT", new_7_6_0_content.getBytes())); } @Test - public void init_on_existing_platform_should_add_new_config_files() throws Exception { + void init_on_existing_platform_should_add_new_config_files(CapturedOutput capturedOutput) throws Exception { //given platformSetup.init(); - final String countConfigFile = "SELECT * FROM CONFIGURATION WHERE resource_name = 'bonita-tenant-community-custom.properties'"; + final String countConfigFile = "SELECT * FROM configuration WHERE resource_name = 'bonita-tenant-community-custom.properties'"; assertThat(jdbcTemplate.queryForList(countConfigFile)).hasSize(2) .anyMatch(map -> map.get("CONTENT_TYPE").equals("TENANT_ENGINE")) .anyMatch(map -> map.get("CONTENT_TYPE").equals("TENANT_TEMPLATE_ENGINE")); @@ -552,7 +516,6 @@ public void init_on_existing_platform_should_add_new_config_files() throws Excep .update("DELETE from configuration WHERE resource_name = 'bonita-tenant-community-custom.properties'"); assertThat(jdbcTemplate.queryForList(countConfigFile)).isEmpty(); - systemOutRule.clearLog(); //when platformSetup.init(); @@ -561,7 +524,7 @@ public void init_on_existing_platform_should_add_new_config_files() throws Excep assertThat(jdbcTemplate.queryForList(countConfigFile)).hasSize(2) .anyMatch(map -> map.get("CONTENT_TYPE").equals("TENANT_ENGINE")) .anyMatch(map -> map.get("CONTENT_TYPE").equals("TENANT_TEMPLATE_ENGINE")); - assertThat(systemOutRule.getLog()).contains( - "New configuration file detected 'bonita-tenant-community-custom.properties'"); + assertThat(capturedOutput.getOut()) + .contains("New configuration file detected 'bonita-tenant-community-custom.properties'"); } } diff --git a/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/PlatformSetupTest.java b/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/PlatformSetupTest.java index 45cccdacf16..a1ba8bd9aa0 100644 --- a/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/PlatformSetupTest.java +++ b/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/PlatformSetupTest.java @@ -14,8 +14,8 @@ package org.bonitasoft.platform.setup; import static org.apache.commons.io.FilenameUtils.separatorsToSystem; -import static org.assertj.core.api.Assertions.assertThat; -import static org.bonitasoft.platform.setup.PlatformSetup.BONITA_SETUP_FOLDER; +import static org.assertj.core.api.Assertions.*; +import static org.bonitasoft.platform.setup.PlatformSetup.*; import static org.mockito.Mockito.*; import java.nio.file.Files; @@ -29,6 +29,7 @@ import org.bonitasoft.platform.configuration.ConfigurationService; import org.bonitasoft.platform.configuration.model.BonitaConfiguration; import org.bonitasoft.platform.configuration.model.LightBonitaConfiguration; +import org.bonitasoft.platform.database.DatabaseVendor; import org.bonitasoft.platform.exception.PlatformException; import org.bonitasoft.platform.util.ConfigurationFolderUtil; import org.bonitasoft.platform.version.VersionService; @@ -36,13 +37,13 @@ import org.junit.Rule; import org.junit.Test; import org.junit.contrib.java.lang.system.RestoreSystemProperties; -import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; import org.junit.rules.TestRule; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.test.util.ReflectionTestUtils; /** * @author Baptiste Mesta @@ -65,10 +66,8 @@ public class PlatformSetupTest { @InjectMocks private PlatformSetup platformSetup; - private ConfigurationFolderUtil configurationFolderUtil = new ConfigurationFolderUtil(); + private final ConfigurationFolderUtil configurationFolderUtil = new ConfigurationFolderUtil(); - @Rule - public ExpectedException expectedException = ExpectedException.none(); @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); @Rule @@ -76,34 +75,138 @@ public class PlatformSetupTest { @Before public void before() throws Exception { + setPlatformSetupDbVendor(DatabaseVendor.H2.getValue()); + setPlatformSetupBdmDbVendor(DatabaseVendor.H2.getValue()); doReturn(connection).when(dataSource).getConnection(); doReturn(metaData).when(connection).getMetaData(); } + private void setPlatformSetupDbVendor(String dbVendor) { + ReflectionTestUtils.setField(platformSetup, "dbVendor", dbVendor); + } + + private void setPlatformSetupBdmDbVendor(String bdmDbVendor) { + ReflectionTestUtils.setField(platformSetup, "bdmDbVendor", bdmDbVendor); + } + @Test public void should_not_check_license_if_platform_already_init() throws Exception { final Path setupFolder = temporaryFolder.newFolder().toPath(); System.setProperty(BONITA_SETUP_FOLDER, setupFolder.toString()); - final Path platform_conf = configurationFolderUtil.buildPlatformConfFolder(setupFolder); - final Path licenseFolder = platform_conf.resolve("licenses"); + final Path platformConf = configurationFolderUtil.buildPlatformConfFolder(setupFolder); + final Path licenseFolder = platformConf.resolve("licenses"); Files.createDirectories(licenseFolder); doReturn(true).when(scriptExecutor).isPlatformAlreadyCreated(); //no exception - platformSetup.init(); + assertThatNoException().isThrownBy(platformSetup::init); } @Test public void should_fail_if_init_with_no_license() throws Exception { final Path setupFolder = temporaryFolder.newFolder().toPath(); System.setProperty(BONITA_SETUP_FOLDER, setupFolder.toString()); - final Path platform_conf = configurationFolderUtil.buildPlatformConfFolder(setupFolder); - final Path licenseFolder = platform_conf.resolve("licenses"); + final Path platformConf = configurationFolderUtil.buildPlatformConfFolder(setupFolder); + final Path licenseFolder = platformConf.resolve("licenses"); Files.createDirectories(licenseFolder); - expectedException.expect(PlatformException.class); - expectedException.expectMessage("No license (.lic file) found"); - platformSetup.init(); + assertThatExceptionOfType(PlatformException.class) + .isThrownBy(platformSetup::init) + .withMessageStartingWith("No license (.lic file) found."); + } + + @Test + public void should_fail_if_init_with_incorrect_database_vendor() { + //given + String dbVendor = "foobar"; + setPlatformSetupDbVendor(dbVendor); + + //when - then + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(platformSetup::init) + .withMessage("Unknown database vendor: %s", dbVendor); + } + + @Test + public void should_fail_if_init_with_incorrect_bdm_database_vendor() { + //given + String dbVendor = "foobar"; + setPlatformSetupBdmDbVendor(dbVendor); + + //when - then + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(platformSetup::init) + .withMessage("Unknown database vendor: %s", dbVendor); + } + + @Test + public void should_fail_if_init_with_unsupported_database_vendor() { + //given + DatabaseVendor dbVendor = DatabaseVendor.ORACLE; + setPlatformSetupDbVendor(dbVendor.getValue()); + + //when - then + assertThatExceptionOfType(PlatformException.class) + .isThrownBy(platformSetup::init) + .withMessage("Database vendor '%s' is not supported with the community edition", dbVendor); + } + + @Test + public void should_fail_if_init_with_unsupported_bdm_database_vendor() { + //given + DatabaseVendor dbVendor = DatabaseVendor.ORACLE; + setPlatformSetupBdmDbVendor(dbVendor.getValue()); + + //when - then + assertThatExceptionOfType(PlatformException.class) + .isThrownBy(platformSetup::init) + .withMessage("Database vendor '%s' is not supported with the community edition", dbVendor); + } + + @Test + public void should_not_fail_if_init_with_postgres_database_vendor() { + //given + setPlatformSetupDbVendor(DatabaseVendor.POSTGRES.getValue()); + + //when - then + assertThatNoException().isThrownBy(platformSetup::init); + } + + @Test + public void should_not_fail_if_init_with_postgres_bdm_database_vendor() { + //given + setPlatformSetupBdmDbVendor(DatabaseVendor.POSTGRES.getValue()); + + //when - then + assertThatNoException().isThrownBy(platformSetup::init); + } + + @Test + public void should_init_dbVendor_with_system_prop_if_null() throws Exception { + //given + setPlatformSetupDbVendor(null); + DatabaseVendor dbVendor = DatabaseVendor.POSTGRES; + System.setProperty(BONITA_DB_VENDOR_PROPERTY, dbVendor.getValue()); + + //when + platformSetup.initProperties(); + + //then + assertThat(platformSetup.dbVendor).isEqualTo(dbVendor.getValue()); + } + + @Test + public void should_init_bdmDbVendor_with_system_prop_if_null() throws Exception { + //given + setPlatformSetupBdmDbVendor(null); + DatabaseVendor dbVendor = DatabaseVendor.POSTGRES; + System.setProperty(BONITA_BDM_DB_VENDOR_PROPERTY, dbVendor.getValue()); + + //when + platformSetup.initProperties(); + + //then + assertThat(platformSetup.bdmDbVendor).isEqualTo(dbVendor.getValue()); } @Test @@ -150,8 +253,7 @@ public void getFolderFromConfiguration_should_work_for_platform_level_folder() t final Path folder = platformSetup.getFolderFromConfiguration(configuration); // then: - assertThat(folder.toString()) - .isEqualTo(separatorsToSystem(setupFolder.toString() + "/platform_conf/current/some_folder")); + assertThat(folder).hasToString(separatorsToSystem(setupFolder + "/platform_conf/current/some_folder")); } @Test @@ -167,7 +269,7 @@ public void getFolderFromConfiguration_should_work_for_tenant_level_folder() thr final Path folder = platformSetup.getFolderFromConfiguration(configuration); // then: - assertThat(folder.toString()).isEqualTo(separatorsToSystem(setupFolder.toString() + - "/platform_conf/current/tenants/2/tenant-level-folder")); + assertThat(folder) + .hasToString(separatorsToSystem(setupFolder + "/platform_conf/current/tenants/2/tenant-level-folder")); } } diff --git a/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/ScriptExecutorIT.java b/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/ScriptExecutorIT.java index 7bacf64c3ee..94027a6ac71 100644 --- a/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/ScriptExecutorIT.java +++ b/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/ScriptExecutorIT.java @@ -13,7 +13,7 @@ **/ package org.bonitasoft.platform.setup; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.*; import static org.bonitasoft.platform.setup.PlatformSetup.BONITA_SETUP_FOLDER; import static org.bonitasoft.platform.setup.PlatformSetup.PLATFORM_CONF_FOLDER_NAME; import static org.bonitasoft.platform.setup.ScriptExecutor.FAIL_ON_ERROR; @@ -29,7 +29,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.contrib.java.lang.system.ClearSystemProperties; -import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; import org.junit.rules.TestRule; import org.junit.runner.RunWith; @@ -67,9 +66,6 @@ public class ScriptExecutorIT { @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Before public void before() throws Exception { removeSetupFolderProperty(); @@ -95,15 +91,15 @@ public void should_be_able_to_create_platform_tables() throws Exception { assertThat(platformRows).isEqualTo(1); final Map rowPlatform = jdbcTemplate.queryForMap("select * from platform"); assertThat("" + rowPlatform.get("id")).isEqualTo("1"); // convert to String as not all RDBMS convert the same way (long, int, bigDecimal...) - assertThat(rowPlatform.get("created_by")).isEqualTo("platformAdmin"); + assertThat(rowPlatform).containsEntry("created_by", "platformAdmin"); final Map rowTenant = jdbcTemplate.queryForMap("select * from tenant"); assertThat("" + rowTenant.get("id")).isEqualTo("1"); // convert to String as not all RDBMS convert the same way (long, int, bigDecimal...) - assertThat(rowTenant.get("createdBy")).isEqualTo("defaultUser"); + assertThat(rowTenant).containsEntry("createdBy", "defaultUser"); } @Test - public void should_executeSQLResource_use_filesystem() throws Exception { + public void executeSQLResource_should_be_successful_using_filesystem_scripts() throws Exception { //given final File confFolder = temporaryFolder.newFolder(); final Path createTableScript = confFolder.toPath().resolve(PLATFORM_CONF_FOLDER_NAME).resolve("sql") @@ -111,42 +107,30 @@ public void should_executeSQLResource_use_filesystem() throws Exception { final Path dropTableScript = confFolder.toPath().resolve(PLATFORM_CONF_FOLDER_NAME).resolve("sql") .resolve(dbVendor).resolve("cleanup.sql"); Files.createDirectories(createTableScript.getParent()); - final String createTable = "CREATE TABLE " + - dbVendor + - "_configuration (" + - " tenant_id BIGINT NOT NULL," + - " content_type VARCHAR(50) NOT NULL," + - " resource_name VARCHAR(120) NOT NULL," + - " resource_content LONGBLOB NOT NULL" + - ")"; + final String tableName = dbVendor + "_test"; + final String createTable = "CREATE TABLE " + tableName + " (id INT NOT NULL)"; Files.write(createTableScript, createTable.getBytes()); - Files.write(dropTableScript, ("DROP TABLE " + dbVendor + "_configuration").getBytes()); + Files.write(dropTableScript, ("DROP TABLE " + tableName).getBytes()); System.setProperty(BONITA_SETUP_FOLDER, confFolder.getAbsolutePath()); - //when - scriptExecutor.executeSQLResource("myScript.sql", FAIL_ON_ERROR); - - //then - final int platformRows = JdbcTestUtils.countRowsInTable(jdbcTemplate, dbVendor + - "_configuration"); - scriptExecutor.executeSQLResource("cleanup.sql", FAIL_ON_ERROR); - assertThat(platformRows).as("should create empty table from filesystem ").isEqualTo(0); + //when - then + assertThatNoException().isThrownBy(() -> scriptExecutor.executeSQLResource("myScript.sql", FAIL_ON_ERROR)); + final int platformRows = JdbcTestUtils.countRowsInTable(jdbcTemplate, tableName); + assertThatNoException().isThrownBy(() -> scriptExecutor.executeSQLResource("cleanup.sql", FAIL_ON_ERROR)); + assertThat(platformRows).as("should create empty table from filesystem ").isZero(); } @Test - public void should_executeSQLResource_fail_when_script_is_missing() throws Exception { + public void executeSQLResource_should_fail_when_script_is_missing() throws Exception { //given final File confFolder = temporaryFolder.newFolder(); final Path sqlScript = confFolder.toPath().resolve(PLATFORM_CONF_FOLDER_NAME).resolve("sql").resolve(dbVendor) .resolve("missingScript.sql"); System.setProperty(BONITA_SETUP_FOLDER, confFolder.getAbsolutePath()); - //expect - expectedException.expect(RuntimeException.class); - expectedException - .expectMessage("SQL resource file not found in filesystem: " + sqlScript.toFile().getAbsolutePath()); - - //when - scriptExecutor.executeSQLResource("missingScript.sql", FAIL_ON_ERROR); + //when - then + assertThatExceptionOfType(RuntimeException.class) + .isThrownBy(() -> scriptExecutor.executeSQLResource("missingScript.sql", FAIL_ON_ERROR)) + .withMessage("SQL resource file not found in filesystem: " + sqlScript.toFile().getAbsolutePath()); } } diff --git a/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/ScriptExecutorTest.java b/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/ScriptExecutorTest.java index 987a7eb27f4..437b329a215 100644 --- a/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/ScriptExecutorTest.java +++ b/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/ScriptExecutorTest.java @@ -15,29 +15,21 @@ import static org.mockito.Mockito.*; -import org.bonitasoft.platform.setup.jndi.MemoryJNDISetup; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.junit4.SpringRunner; /** * author Emmanuel Duchastenier */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = { - PlatformSetupApplication.class -}) +@SpringBootTest(classes = PlatformSetupApplication.class, + // use an in-memory h2 database for those tests + properties = "h2.url=jdbc:h2:mem:${db.database.name}") public class ScriptExecutorTest { - @Autowired - MemoryJNDISetup memoryJNDISetup; - - @Autowired - JdbcTemplate jdbcTemplate; - @Autowired private ScriptExecutor scriptExecutor; @@ -55,6 +47,7 @@ public void createAndInitializePlatformIfNecessary_should_not_create_platform_if verify(spy, times(0)).createTables(); verify(spy, times(0)).initializePlatformStructure(); verify(spy, times(0)).insertPlatform(); + verify(spy, times(0)).insertTenant(); } @Test @@ -70,6 +63,7 @@ public void createAndInitializePlatformIfNecessary_should_create_platform_if_not verify(spy).createTables(); verify(spy).initializePlatformStructure(); verify(spy).insertPlatform(); + verify(spy).insertTenant(); //cleanup scriptExecutor.deleteTables(); diff --git a/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/command/InitCommandTest.java b/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/command/InitCommandTest.java index 46c75640eaf..7a19a6b6f6c 100644 --- a/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/command/InitCommandTest.java +++ b/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/command/InitCommandTest.java @@ -53,6 +53,8 @@ public void before() throws Exception { @Test public void should_execute_init() throws Exception { + doNothing().when(initCommand).askConfirmationIfH2(); + initCommand.execute(new Options(), buildCommandLine()); verify(platformSetup).init(); @@ -60,6 +62,8 @@ public void should_execute_init() throws Exception { @Test public void should_call_h2_confirmation() throws Exception { + doNothing().when(initCommand).askConfirmationIfH2(); + initCommand.execute(new Options(), buildCommandLine()); verify(initCommand).askConfirmationIfH2(); diff --git a/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/command/configure/DatabaseConfigurationTest.java b/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/command/configure/DatabaseConfigurationTest.java index 7733e79b841..d4f4044783f 100644 --- a/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/command/configure/DatabaseConfigurationTest.java +++ b/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/command/configure/DatabaseConfigurationTest.java @@ -31,6 +31,8 @@ */ public class DatabaseConfigurationTest { + private static final String TEST_DATASOURCE_CONFIG_DIR = "/datasource-config/"; + @Rule public TestRule clean = new RestoreSystemProperties(); @@ -39,7 +41,7 @@ public void bonita_database_values_can_be_overridden_by_system_properties() thro // given: final Properties properties = new PropertyLoader().loadProperties(); - System.setProperty("db.vendor", "mysql"); + System.setProperty("db.vendor", "postgres"); System.setProperty("db.server.name", "postgresServer"); System.setProperty("db.server.port", "3333"); System.setProperty("db.database.name", "bonita_database"); @@ -50,7 +52,7 @@ public void bonita_database_values_can_be_overridden_by_system_properties() thro final DatabaseConfiguration bonitaConfig = new DatabaseConfiguration("", properties, null); // then: - assertThat(bonitaConfig.getDbVendor()).isEqualTo("mysql"); + assertThat(bonitaConfig.getDbVendor()).isEqualTo("postgres"); assertThat(bonitaConfig.getServerName()).isEqualTo("postgresServer"); assertThat(bonitaConfig.getServerPort()).isEqualTo("3333"); assertThat(bonitaConfig.getDatabaseName()).isEqualTo("bonita_database"); @@ -62,7 +64,7 @@ public void bonita_database_values_can_be_overridden_by_system_properties() thro public void bdm_database_values_can_be_overridden_by_system_properties() throws Exception { // given: final Properties properties = new Properties(); - properties.load(this.getClass().getResourceAsStream("/internal.properties")); + properties.load(this.getClass().getResourceAsStream(TEST_DATASOURCE_CONFIG_DIR + "internal.properties")); System.setProperty("bdm.db.vendor", "postgres"); System.setProperty("bdm.db.server.name", "myServer"); @@ -87,8 +89,9 @@ public void bdm_database_values_can_be_overridden_by_system_properties() throws public void database_values_should_be_trimmed() throws Exception { // given: final Properties properties = new Properties(); - properties.load(this.getClass().getResourceAsStream("/database_with_space_values.properties")); - properties.load(this.getClass().getResourceAsStream("/internal.properties")); + properties.load(this.getClass() + .getResourceAsStream(TEST_DATASOURCE_CONFIG_DIR + "database_with_space_values.properties")); + properties.load(this.getClass().getResourceAsStream(TEST_DATASOURCE_CONFIG_DIR + "internal.properties")); System.setProperty("db.server.name", " localhost "); System.setProperty("db.server.port", " 5135 "); @@ -100,7 +103,7 @@ public void database_values_should_be_trimmed() throws Exception { // then: assertThat(dbConfig.getUrl()).isEqualTo("jdbc:postgresql://localhost:5135/bonita"); assertThat(bdmDbConfig.getUrl()) - .isEqualTo("jdbc:oracle:thin:@//ora1.rd.lan:1521/ORCL_DATABASE?oracle.net.disableOob=true"); + .isEqualTo("jdbc:postgresql://postgres.rd.lan:5432/business_data"); } @Test @@ -124,7 +127,7 @@ public void support_absolute_path_in_h2_database_dir() throws Exception { assertThat(bonitaConfig.getUrl()) .isEqualTo("jdbc:h2:file:" + h2DatabaseDir - + "/bonita;DB_CLOSE_ON_EXIT=FALSE;IGNORECASE=TRUE;AUTO_SERVER=TRUE;"); + + "/bonita_journal.db;DB_CLOSE_ON_EXIT=FALSE;IGNORECASE=TRUE;AUTO_SERVER=TRUE;"); } @Test @@ -144,7 +147,7 @@ public void support_properties_in_h2_database_dir() throws Exception { assertThat(dbConfig.getUrl()) .isEqualTo("jdbc:h2:file:" + h2DatabaseDir - + "/bonita;DB_CLOSE_ON_EXIT=FALSE;IGNORECASE=TRUE;AUTO_SERVER=TRUE;"); + + "/bonita_journal.db;DB_CLOSE_ON_EXIT=FALSE;IGNORECASE=TRUE;AUTO_SERVER=TRUE;"); } @Test @@ -165,14 +168,14 @@ public void convert_relative_path_to_absolute_path_in_h2_database_dir() throws E .isEqualTo("jdbc:h2:file:" + rootPath.resolve("setup").resolve(h2DatabaseDir).toAbsolutePath().normalize().toString() .replace("\\", "/") - + "/bonita;DB_CLOSE_ON_EXIT=FALSE;IGNORECASE=TRUE;AUTO_SERVER=TRUE;"); + + "/bonita_journal.db;DB_CLOSE_ON_EXIT=FALSE;IGNORECASE=TRUE;AUTO_SERVER=TRUE;"); } @Test public void jdbc_pool_size_values_must_be_integers() throws Exception { // given: final Properties properties = new Properties(); - properties.load(this.getClass().getResourceAsStream("/internal.properties")); + properties.load(this.getClass().getResourceAsStream(TEST_DATASOURCE_CONFIG_DIR + "internal.properties")); System.setProperty("bdm.db.vendor", "postgres"); System.setProperty("bdm.db.server.name", "myServer"); diff --git a/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/command/configure/PropertyReaderTest.java b/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/command/configure/PropertyReaderTest.java index c23939923ec..3796ee7183a 100644 --- a/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/command/configure/PropertyReaderTest.java +++ b/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/command/configure/PropertyReaderTest.java @@ -39,7 +39,7 @@ public class PropertyReaderTest { public void properties_file_values_can_be_overridden_by_system_properties() throws Exception { // given: final Properties properties = new Properties(); - properties.load(this.getClass().getResourceAsStream("/database.properties")); + properties.load(this.getClass().getResourceAsStream("/datasource-config/database.properties")); final PropertyReader bdmConfig = new PropertyReader(properties); assertThat(bdmConfig.getPropertyAndFailIfNull("bdm.db.vendor")).isEqualTo("oracle"); diff --git a/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/command/configure/TomcatBundleConfiguratorTest.java b/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/command/configure/TomcatBundleConfiguratorTest.java index 706e031d7aa..97ad84799db 100644 --- a/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/command/configure/TomcatBundleConfiguratorTest.java +++ b/platform/platform-setup/src/test/java/org/bonitasoft/platform/setup/command/configure/TomcatBundleConfiguratorTest.java @@ -13,17 +13,12 @@ **/ package org.bonitasoft.platform.setup.command.configure; -import static junit.framework.TestCase.fail; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.bonitasoft.platform.setup.PlatformSetup.BONITA_SETUP_FOLDER; import static org.bonitasoft.platform.setup.command.configure.BundleConfiguratorTest.checkFileContains; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; import java.io.File; import java.nio.file.Path; @@ -37,7 +32,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.contrib.java.lang.system.RestoreSystemProperties; -import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; import org.junit.rules.TestRule; import org.junit.runner.RunWith; @@ -52,9 +46,6 @@ public class TomcatBundleConfiguratorTest { @Rule public final TestRule restoreSystemProperties = new RestoreSystemProperties(); - @Rule - public final ExpectedException expectedException = ExpectedException.none(); - @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); @@ -82,16 +73,15 @@ public void setupTempConfFolder() throws Exception { @Test public void should_delete_h2_jar_from_classpath_if_h2_is_not_used() throws Exception { // given: - System.setProperty("db.vendor", "oracle"); - System.setProperty("db.database.name", "bonita_with$dollarXXX\\myInstance.of.bonita&perf=good"); - System.setProperty("db.user", "_bonita_with$dollar\\andBackSlash"); - System.setProperty("db.password", "bpm_With$dollar\\andBackSlash"); + System.setProperty("db.vendor", "postgres"); + System.setProperty("db.database.name", "bonita"); + System.setProperty("db.user", "bonita"); + System.setProperty("db.password", "bpm"); - System.setProperty("bdm.db.vendor", "oracle"); - System.setProperty("bdm.db.database.name", - "bonita_bdm_with$dollarXXX\\myInstance.of.bdm&perf=good?oracle.net.disableOob=true"); - System.setProperty("bdm.db.user", "_bdmWith$dollar\\andBackSlash"); - System.setProperty("bdm.db.password", "bdm_bpm_With$dollar\\andBackSlash"); + System.setProperty("bdm.db.vendor", "postgres"); + System.setProperty("bdm.db.database.name", "business_data"); + System.setProperty("bdm.db.user", "bizUser"); + System.setProperty("bdm.db.password", "bizPwd"); // given: final Path h2jarPath = tomcatFolder.resolve("lib").resolve("bonita").resolve("h2.jar"); @@ -108,10 +98,10 @@ public void should_delete_h2_jar_from_classpath_if_h2_is_not_used() throws Excep @Test public void should_not_delete_h2_jar_from_classpath_if_h2_is_used_for_bdm() throws Exception { // given: - System.setProperty("db.vendor", "oracle"); - System.setProperty("db.database.name", "bonita_with$dollarXXX\\myInstance.of.bonita&perf=good"); - System.setProperty("db.user", "_bonita_with$dollar\\andBackSlash"); - System.setProperty("db.password", "bpm_With$dollar\\andBackSlash"); + System.setProperty("db.vendor", "postgres"); + System.setProperty("db.database.name", "bonita"); + System.setProperty("db.user", "bonita"); + System.setProperty("db.password", "bpm"); System.setProperty("bdm.db.vendor", "h2"); System.setProperty("bdm.db.database.name", "business_data.db"); @@ -138,11 +128,10 @@ public void should_not_delete_h2_jar_from_classpath_if_h2_is_used_for_bonita() t System.setProperty("db.user", "myUser"); System.setProperty("db.password", "myPwd"); - System.setProperty("bdm.db.vendor", "oracle"); - System.setProperty("bdm.db.database.name", - "bonita_bdm_with$dollarXXX\\myInstance.of.bdm&perf=good?oracle.net.disableOob=true"); - System.setProperty("bdm.db.user", "_bdmWith$dollar\\andBackSlash"); - System.setProperty("bdm.db.password", "bdm_bpm_With$dollar\\andBackSlash"); + System.setProperty("bdm.db.vendor", "postgres"); + System.setProperty("bdm.db.database.name", "business_data"); + System.setProperty("bdm.db.user", "bizUser"); + System.setProperty("bdm.db.password", "bizPwd"); // given: final Path h2jarPath = tomcatFolder.resolve("lib").resolve("bonita").resolve("h2.jar"); @@ -182,7 +171,7 @@ public void should_not_delete_h2_jar_from_classpath_if_h2_is_used_for_bonita_and } @Test - public void should_not_fail_if_bonita_xml_file_does_not_pre_exist() throws Exception { + public void should_not_fail_if_bonitaXml_file_does_not_pre_exist() throws Exception { // given: final Path bonitaXmlPath = tomcatFolder.resolve("conf").resolve("Catalina").resolve("localhost") .resolve("bonita.xml"); @@ -198,6 +187,10 @@ public void should_not_fail_if_bonita_xml_file_does_not_pre_exist() throws Excep @Test public void configureApplicationServer_should_update_setEnv_file() throws Exception { + // given: + System.setProperty("db.vendor", "postgres"); + System.setProperty("bdm.db.vendor", "postgres"); + // when: configurator.configureApplicationServer(); @@ -205,9 +198,9 @@ public void configureApplicationServer_should_update_setEnv_file() throws Except assertThat(numberOfBackups("setenv.sh")).isEqualTo(1); assertThat(numberOfBackups("setenv.bat")).isEqualTo(1); checkFileContains(tomcatFolder.resolve("bin").resolve("setenv.sh"), "-Dsysprop.bonita.db.vendor=postgres", - "-Dsysprop.bonita.bdm.db.vendor=oracle"); + "-Dsysprop.bonita.bdm.db.vendor=postgres"); checkFileContains(tomcatFolder.resolve("bin").resolve("setenv.bat"), "-Dsysprop.bonita.db.vendor=postgres", - "-Dsysprop.bonita.bdm.db.vendor=oracle"); + "-Dsysprop.bonita.bdm.db.vendor=postgres"); } private int numberOfBackups(String file) { @@ -222,34 +215,50 @@ public void configureApplicationServer_should_fail_if_no_driver_folder() throws final Path driverFolder = bundleFolder.resolve("setup").resolve("lib"); FileUtils.deleteDirectory(driverFolder.toFile()); - // then: - expectedException.expect(PlatformException.class); - expectedException.expectMessage("Drivers folder not found: " + driverFolder.toString()); - - // when: - configurator.configureApplicationServer(); + // when - then: + assertThatExceptionOfType(PlatformException.class).isThrownBy(configurator::configureApplicationServer) + .withMessage("Drivers folder not found: " + driverFolder + + ". Make sure it exists and put a jar or zip file containing drivers there."); } @Test - public void configureApplicationServer_should_update_bonita_xml_file() throws Exception { + public void configureApplicationServer_should_update_bonitaXml_file() throws Exception { + // given: + System.setProperty("db.vendor", "postgres"); + System.setProperty("db.server.name", "db.localhost"); + System.setProperty("db.server.port", "5432"); + System.setProperty("db.database.name", "bonita"); + System.setProperty("db.user", "bonita"); + System.setProperty("db.password", "bpm"); + + System.setProperty("bdm.db.vendor", "postgres"); + System.setProperty("bdm.db.server.name", "biz.localhost"); + System.setProperty("bdm.db.server.port", "5433"); + System.setProperty("bdm.db.database.name", "business_data"); + System.setProperty("bdm.db.user", "bizUser"); + System.setProperty("bdm.db.password", "bizPwd"); + + System.setProperty("connection-pool.maxTotal", "200"); + // when: configurator.configureApplicationServer(); // then: - final Path bonita_xml = tomcatFolder.resolve("conf").resolve("Catalina").resolve("localhost") + final Path bonitaXml = tomcatFolder.resolve("conf").resolve("Catalina").resolve("localhost") .resolve("bonita.xml"); - checkFileContains(bonita_xml, + checkFileContains(bonitaXml, "validationQuery=\"SELECT 1\"", "username=\"bonita\"", "password=\"bpm\"", - "driverClassName=\"org.postgresql.Driver\"", - "url=\"jdbc:postgresql://localhost:5432/bonita\""); - checkFileContains(bonita_xml, - "validationQuery=\"SELECT 1 FROM DUAL\"", "username=\"bizUser\"", "password=\"bizPwd\"", - "driverClassName=\"oracle.jdbc.OracleDriver\"", - "url=\"jdbc:oracle:thin:@//ora1.rd.lan:1521/ORCL_with\\backslash?oracle.net.disableOob=true\""); - checkFileContains(bonita_xml, "type=\"org.postgresql.xa.PGXADataSource\"", - "class=\"org.postgresql.xa.PGXADataSource\"", "factory=\"org.postgresql.xa.PGXADataSourceFactory\"", - "serverName=\"localhost\"", "portNumber=\"5432\"", "port=\"5432\"", "databaseName=\"bonita\""); - checkFileContains(bonita_xml, "initialSize=\"8\"", + "serverName=\"db.localhost\"", "portNumber=\"5432\"", "port=\"5432\"", "databaseName=\"bonita\"", + "url=\"jdbc:postgresql://db.localhost:5432/bonita\""); + checkFileContains(bonitaXml, + "validationQuery=\"SELECT 1\"", "username=\"bizUser\"", "password=\"bizPwd\"", + "serverName=\"biz.localhost\"", "portNumber=\"5433\"", "port=\"5433\"", + "databaseName=\"business_data\"", + "url=\"jdbc:postgresql://biz.localhost:5433/business_data\""); + checkFileContains(bonitaXml, "driverClassName=\"org.postgresql.Driver\"", + "type=\"org.postgresql.xa.PGXADataSource\"", "class=\"org.postgresql.xa.PGXADataSource\"", + "factory=\"org.postgresql.xa.PGXADataSourceFactory\""); + checkFileContains(bonitaXml, "initialSize=\"8\"", // maxTotal value overridden in database.properties "maxTotal=\"200\"", "minIdle=\"8\"", @@ -259,49 +268,34 @@ public void configureApplicationServer_should_update_bonita_xml_file() throws Ex } @Test - public void configureApplicationServer_should_support_H2_replacements_for_Bonita_database() throws Exception { + public void configureApplicationServer_should_support_H2_replacements_for_Bonita_database_and_BDM() + throws Exception { // given: System.setProperty("db.vendor", "h2"); System.setProperty("db.database.name", "internal_database.db"); System.setProperty("db.user", "myUser"); System.setProperty("db.password", "myPwd"); + System.setProperty("bdm.db.vendor", "h2"); + System.setProperty("bdm.db.database.name", "internal_business_data.db"); + System.setProperty("bdm.db.user", "bizUser"); + System.setProperty("bdm.db.password", "bizPwd"); + // when: configurator.configureApplicationServer(); // then: - final Path bonita_xml = tomcatFolder.resolve("conf").resolve("Catalina").resolve("localhost") + final Path bonitaXml = tomcatFolder.resolve("conf").resolve("Catalina").resolve("localhost") .resolve("bonita.xml"); - checkFileContains(bonita_xml, "validationQuery=\"SELECT 1\"", "username=\"myUser\"", "password=\"myPwd\"", + checkFileContains(bonitaXml, "validationQuery=\"SELECT 1\"", "username=\"myUser\"", "password=\"myPwd\"", "driverClassName=\"org.h2.Driver\"", "url=\"jdbc:h2:file:" + databaseAbsolutePath + "/internal_database.db;DB_CLOSE_ON_EXIT=FALSE;IGNORECASE=TRUE;AUTO_SERVER=TRUE;\""); - checkFileContains(bonita_xml, "validationQuery=\"SELECT 1 FROM DUAL\"", "username=\"bizUser\"", - "password=\"bizPwd\"", - "driverClassName=\"oracle.jdbc.OracleDriver\"", - "url=\"jdbc:oracle:thin:@//ora1.rd.lan:1521/ORCL_with\\backslash?oracle.net.disableOob=true\""); - } - - @Test - public void configureApplicationServer_should_support_H2_replacements_for_BDM() throws Exception { - // given: - System.setProperty("bdm.db.vendor", "h2"); - System.setProperty("bdm.db.database.name", "business_data.db"); - System.setProperty("bdm.db.user", "sa"); - System.setProperty("bdm.db.password", ""); - - // when: - configurator.configureApplicationServer(); - - // then: - final Path bonita_xml = tomcatFolder.resolve("conf").resolve("Catalina").resolve("localhost") - .resolve("bonita.xml"); - - checkFileContains(bonita_xml, "validationQuery=\"SELECT 1\"", "username=\"sa\"", "password=\"\"", + checkFileContains(bonitaXml, "validationQuery=\"SELECT 1\"", "username=\"bizUser\"", "password=\"bizPwd\"", "driverClassName=\"org.h2.Driver\"", "url=\"jdbc:h2:file:" + databaseAbsolutePath - + "/business_data.db;DB_CLOSE_ON_EXIT=FALSE;IGNORECASE=TRUE;AUTO_SERVER=TRUE;\""); + + "/internal_business_data.db;DB_CLOSE_ON_EXIT=FALSE;IGNORECASE=TRUE;AUTO_SERVER=TRUE;\""); } @Test @@ -321,26 +315,30 @@ public void configureApplicationServer_should_support_special_characters_for_h2_ configurator.configureApplicationServer(); // then: - final Path bonita_xml = tomcatFolder.resolve("conf").resolve("Catalina").resolve("localhost") + final Path bonitaXml = tomcatFolder.resolve("conf").resolve("Catalina").resolve("localhost") .resolve("bonita.xml"); - checkFileContains(bonita_xml, "validationQuery=\"SELECT 1\"", "username=\"_bonita_with$dollar\\andBackSlash\"", + checkFileContains(bonitaXml, "validationQuery=\"SELECT 1\"", "username=\"_bonita_with$dollar\\andBackSlash\"", "password=\"bpm_With$dollar\\andBackSlash\"", "driverClassName=\"org.h2.Driver\"", "url=\"jdbc:h2:file:" + databaseAbsolutePath + "/bonita_bdm_with$dollarXXX.db;DB_CLOSE_ON_EXIT=FALSE;IGNORECASE=TRUE;AUTO_SERVER=TRUE;\""); } @Test - public void configureApplicationServer_should_support_special_characters_for_oracle_database() throws Exception { + public void configureApplicationServer_should_support_special_characters_for_database() throws Exception { // given: - System.setProperty("db.vendor", "oracle"); + System.setProperty("db.vendor", "postgres"); + System.setProperty("db.server.name", "localhost"); + System.setProperty("db.server.port", "5432"); System.setProperty("db.database.name", "bonita_with$dollarXXX\\myInstance.of.bonita&perf=good"); System.setProperty("db.user", "_bonita_with$dollar\\andBackSlash"); System.setProperty("db.password", "bpm_With$dollar\\andBackSlash"); - System.setProperty("bdm.db.vendor", "oracle"); + System.setProperty("bdm.db.vendor", "postgres"); + System.setProperty("bdm.db.server.name", "localhost"); + System.setProperty("bdm.db.server.port", "5432"); System.setProperty("bdm.db.database.name", - "bonita_bdm_with$dollarXXX\\myInstance.of.bdm&perf=good?oracle.net.disableOob=true"); + "bonita_bdm_with$dollarXXX\\myInstance.of.bdm&perf=good?host.net.disableOob=true"); System.setProperty("bdm.db.user", "_bdmWith$dollar\\andBackSlash"); System.setProperty("bdm.db.password", "bdm_bpm_With$dollar\\andBackSlash"); @@ -348,27 +346,34 @@ public void configureApplicationServer_should_support_special_characters_for_ora configurator.configureApplicationServer(); // then: - final Path bonita_xml = tomcatFolder.resolve("conf").resolve("Catalina").resolve("localhost") + final Path bonitaXml = tomcatFolder.resolve("conf").resolve("Catalina").resolve("localhost") .resolve("bonita.xml"); - checkFileContains(bonita_xml, "validationQuery=\"SELECT 1 FROM DUAL\"", + checkFileContains(bonitaXml, "validationQuery=\"SELECT 1\"", "username=\"_bonita_with$dollar\\andBackSlash\"", "password=\"bpm_With$dollar\\andBackSlash\"", - "driverClassName=\"oracle.jdbc.OracleDriver\"", - "url=\"jdbc:oracle:thin:@//localhost:5432/bonita_with$dollarXXX\\myInstance.of.bonita&perf=good?oracle.net.disableOob=true\""); + "driverClassName=\"org.postgresql.Driver\"", + "url=\"jdbc:postgresql://localhost:5432/bonita_with$dollarXXX\\myInstance.of.bonita&perf=good\"", + "url=\"jdbc:postgresql://localhost:5432/bonita_bdm_with$dollarXXX\\myInstance.of.bdm&perf=good?host.net.disableOob=true\""); } @Test public void should_copy_both_drivers_if_not_the_same_dbVendor_for_bdm() throws Exception { + // given: + System.setProperty("db.vendor", "h2"); + System.setProperty("bdm.db.vendor", "postgres"); + // when: spy.configureApplicationServer(); // then: + verify(spy).copyDriverFile(any(Path.class), any(Path.class), eq("h2")); verify(spy).copyDriverFile(any(Path.class), any(Path.class), eq("postgres")); - verify(spy).copyDriverFile(any(Path.class), any(Path.class), eq("oracle")); } @Test public void should_not_copy_drivers_again_if_same_dbVendor_for_bdm() throws Exception { + // given: + System.setProperty("db.vendor", "postgres"); System.setProperty("bdm.db.vendor", "postgres"); // when: @@ -381,49 +386,47 @@ public void should_not_copy_drivers_again_if_same_dbVendor_for_bdm() throws Exce @Test public void should_fail_if_tomcat_mandatory_file_not_present() throws Exception { final Path confFile = tomcatFolder.resolve("bin").resolve("setenv.sh"); - FileUtils.deleteQuietly(confFile.toFile()); + FileUtils.delete(confFile.toFile()); - // then: - expectedException.expect(PlatformException.class); - expectedException.expectMessage("File setenv.sh is mandatory but is not found"); - - // when: - configurator.configureApplicationServer(); + // when - then: + assertThatExceptionOfType(PlatformException.class).isThrownBy(configurator::configureApplicationServer) + .withMessage("File setenv.sh is mandatory but is not found"); } @Test public void configureApplicationServer_should_fail_if_drivers_not_found() throws Exception { // given: - final String dbVendor = "sqlserver"; + final String dbVendor = "postgres"; System.setProperty("db.vendor", dbVendor); - - // then: - expectedException.expect(PlatformException.class); - expectedException.expectMessage("No " + dbVendor + " drivers found in folder"); - - // when: - configurator.configureApplicationServer(); + final Path libFolder = bundleFolder.resolve("setup").resolve("lib"); + final Path driverJar = libFolder.resolve("postgres9.2-drivers.jar"); + FileUtils.delete(driverJar.toFile()); + + // when - then: + assertThatExceptionOfType(PlatformException.class).isThrownBy(configurator::configureApplicationServer) + .withMessage("No " + dbVendor + " drivers found in folder " + libFolder + + ". Make sure to put a jar or zip file containing drivers there."); } @Test public void exception_in_configure_should_restore_previous_configuration() throws Exception { // given: doThrow(PlatformException.class).when(spy).copyDatabaseDriversIfNecessary(any(Path.class), any(Path.class), - eq("oracle")); + eq("h2")); - // when: - try { - spy.configureApplicationServer(); - fail("Should have thrown exception"); - } catch (PlatformException e) { - // then: - verify(spy).restorePreviousConfiguration(any(Path.class), any(Path.class), any(Path.class)); - } + // when - then: + assertThatExceptionOfType(PlatformException.class).isThrownBy(spy::configureApplicationServer); + verify(spy).restorePreviousConfiguration(any(Path.class), any(Path.class), any(Path.class)); } @Test public void should_not_make_backup_if_content_is_the_same() throws Exception { // given: + System.setProperty("db.vendor", "postgres"); + System.setProperty("db.database.name", "bonita"); + System.setProperty("db.user", "bonita"); + System.setProperty("db.password", "bpm"); + configurator.configureApplicationServer(); assertThat(numberOfBackups("bonita.xml")).isEqualTo(1); @@ -442,16 +445,21 @@ public void should_not_make_backup_if_content_is_the_same() throws Exception { @Test public void should_make_new_backup_if_configuration_changes() throws Exception { // given: + System.setProperty("db.vendor", "postgres"); + System.setProperty("db.database.name", "bonita"); + System.setProperty("db.user", "bonita"); + System.setProperty("db.password", "bpm"); + configurator.configureApplicationServer(); assertThat(numberOfBackups("bonita.xml")).isEqualTo(1); assertThat(numberOfBackups("setenv.bat")).isEqualTo(1); assertThat(numberOfBackups("setenv.sh")).isEqualTo(1); - System.setProperty("bdm.db.vendor", "h2"); - System.setProperty("bdm.db.database.name", "business_data.db"); - System.setProperty("bdm.db.user", "sa"); - System.setProperty("bdm.db.password", ""); + System.setProperty("db.vendor", "h2"); + System.setProperty("db.database.name", "bonita_journal.db"); + System.setProperty("db.user", "sa"); + System.setProperty("db.password", ""); // so that horodated file has different Thread.sleep(1020); diff --git a/platform/platform-setup/src/test/resources/database.properties b/platform/platform-setup/src/test/resources/database.properties index b8c7ce580cd..807a5ea14fc 100644 --- a/platform/platform-setup/src/test/resources/database.properties +++ b/platform/platform-setup/src/test/resources/database.properties @@ -1,25 +1,48 @@ -##################################### -# Bonita internal database properties -##################################### +##################################################################### +# Nominal database.properties copied from src/main/standalone folder +##################################################################### -db.vendor=postgres -db.server.name=localhost -db.server.port=5432 -db.database.name=bonita -db.user=bonita -db.password=bpm -# Override default maxTotal value -connection-pool.maxTotal = 200 +#################################################################################### +# +# Modify the following values to suit your database needs. +# Fore more information, see file ../HOW_TO_CONFIGURE_AND_RUN.txt +# +#################################################################################### -##################################### + +######################################### +# Bonita database properties +######################################### + +# Valid values for Community edition: h2, postgres +# Valid values for Enterprise editions: h2, postgres, sqlserver, oracle, mysql +db.vendor=h2 +# when using h2, no server or port setting is needed since connexion is made using file protocol mode using relative directory: +db.server.name=SERVER_NAME +db.server.port=SERVER_PORT +# if your database name contains a backslash (\) character, you must double it (\\): +db.database.name=bonita_journal.db +db.user=sa +# if your database password contains a backslash (\) character, you must double it (\\): +db.password= + +################################### # Business Data database properties -##################################### -bdm.db.vendor=oracle -bdm.db.server.name=ora1.rd.lan -bdm.db.server.port=1521 -bdm.db.database.name=ORCL_with\\backslash -bdm.db.user=bizUser -bdm.db.password=bizPwd +################################### +# Valid values for Community edition: h2, postgres +# Valid values for Enterprise editions: h2, postgres, sqlserver, oracle, mysql +bdm.db.vendor=h2 +bdm.db.server.name=SERVER_NAME +bdm.db.server.port=SERVER_PORT +bdm.db.database.name=business_data.db +bdm.db.user=sa +bdm.db.password= + +# IMPORTANT NOTE regarding H2 database: +# in case you move whole setup folder to another directory, you must change property below +# to point to original folder containing h2 database folder +# new value can be relative or absolute since it still points to the right folder +# WARNING for Windows users: keep forward slashes like below (instead of backslashes): h2.database.dir=../h2_database diff --git a/platform/platform-setup/src/test/resources/datasource-config/database.properties b/platform/platform-setup/src/test/resources/datasource-config/database.properties new file mode 100644 index 00000000000..b8c7ce580cd --- /dev/null +++ b/platform/platform-setup/src/test/resources/datasource-config/database.properties @@ -0,0 +1,25 @@ +##################################### +# Bonita internal database properties +##################################### + +db.vendor=postgres +db.server.name=localhost +db.server.port=5432 +db.database.name=bonita +db.user=bonita +db.password=bpm + +# Override default maxTotal value +connection-pool.maxTotal = 200 + +##################################### +# Business Data database properties +##################################### +bdm.db.vendor=oracle +bdm.db.server.name=ora1.rd.lan +bdm.db.server.port=1521 +bdm.db.database.name=ORCL_with\\backslash +bdm.db.user=bizUser +bdm.db.password=bizPwd + +h2.database.dir=../h2_database diff --git a/platform/platform-setup/src/test/resources/database_with_space_values.properties b/platform/platform-setup/src/test/resources/datasource-config/database_with_space_values.properties similarity index 68% rename from platform/platform-setup/src/test/resources/database_with_space_values.properties rename to platform/platform-setup/src/test/resources/datasource-config/database_with_space_values.properties index 319ba88fca2..c53191161d4 100644 --- a/platform/platform-setup/src/test/resources/database_with_space_values.properties +++ b/platform/platform-setup/src/test/resources/datasource-config/database_with_space_values.properties @@ -12,9 +12,9 @@ db.password=bpm ##################################### # Business Data database properties ##################################### -bdm.db.vendor=oracle -bdm.db.server.name= ora1.rd.lan -bdm.db.server.port= 1521 -bdm.db.database.name= ORCL_DATABASE -bdm.db.user=bizUser -bdm.db.password=bizPwd +bdm.db.vendor=postgres +bdm.db.server.name= postgres.rd.lan +bdm.db.server.port= 5432 +bdm.db.database.name= business_data +bdm.db.user=bonita +bdm.db.password=bpm diff --git a/platform/platform-setup/src/test/resources/incomplete_database.properties b/platform/platform-setup/src/test/resources/datasource-config/incomplete_database.properties similarity index 100% rename from platform/platform-setup/src/test/resources/incomplete_database.properties rename to platform/platform-setup/src/test/resources/datasource-config/incomplete_database.properties diff --git a/platform/platform-setup/src/test/resources/incomplete_internal.properties b/platform/platform-setup/src/test/resources/datasource-config/incomplete_internal.properties similarity index 100% rename from platform/platform-setup/src/test/resources/incomplete_internal.properties rename to platform/platform-setup/src/test/resources/datasource-config/incomplete_internal.properties diff --git a/platform/platform-setup/src/test/resources/datasource-config/internal.properties b/platform/platform-setup/src/test/resources/datasource-config/internal.properties new file mode 100644 index 00000000000..cf7e5f6dda5 --- /dev/null +++ b/platform/platform-setup/src/test/resources/datasource-config/internal.properties @@ -0,0 +1,58 @@ +# Nominal internal.properties copied from src/main/standalone module + +h2.nonXaDriver=org.h2.Driver +h2.xaDriver=org.h2.jdbcx.JdbcDataSource +h2.xaDSFactory=org.h2.jdbcx.JdbcDataSourceFactory + +postgres.nonXaDriver=org.postgresql.Driver +postgres.xaDriver=org.postgresql.xa.PGXADataSource +postgres.xaDSFactory=org.postgresql.xa.PGXADataSourceFactory + +########################### +## Bonita database +########################### + +# h2 properties +h2.url=jdbc:h2:file:${h2.database.dir}/${db.database.name};DB_CLOSE_ON_EXIT=FALSE;IGNORECASE=TRUE;AUTO_SERVER=TRUE; +h2.testQuery=SELECT 1 + +# postgres properties +postgres.url=jdbc:postgresql://${db.server.name}:${db.server.port}/${db.database.name} +postgres.testQuery=SELECT 1 + + +# spring properties +spring.datasource.username=${db.user} +spring.datasource.password=${db.password} +spring.datasource.driver-class-name=${${db.vendor}.nonXaDriver} +spring.datasource.url=${${db.vendor}.url} + +# The initial number of connections when the connection pool starts. +connection-pool.initialSize=8 +# The maximum number of active connections that can be allocated from this pool at the same time. +connection-pool.maxTotal=50 +# The minimum number of active connections that always established after pool created and connection has reached this size. +connection-pool.minIdle=8 +# The maximum number of connections that should be kept in the pool at all times. +connection-pool.maxIdle=16 + +########################### +# Business Data database +########################### + +# h2 properties +h2.bdm.url=jdbc:h2:file:${h2.database.dir}/${bdm.db.database.name};DB_CLOSE_ON_EXIT=FALSE;IGNORECASE=TRUE;AUTO_SERVER=TRUE; +h2.bdm.testQuery=SELECT 1 + +# postgres properties +postgres.bdm.url=jdbc:postgresql://${bdm.db.server.name}:${bdm.db.server.port}/${bdm.db.database.name} +postgres.bdm.testQuery=SELECT 1 + +# The initial number of connections when the connection pool starts. +bdm.connection-pool.initialSize=4 +# The maximum number of active connections that can be allocated from this pool at the same time. +bdm.connection-pool.maxTotal=20 +# The minimum number of active connections that always established after pool created and connection has reached this size. +bdm.connection-pool.minIdle=4 +# The maximum number of connections that should be kept in the pool at all times. +bdm.connection-pool.maxIdle=10 diff --git a/platform/platform-setup/src/test/resources/missingDriverClass_internal.properties b/platform/platform-setup/src/test/resources/datasource-config/missingDriverClass_internal.properties similarity index 100% rename from platform/platform-setup/src/test/resources/missingDriverClass_internal.properties rename to platform/platform-setup/src/test/resources/datasource-config/missingDriverClass_internal.properties diff --git a/platform/platform-setup/src/test/resources/h2.properties b/platform/platform-setup/src/test/resources/h2.properties deleted file mode 100644 index b47f5f920a3..00000000000 --- a/platform/platform-setup/src/test/resources/h2.properties +++ /dev/null @@ -1 +0,0 @@ -# file is required but no specific properties are necessary with H2 diff --git a/platform/platform-setup/src/test/resources/internal.properties b/platform/platform-setup/src/test/resources/internal.properties index 740c38e85b9..dd0e0c37b5f 100644 --- a/platform/platform-setup/src/test/resources/internal.properties +++ b/platform/platform-setup/src/test/resources/internal.properties @@ -1,4 +1,15 @@ -### properties below don't need to be modified unless specific requirements +##################################################################### +# Nominal internal.properties copied from src/main/standalone folder +##################################################################### + +################################################################################## +# # +# properties below must NOT be modified unless specific requirements # +# # +################################################################################## +# /!\ WARNING /!\ # +# Any value containing a backslash (\) character MUST be doubled (\\) # +################################################################################## h2.nonXaDriver=org.h2.Driver h2.xaDriver=org.h2.jdbcx.JdbcDataSource @@ -8,24 +19,8 @@ postgres.nonXaDriver=org.postgresql.Driver postgres.xaDriver=org.postgresql.xa.PGXADataSource postgres.xaDSFactory=org.postgresql.xa.PGXADataSourceFactory -# use this drivers for pre-8.0 MySQL version: -# mysql.nonXaDriver=com.mysql.jdbc.Driver -# mysql.xaDriver=com.mysql.jdbc.jdbc2.optional.MysqlXADataSource -# Otherwise use MySQL 8+ new driver: -mysql.nonXaDriver=com.mysql.cj.jdbc.Driver -mysql.xaDriver=com.mysql.cj.jdbc.MysqlXADataSource -mysql.xaDSFactory=com.mysql.cj.jdbc.MysqlDataSourceFactory - -sqlserver.nonXaDriver=com.microsoft.sqlserver.jdbc.SQLServerDriver -sqlserver.xaDriver=com.microsoft.sqlserver.jdbc.SQLServerXADataSource -sqlserver.xaDSFactory=com.microsoft.sqlserver.jdbc.SQLServerDataSourceObjectFactory - -oracle.nonXaDriver=oracle.jdbc.OracleDriver -oracle.xaDriver=oracle.jdbc.xa.client.OracleXADataSource -oracle.xaDSFactory=oracle.jdbc.pool.OracleDataSourceFactory - ########################### -## Bonita internal database +## Bonita database ########################### # h2 properties @@ -36,17 +31,6 @@ h2.testQuery=SELECT 1 postgres.url=jdbc:postgresql://${db.server.name}:${db.server.port}/${db.database.name} postgres.testQuery=SELECT 1 -# mysql properties -mysql.url=jdbc:mysql://${db.server.name}:${db.server.port}/${db.database.name}?dontTrackOpenResources=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true -mysql.testQuery=SELECT 1 - -# sqlserver properties -sqlserver.url=jdbc:sqlserver://${db.server.name}:${db.server.port};database=${db.database.name} -sqlserver.testQuery=SELECT 1 - -# oracle properties -oracle.url=jdbc:oracle:thin:@//${db.server.name}:${db.server.port}/${db.database.name}?oracle.net.disableOob=true -oracle.testQuery=SELECT 1 FROM DUAL # spring properties spring.datasource.username=${db.user} @@ -54,14 +38,17 @@ spring.datasource.password=${db.password} spring.datasource.driver-class-name=${${db.vendor}.nonXaDriver} spring.datasource.url=${${db.vendor}.url} -# datasource jdbc connection pool sizes +# The initial number of connections when the connection pool starts. connection-pool.initialSize=8 +# The maximum number of active connections that can be allocated from this pool at the same time. connection-pool.maxTotal=50 +# The minimum number of active connections that always established after pool created and connection has reached this size. connection-pool.minIdle=8 +# The maximum number of connections that should be kept in the pool at all times. connection-pool.maxIdle=16 ########################### -# BusinessData database +# Business Data database ########################### # h2 properties @@ -72,19 +59,11 @@ h2.bdm.testQuery=SELECT 1 postgres.bdm.url=jdbc:postgresql://${bdm.db.server.name}:${bdm.db.server.port}/${bdm.db.database.name} postgres.bdm.testQuery=SELECT 1 -# mysql properties -mysql.bdm.url=jdbc:mysql://${bdm.db.server.name}:${bdm.db.server.port}/${bdm.db.database.name}?dontTrackOpenResources=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true -mysql.bdm.testQuery=SELECT 1 - -# sqlserver properties -sqlserver.bdm.url=jdbc:sqlserver://${bdm.db.server.name}:${bdm.db.server.port};database=${bdm.db.database.name} -sqlserver.bdm.testQuery=SELECT 1 - -# oracle properties -oracle.bdm.url=jdbc:oracle:thin:@//${bdm.db.server.name}:${bdm.db.server.port}/${bdm.db.database.name}?oracle.net.disableOob=true -oracle.bdm.testQuery=SELECT 1 FROM DUAL - +# The initial number of connections when the connection pool starts. bdm.connection-pool.initialSize=4 +# The maximum number of active connections that can be allocated from this pool at the same time. bdm.connection-pool.maxTotal=20 +# The minimum number of active connections that always established after pool created and connection has reached this size. bdm.connection-pool.minIdle=4 +# The maximum number of connections that should be kept in the pool at all times. bdm.connection-pool.maxIdle=10 diff --git a/platform/platform-setup/src/test/resources/mysql.properties b/platform/platform-setup/src/test/resources/mysql.properties deleted file mode 100644 index 6e8c7735e7a..00000000000 --- a/platform/platform-setup/src/test/resources/mysql.properties +++ /dev/null @@ -1,20 +0,0 @@ -##################### -# Database properties -##################### -db.server.name=mysql2.rd.lan -db.server.port=3306 -db.database.name=bos6_manu -db.user=bos6_manu -db.password=bos6_manu - - -################# -# JDBC properties -################# -spring.datasource.username=${db.user} -spring.datasource.password=${db.password} -spring.datasource.url=jdbc:mysql://${db.server.name}:${db.server.port}/${db.database.name}?useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true -# use this driver / datasource for pre-8.0 MySQL version: -# spring.datasource.driver-class-name=com.mysql.jdbc.Driver -# Otherwise use MySQL 8+ version: -spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver diff --git a/platform/platform-setup/src/test/resources/oracle.properties b/platform/platform-setup/src/test/resources/oracle.properties deleted file mode 100644 index fe0ad9ae299..00000000000 --- a/platform/platform-setup/src/test/resources/oracle.properties +++ /dev/null @@ -1,17 +0,0 @@ -##################### -# Database properties -##################### -db.server.name=ora1.rd.lan -db.server.port=1521 -db.database.name=orcl -db.user=bos6_manu -db.password=bos6_manu - - -################# -# JDBC properties -################# -spring.datasource.username=${db.user} -spring.datasource.password=${db.password} -spring.datasource.url=jdbc:oracle:thin:@//${db.server.name}:${db.server.port}/${db.database.name}?oracle.net.disableOob=true -spring.datasource.driver-class-name=oracle.jdbc.OracleDriver diff --git a/platform/platform-setup/src/test/resources/postgres.properties b/platform/platform-setup/src/test/resources/postgres.properties deleted file mode 100644 index b3ba4d159ee..00000000000 --- a/platform/platform-setup/src/test/resources/postgres.properties +++ /dev/null @@ -1,17 +0,0 @@ -##################### -# Database properties -##################### -db.server.name=localhost -db.server.port=5432 -db.database.name=bonita -db.user=bonita -db.password=bpm - - -################# -# JDBC properties -################# -spring.datasource.username=${db.user} -spring.datasource.password=${db.password} -spring.datasource.url=jdbc:postgresql://${db.server.name}:${db.server.port}/${db.database.name} -spring.datasource.driver-class-name=org.postgresql.Driver diff --git a/platform/platform-setup/src/test/resources/sqlserver.properties b/platform/platform-setup/src/test/resources/sqlserver.properties deleted file mode 100644 index 54bb16dda0b..00000000000 --- a/platform/platform-setup/src/test/resources/sqlserver.properties +++ /dev/null @@ -1,17 +0,0 @@ -##################### -# Database properties -##################### -db.server.name=localhost -db.server.port=1433 -db.database.name=bonita -db.user=bonita -db.password=bpm - - -################# -# JDBC properties -################# -spring.datasource.username=${db.user} -spring.datasource.password=${db.password} -spring.datasource.url=jdbc:sqlserver://${db.server.name}:${db.server.port};database=${db.database.name} -spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver diff --git a/services/bonita-archive/build.gradle b/services/bonita-archive/build.gradle index e7b4f791761..ecd9c515ea2 100644 --- a/services/bonita-archive/build.gradle +++ b/services/bonita-archive/build.gradle @@ -4,7 +4,6 @@ dependencies { api project(':services:bonita-commons') api project(':services:bonita-transaction') api project(':services:bonita-persistence') - testImplementation libs.junit4 testImplementation libs.mockitoCore testImplementation libs.logback } diff --git a/services/bonita-authentication/build.gradle b/services/bonita-authentication/build.gradle index cdfaf3d3c09..94c909f2a2b 100644 --- a/services/bonita-authentication/build.gradle +++ b/services/bonita-authentication/build.gradle @@ -3,6 +3,5 @@ dependencies { api project(':services:bonita-identity') api project(':services:bonita-commons') - testImplementation libs.junit4 testImplementation libs.mockitoCore } diff --git a/services/bonita-authorization/build.gradle b/services/bonita-authorization/build.gradle index 53e14fef916..ff8185d608c 100644 --- a/services/bonita-authorization/build.gradle +++ b/services/bonita-authorization/build.gradle @@ -7,7 +7,6 @@ dependencies { api project(':bpm:bonita-core:bonita-home-server') api project(':bpm:bonita-common') - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.mockitoCore testImplementation libs.logback diff --git a/services/bonita-authorization/src/main/resources/org/bonitasoft/engine/authorization/properties/dynamic-permissions-checks.properties b/services/bonita-authorization/src/main/resources/org/bonitasoft/engine/authorization/properties/dynamic-permissions-checks.properties index e20da874d4f..fc74aed35c1 100644 --- a/services/bonita-authorization/src/main/resources/org/bonitasoft/engine/authorization/properties/dynamic-permissions-checks.properties +++ b/services/bonita-authorization/src/main/resources/org/bonitasoft/engine/authorization/properties/dynamic-permissions-checks.properties @@ -167,6 +167,8 @@ GET|living/application=[profile|Administrator, check|org.bonitasoft.permissions. # Secure application menu resource GET|living/application-menu=[profile|Administrator, check|org.bonitasoft.permissions.ApplicationMenuPermissionRule] +# Platform information +GET|system/information=[profile|Administrator] #Servlets GET|portal/documentDownload=[profile|Administrator, check|org.bonitasoft.permissions.DownloadDocumentPermissionRule] diff --git a/services/bonita-business-application/build.gradle b/services/bonita-business-application/build.gradle index 746cbd004cd..160060dc76f 100644 --- a/services/bonita-business-application/build.gradle +++ b/services/bonita-business-application/build.gradle @@ -5,7 +5,6 @@ dependencies { api project(':services:bonita-events') api project(':services:bonita-log') api project(':services:bonita-builder') - testImplementation libs.junit4 testImplementation libs.mockitoCore testImplementation libs.assertj diff --git a/services/bonita-business-application/src/main/java/org/bonitasoft/engine/business/application/impl/ApplicationServiceImpl.java b/services/bonita-business-application/src/main/java/org/bonitasoft/engine/business/application/impl/ApplicationServiceImpl.java index 01ca4880f37..177ea3cd1fb 100755 --- a/services/bonita-business-application/src/main/java/org/bonitasoft/engine/business/application/impl/ApplicationServiceImpl.java +++ b/services/bonita-business-application/src/main/java/org/bonitasoft/engine/business/application/impl/ApplicationServiceImpl.java @@ -327,11 +327,19 @@ private T logAndRetrowException(final long objec } private void validateUpdatedFields(final EntityUpdateDescriptor updateDescriptor, - final SApplicationWithIcon application) throws SBonitaReadException, SObjectAlreadyExistsException { + final SApplicationWithIcon application) + throws SBonitaReadException, SObjectAlreadyExistsException, SObjectModificationException { if (updateDescriptor.getFields().containsKey(AbstractSApplication.TOKEN) && !application.getToken().equals(updateDescriptor.getFields().get(AbstractSApplication.TOKEN))) { validateApplicationToken((String) updateDescriptor.getFields().get(AbstractSApplication.TOKEN)); } + if (updateDescriptor.getFields().containsKey(AbstractSApplication.LINK) + && !Boolean.valueOf(application.isLink()) + .equals(updateDescriptor.getFields().get(AbstractSApplication.LINK))) { + throw new SObjectModificationException(format( + "The 'link' nature of application '%s' is not modifiable. You can not switch between legacy and application links.", + application.getDisplayName())); + } } @Override diff --git a/services/bonita-business-application/src/main/java/org/bonitasoft/engine/business/application/model/AbstractSApplication.java b/services/bonita-business-application/src/main/java/org/bonitasoft/engine/business/application/model/AbstractSApplication.java index 13569ad4625..f17c0787e42 100644 --- a/services/bonita-business-application/src/main/java/org/bonitasoft/engine/business/application/model/AbstractSApplication.java +++ b/services/bonita-business-application/src/main/java/org/bonitasoft/engine/business/application/model/AbstractSApplication.java @@ -47,6 +47,7 @@ public abstract class AbstractSApplication implements PersistentObject { public static final String ICON_MIME_TYPE = "iconMimeType"; public static final String EDITABLE = "editable"; public static final String INTERNAL_PROFILE = "internalProfile"; + public static final String LINK = "isLink"; @Id private long tenantId; @@ -87,6 +88,9 @@ public abstract class AbstractSApplication implements PersistentObject { private boolean editable = true; @Column private String internalProfile; + // "link" is a reserved keyword in some databases + @Column + private boolean isLink; public AbstractSApplication(String token, String displayName, String version, long creationDate, long createdBy, String state, boolean editable) { diff --git a/services/bonita-business-data/bonita-business-data-api/build.gradle b/services/bonita-business-data/bonita-business-data-api/build.gradle index 826f7dcabcc..2785592584e 100644 --- a/services/bonita-business-data/bonita-business-data-api/build.gradle +++ b/services/bonita-business-data/bonita-business-data-api/build.gradle @@ -3,7 +3,6 @@ dependencies { api project(':services:bonita-commons') api libs.javassist - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.mockitoCore testImplementation libs.logback diff --git a/services/bonita-business-data/bonita-business-data-client-resources/build.gradle b/services/bonita-business-data/bonita-business-data-client-resources/build.gradle index d1a89c5bd02..927f18a76cc 100644 --- a/services/bonita-business-data/bonita-business-data-client-resources/build.gradle +++ b/services/bonita-business-data/bonita-business-data-client-resources/build.gradle @@ -9,7 +9,6 @@ dependencies { api libs.javassist compileOnly project(':bpm:bonita-client') testImplementation project(':bpm:bonita-client') - testImplementation libs.junit4 testImplementation libs.mockitoCore testImplementation libs.assertj testImplementation(libs.hibernateCore) { diff --git a/services/bonita-business-data/bonita-business-data-generator/build.gradle b/services/bonita-business-data/bonita-business-data-generator/build.gradle index 47c41462909..d01d0db11a8 100644 --- a/services/bonita-business-data/bonita-business-data-generator/build.gradle +++ b/services/bonita-business-data/bonita-business-data-generator/build.gradle @@ -14,7 +14,6 @@ dependencies { api project(':bpm:bonita-common') api libs.commonsLang api libs.jaxbCodeModel - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.mockitoCore testImplementation libs.logback diff --git a/services/bonita-business-data/bonita-business-data-impl/build.gradle b/services/bonita-business-data/bonita-business-data-impl/build.gradle index 5e477c28af6..33be215e56a 100644 --- a/services/bonita-business-data/bonita-business-data-impl/build.gradle +++ b/services/bonita-business-data/bonita-business-data-impl/build.gradle @@ -16,7 +16,6 @@ dependencies { annotationProcessor libs.lombok compileOnly libs.lombok - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.jsonUnitFluent testImplementation libs.mockitoCore @@ -27,19 +26,10 @@ dependencies { testImplementation testFixtures(project(':bpm:bonita-common')) testRuntimeOnly libs.tomcatDbcp testRuntimeOnly libs.h2 - testRuntimeOnly libs.mysql - testRuntimeOnly libs.postgresql - testRuntimeOnly libs.msSqlServer // Property Based Test framework: testImplementation(libs.quickcheckCore) testImplementation(libs.quickcheckGenerators) } -// run: -// ./gradlew mysqlDatabaseTest -// ./gradlew oracleDatabaseTest -// ./gradlew sqlserverDatabaseTest -// ./gradlew postgresDatabaseTest -// to run tests on specific docker DB: databaseIntegrationTest { includes '**/*Test.class' } diff --git a/services/bonita-business-data/bonita-business-data-impl/src/main/java/org/bonitasoft/engine/business/data/impl/BusinessDataModelRepositoryImpl.java b/services/bonita-business-data/bonita-business-data-impl/src/main/java/org/bonitasoft/engine/business/data/impl/BusinessDataModelRepositoryImpl.java index fa28db14ef8..60baa51ec07 100644 --- a/services/bonita-business-data/bonita-business-data-impl/src/main/java/org/bonitasoft/engine/business/data/impl/BusinessDataModelRepositoryImpl.java +++ b/services/bonita-business-data/bonita-business-data-impl/src/main/java/org/bonitasoft/engine/business/data/impl/BusinessDataModelRepositoryImpl.java @@ -308,8 +308,9 @@ public void uninstall(final long tenantId) throws SBusinessDataRepositoryExcepti try { dependencyService.deleteDependency(BDR_DEPENDENCY_NAME); classLoaderService.refreshClassLoaderImmediatelyWithRollback(identifier(ScopeType.TENANT, tenantId)); + ClassLoader classLoader = classLoaderService.getClassLoader(identifier(ScopeType.TENANT, tenantId)); Thread.currentThread() - .setContextClassLoader(classLoaderService.getClassLoader(identifier(ScopeType.TENANT, tenantId))); + .setContextClassLoader(classLoader); } catch (final SDependencyNotFoundException sde) { // do nothing } catch (final SDependencyException | SClassLoaderException e) { diff --git a/services/bonita-business-data/bonita-business-data-impl/src/test/java/org/bonitasoft/engine/business/data/impl/BusinessDataModelRepositoryImplTest.java b/services/bonita-business-data/bonita-business-data-impl/src/test/java/org/bonitasoft/engine/business/data/impl/BusinessDataModelRepositoryImplTest.java index c5806606aa5..91211304338 100644 --- a/services/bonita-business-data/bonita-business-data-impl/src/test/java/org/bonitasoft/engine/business/data/impl/BusinessDataModelRepositoryImplTest.java +++ b/services/bonita-business-data/bonita-business-data-impl/src/test/java/org/bonitasoft/engine/business/data/impl/BusinessDataModelRepositoryImplTest.java @@ -14,12 +14,11 @@ package org.bonitasoft.engine.business.data.impl; import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.*; import static org.bonitasoft.engine.commons.Pair.pair; import static org.bonitasoft.engine.commons.io.IOUtil.zip; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; -import static org.mockito.Mockito.doReturn; import java.io.InputStream; import java.sql.SQLException; @@ -48,10 +47,10 @@ import org.bonitasoft.engine.resources.TenantResourceType; import org.bonitasoft.engine.resources.TenantResourcesService; import org.hibernate.tool.schema.spi.CommandAcceptanceException; +import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; @@ -84,14 +83,24 @@ public class BusinessDataModelRepositoryImplTest { private BusinessDataModelRepositoryImpl businessDataModelRepository; + private ClassLoader classLoader; + @Before public void setUp() { + // store the context ClassLoader of the current thread + classLoader = Thread.currentThread().getContextClassLoader(); doReturn(platformProperties).when(platformService).getSPlatformProperties(); doReturn("1.0").when(platformProperties).getPlatformVersion(); businessDataModelRepository = spy(new BusinessDataModelRepositoryImpl(platformService, dependencyService, classLoaderService, schemaManager, tenantResourcesService, TENANT_ID)); } + @After + public void tearDown() { + // reset the context ClassLoader of the current thread + Thread.currentThread().setContextClassLoader(classLoader); + } + @Test public void should_createAndDeployServerBDMJar_add_dependency_on_bdm_server_jar() throws Exception { BusinessObjectModel bom = BOMBuilder.aBOM().build(); @@ -129,7 +138,7 @@ public void uninstall_should_delete_a_dependency() throws Exception { public void uninstall_should_ignore_exception_if_the_dependency_does_not_exist() throws Exception { doThrow(new SDependencyNotFoundException("error")).when(dependencyService).deleteDependency("BDR"); - businessDataModelRepository.uninstall(45L); + assertThatNoException().isThrownBy(() -> businessDataModelRepository.uninstall(45L)); } @Test(expected = SBusinessDataRepositoryException.class) @@ -228,29 +237,25 @@ public void getInstalledBDMVersion_should_return_version_number(long version) th assertThat(installedBDMVersion).isEqualTo(String.valueOf(version)); } - @Rule - public ExpectedException expectedException = ExpectedException.none(); - @Test - public void update_should_convert_exceptions_to_allow_to_see_entire_root_cause() throws Exception { + public void update_should_convert_exceptions_to_allow_to_see_entire_root_cause() { // given: doReturn(singletonList(new CommandAcceptanceException("Error executing DDL bla bla bla...", new SQLSyntaxErrorException("ORA-02275: une telle contrainte référentielle existe déjà dans la table", - new Exception("Root Oracle Cause"))))).when(schemaManager).update(anySet()); - - // then: - expectedException.expect(SBusinessDataRepositoryDeploymentException.class); - expectedException.expectMessage( - "1: org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL bla bla bla..."); - expectedException.expectMessage("caused by java.sql.SQLSyntaxErrorException"); - expectedException.expectMessage("caused by java.lang.Exception: Root Oracle Cause"); - - // when: - businessDataModelRepository.update(new HashSet<>()); + new Exception("Root Oracle Cause"))))) + .when(schemaManager).update(anySet()); + + // when - then: + assertThatExceptionOfType(SBusinessDataRepositoryDeploymentException.class) + .isThrownBy(() -> businessDataModelRepository.update(new HashSet<>())) + .withMessageContainingAll( + "1: org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL bla bla bla...", + "caused by java.sql.SQLSyntaxErrorException", + "caused by java.lang.Exception: Root Oracle Cause"); } @Test - public void update_should_convert_all_exceptions_in_the_list() throws Exception { + public void update_should_convert_all_exceptions_in_the_list() { // given: doReturn(Arrays.asList( new CommandAcceptanceException("Error executing DDL bla bla bla...", @@ -258,19 +263,17 @@ public void update_should_convert_all_exceptions_in_the_list() throws Exception "ORA-02275: une telle contrainte référentielle existe déjà dans la table", new Exception("Root Oracle Cause"))), new CommandAcceptanceException("CommandAcceptanceException bliblibli", - new SQLSyntaxErrorException("Hibernate error")))).when(schemaManager).update(anySet()); - - // then: - expectedException.expect(SBusinessDataRepositoryDeploymentException.class); - expectedException.expectMessage( - "1: org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL bla bla bla..."); - expectedException.expectMessage("caused by java.lang.Exception: Root Oracle Cause"); - expectedException.expectMessage( - "2: org.hibernate.tool.schema.spi.CommandAcceptanceException: CommandAcceptanceException bliblibli"); - expectedException.expectMessage("caused by java.sql.SQLSyntaxErrorException: Hibernate error"); - - // when: - businessDataModelRepository.update(new HashSet<>()); + new SQLSyntaxErrorException("Hibernate error")))) + .when(schemaManager).update(anySet()); + + // when - then: + assertThatExceptionOfType(SBusinessDataRepositoryDeploymentException.class) + .isThrownBy(() -> businessDataModelRepository.update(new HashSet<>())) + .withMessageContainingAll( + "1: org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL bla bla bla...", + "caused by java.lang.Exception: Root Oracle Cause", + "2: org.hibernate.tool.schema.spi.CommandAcceptanceException: CommandAcceptanceException bliblibli", + "caused by java.sql.SQLSyntaxErrorException: Hibernate error"); } @Test diff --git a/services/bonita-business-data/bonita-business-data-impl/src/test/java/org/bonitasoft/engine/business/data/impl/BusinessDataServiceImplTest.java b/services/bonita-business-data/bonita-business-data-impl/src/test/java/org/bonitasoft/engine/business/data/impl/BusinessDataServiceImplTest.java index 5fc6ac8b161..881c620b741 100644 --- a/services/bonita-business-data/bonita-business-data-impl/src/test/java/org/bonitasoft/engine/business/data/impl/BusinessDataServiceImplTest.java +++ b/services/bonita-business-data/bonita-business-data-impl/src/test/java/org/bonitasoft/engine/business/data/impl/BusinessDataServiceImplTest.java @@ -13,7 +13,7 @@ **/ package org.bonitasoft.engine.business.data.impl; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; import java.io.Serializable; @@ -41,9 +41,7 @@ import org.bonitasoft.engine.business.data.proxy.ServerProxyfier; import org.bonitasoft.engine.commons.TypeConverterUtil; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; @@ -58,8 +56,6 @@ public class BusinessDataServiceImplTest { private static final String PARAMETER_BUSINESSDATA_CLASS_URI_VALUE = "/businessdata/{className}/{id}/{field}"; private static final String NEW_NAME = "new name"; private final Entity pojo = new EntityPojo(1L); - @Rule - public ExpectedException expectedException = ExpectedException.none(); @Mock JsonBusinessDataSerializer jsonEntitySerializer; @Mock @@ -73,78 +69,84 @@ public class BusinessDataServiceImplTest { private Entity businessData; @Mock private CountQueryProvider countQueryProvider; - private TypeConverterUtil typeConverterUtil; @Before - public void before() throws Exception { + public void before() { final String[] datePatterns = new String[] { "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd'T'HH:mm:ss", "yyyy-MM-dd", "HH:mm:ss", "yyyy-MM-dd'T'HH:mm:ss.SSS" }; - typeConverterUtil = new TypeConverterUtil(datePatterns); businessDataService = spy(new BusinessDataServiceImpl(businessDataRepository, jsonEntitySerializer, - businessDataModelRepository, typeConverterUtil, + businessDataModelRepository, new TypeConverterUtil(datePatterns), businessDataReloader, countQueryProvider)); } @Test - public void isBusinessDataShouldBeTrue() throws Exception { - - final Entity pojo = new EntityPojo(1L); + public void isBusinessDataShouldBeTrue() { assertThat(businessDataService.isBusinessData(pojo)).isTrue(); } @Test - public void isBusinessDataShouldBeTrueWithList() throws Exception { - assertThat(businessDataService.isBusinessData(Arrays.asList(pojo))).isTrue(); + public void isBusinessDataShouldBeTrueWithList() { + assertThat(businessDataService.isBusinessData(List.of(pojo))).isTrue(); assertThat(businessDataService.isBusinessData(new ArrayList())).isTrue(); } @Test - public void isBusinessDataShouldBeFalseWithList() throws Exception { + public void isBusinessDataShouldBeFalseWithList() { assertThat(businessDataService.isBusinessData("not a list")).isFalse(); - assertThat(businessDataService.isBusinessData(Arrays.asList(new Long(1L)))).isFalse(); + assertThat(businessDataService.isBusinessData(List.of(1L))).isFalse(); } @Test - public void isBusinessDataShouldBeFalse() throws Exception { - final Object pojo = new Object(); - assertThat(businessDataService.isBusinessData(pojo)).isFalse(); + public void isBusinessDataShouldBeFalse() { + final Object pojoObject = new Object(); + assertThat(businessDataService.isBusinessData(pojoObject)).isFalse(); } @Test - public void isBusinessDataShouldBeFalseWhenDataIsNull() throws Exception { + public void isBusinessDataShouldBeFalseWhenDataIsNull() { assertThat(businessDataService.isBusinessData(null)).isFalse(); } - @Test(expected = SBusinessDataNotFoundException.class) + @Test public void callJavaOperationShouldThrowExceptionWhenBusinessDataIsNull() throws Exception { - businessDataService.callJavaOperation(null, new EntityPojo(1L), "someMethod", String.class.getName()); + assertThatExceptionOfType(SBusinessDataNotFoundException.class) + .isThrownBy(() -> businessDataService.callJavaOperation(null, new EntityPojo(1L), "someMethod", + String.class.getName())); } @Test - public void callJavaOperationShouldInvokeListMethod() throws Exception { + public void callJavaOperationShouldInvokeListMethod() { final List entities = new ArrayList<>(); entities.add(new EntityPojo(1L)); - businessDataService.callJavaOperation(entities, entities, "contains", Object.class.getName()); + assertThatNoException() + .isThrownBy(() -> businessDataService.callJavaOperation(entities, entities, "contains", + Object.class.getName())); } - @Test(expected = SBusinessDataRepositoryException.class) - public void callJavaOperationShouldThrowExceptionWhenNotAnEntity() throws Exception { - businessDataService.callJavaOperation("not an entity", null, "getLengh", String.class.getName()); + @Test + public void callJavaOperationShouldThrowExceptionWhenNotAnEntity() { + assertThatExceptionOfType(SBusinessDataRepositoryException.class) + .isThrownBy(() -> businessDataService.callJavaOperation("not an entity", null, "getLengh", + String.class.getName())); } - @Test(expected = SBusinessDataNotFoundException.class) + @Test public void callJavaOperationShouldThrowExceptionWhenBusinessDataIsNotFound() throws Exception { //given doThrow(SBusinessDataNotFoundException.class).when(businessDataReloader).reloadEntitySoftly(pojo); //when - businessDataService.callJavaOperation(pojo, new EntityPojo(1L), "getName", String.class.getName()); + assertThatExceptionOfType(SBusinessDataNotFoundException.class) + .isThrownBy(() -> businessDataService.callJavaOperation(pojo, new EntityPojo(1L), "getName", + String.class.getName())); } - @Test(expected = SBusinessDataRepositoryException.class) + @Test public void callJavaOperationShouldThrowExceptionWheninvokeFails() throws Exception { - businessDataService.callJavaOperation(pojo, new EntityPojo(1L), "someMethod", String.class.getName()); + assertThatExceptionOfType(SBusinessDataRepositoryException.class) + .isThrownBy(() -> businessDataService.callJavaOperation(pojo, new EntityPojo(1L), "someMethod", + String.class.getName())); } @Test @@ -189,26 +191,25 @@ public void callJavaOperationShouldSetEntityComposition() throws Exception { assertThat(pojoObject).as("should return object").isNotNull(); assertThat(pojoObject.getCompositionEntity()).as("should have set entity").isEqualTo(compositionEntity); - verify(businessDataRepository, never()).findById(compositionEntity.getClass(), - compositionEntity.getPersistenceId()); + verify(businessDataReloader, never()).reloadEntity(any(Entity.class)); } @Test public void callJavaOperationShouldSetEntityAggregation() throws Exception { //given - final EntityPojo compositionEntity = new EntityPojo(2L); + final EntityPojo aggregationEntity = new EntityPojo(2L); doReturn(pojo).when(businessDataReloader).reloadEntitySoftly(pojo); + doReturn(aggregationEntity).when(businessDataReloader).reloadEntity(aggregationEntity); //when - final EntityPojo pojoObject = (EntityPojo) businessDataService.callJavaOperation(pojo, compositionEntity, - "setCompositionEntity", + final EntityPojo pojoObject = (EntityPojo) businessDataService.callJavaOperation(pojo, aggregationEntity, + "setAggregationEntity", Entity.class.getName()); assertThat(pojoObject).as("should return object").isNotNull(); - assertThat(pojoObject.getCompositionEntity()).as("should have set entity").isEqualTo(compositionEntity); - verify(businessDataRepository, never()).findById(compositionEntity.getClass(), - compositionEntity.getPersistenceId()); + assertThat(pojoObject.getAggregationEntity()).as("should have set entity").isEqualTo(aggregationEntity); + verify(businessDataReloader).reloadEntity(aggregationEntity); } @Test @@ -295,7 +296,7 @@ public void callJavaOperationShouldNotLoadEntitiesIfComposition() throws Excepti } @Test - public void callJavaOperationShouldThrowExceptionWhenPersistenceIdIsNull() throws Exception { + public void callJavaOperationShouldThrowExceptionWhenPersistenceIdIsNull() { //given final Long persistenceId1 = 1562L; @@ -304,21 +305,18 @@ public void callJavaOperationShouldThrowExceptionWhenPersistenceIdIsNull() throw final List entities = Arrays.asList(entity1, entity2); doReturn(EntityPojo.class).when(businessDataReloader).getEntityRealClass(entity2); - // expect - expectedException.expect(SBusinessDataNotFoundException.class); - expectedException.expectMessage( - "Forbidden instance of org.bonitasoft.engine.business.data.impl.EntityPojo found. It is only possible to reference persisted instances in an aggregation relation."); - - //when - businessDataService.callJavaOperation(pojo, entities, "setAggregationEntities", List.class.getName()); + //when - then + assertThatExceptionOfType(SBusinessDataNotFoundException.class) + .isThrownBy(() -> businessDataService.callJavaOperation(pojo, entities, "setAggregationEntities", + List.class.getName())) + .withMessage("Forbidden instance of org.bonitasoft.engine.business.data.impl.EntityPojo found. " + + "It is only possible to reference persisted instances in an aggregation relation."); } @Test public void callJavaOperationWithEmptyList() throws Exception { //given - final List entities = Arrays.asList(); - final List keys = Arrays.asList(); - + final List entities = List.of(); doReturn(pojo).when(businessDataReloader).reloadEntitySoftly(pojo); //when @@ -369,8 +367,8 @@ public void shouldSetListOnBusinessDataReplaceTheList() throws Exception { final EntityPojo entityPojo = new EntityPojo(1L); entityPojo.getAggregationEntities().add(entity1); - final List newEntities = Arrays.asList(entity2); - final List keys2 = Arrays.asList(persistenceId2); + final List newEntities = List.of(entity2); + final List keys2 = List.of(persistenceId2); doReturn(entityPojo).when(businessDataReloader).reloadEntitySoftly(entityPojo); // Cannot specify the real instance (instead of any()) because of proxy object that does not match (Mockito): doReturn(pojo.getClass()).when(businessDataReloader).getEntityRealClass(any(Entity.class)); @@ -395,12 +393,10 @@ public void should_loadClass_find_the_class() throws Exception { assertThat(loadClass).isEqualTo(pojo.getClass()); } - @Test(expected = SBusinessDataRepositoryException.class) - public void should_loadClass_throw_exception() throws Exception { - //when - businessDataService.loadClass("not a class"); - - //then exception + @Test + public void should_loadClass_throw_exception() { + assertThatExceptionOfType(SBusinessDataRepositoryException.class) + .isThrownBy(() -> businessDataService.loadClass("not a class")); } @Test @@ -417,7 +413,7 @@ public void should_getJsonEntity_serialize_entity() throws Exception { } - @Test(expected = SBusinessDataRepositoryException.class) + @Test public void should_getJsonEntity_throw_exception() throws Exception { //given doReturn(pojo).when(businessDataRepository).findById(pojo.getClass(), pojo.getPersistenceId()); @@ -425,8 +421,9 @@ public void should_getJsonEntity_throw_exception() throws Exception { PARAMETER_BUSINESSDATA_CLASS_URI_VALUE); //when then exception - businessDataService.getJsonEntity(pojo.getClass().getName(), pojo.getPersistenceId(), - PARAMETER_BUSINESSDATA_CLASS_URI_VALUE); + assertThatExceptionOfType(SBusinessDataRepositoryException.class) + .isThrownBy(() -> businessDataService.getJsonEntity(pojo.getClass().getName(), pojo.getPersistenceId(), + PARAMETER_BUSINESSDATA_CLASS_URI_VALUE)); } @Test @@ -541,10 +538,6 @@ public void getJsonQueryEntities_should_return_count_result_as_json() throws Exc @Test public void getJsonQueryEntities_should_throw_exception_when_query_not_found() throws Exception { - expectedException.expect(SBusinessDataRepositoryException.class); - expectedException - .expectMessage("unable to get query wrongQuery for business object " + EntityPojo.class.getName()); - //given final EntityPojo entity = new EntityPojo(1562L); final Map parameters = new HashMap<>(); @@ -558,8 +551,10 @@ public void getJsonQueryEntities_should_throw_exception_when_query_not_found() t doReturn(businessObjectModel).when(businessDataModelRepository).getBusinessObjectModel(); //when then exception - businessDataService.getJsonQueryEntities(entity.getClass().getName(), "wrongQuery", parameters, 0, 10, - PARAMETER_BUSINESSDATA_CLASS_URI_VALUE); + assertThatExceptionOfType(SBusinessDataRepositoryException.class) + .isThrownBy(() -> businessDataService.getJsonQueryEntities(entity.getClass().getName(), "wrongQuery", + parameters, 0, 10, PARAMETER_BUSINESSDATA_CLASS_URI_VALUE)) + .withMessage("unable to get query wrongQuery for business object " + EntityPojo.class.getName()); } @Test @@ -575,7 +570,6 @@ public void getJsonQueryEntities_should_find_provided_query() throws Exception { doReturn(entity.getClass()).when(businessDataService).loadClass(entity.getClass().getName()); final BusinessObjectModel businessObjectModel = getBusinessObjectModel(entity); doReturn(businessObjectModel).when(businessDataModelRepository).getBusinessObjectModel(); - // Query findQuery=new Query("find","query"); Query countQuery = new Query("countForFind", "query", Long.class.getName()); doReturn(countQuery).when(countQueryProvider).getCountQueryDefinition(any(BusinessObject.class), any(Query.class)); @@ -606,12 +600,6 @@ public void getJsonQueryEntities_should_find_provided_query() throws Exception { @Test public void getJsonQueryEntities_should_check_parameters() throws Exception { - expectedException.expect(SBusinessDataRepositoryException.class); - expectedException.expectMessage("parameter(s) are missing for query named query :"); - expectedException.expectMessage(PARAMETER_INTEGER); - expectedException.expectMessage(PARAMETER_STRING); - expectedException.expectMessage(PARAMETER_LONG); - //given final EntityPojo entity = new EntityPojo(1562L); doReturn(entity.getClass()).when(businessDataService).loadClass(entity.getClass().getName()); @@ -620,8 +608,11 @@ public void getJsonQueryEntities_should_check_parameters() throws Exception { doReturn(businessObjectModel).when(businessDataModelRepository).getBusinessObjectModel(); //when then exception - businessDataService.getJsonQueryEntities(entity.getClass().getName(), "query", null, 0, 10, - PARAMETER_BUSINESSDATA_CLASS_URI_VALUE); + assertThatExceptionOfType(SBusinessDataRepositoryException.class) + .isThrownBy(() -> businessDataService.getJsonQueryEntities(entity.getClass().getName(), "query", null, + 0, 10, PARAMETER_BUSINESSDATA_CLASS_URI_VALUE)) + .withMessageContainingAll("parameter(s) are missing for query named query :", PARAMETER_INTEGER, + PARAMETER_STRING, PARAMETER_LONG); } private BusinessObjectModel getBusinessObjectModel(final EntityPojo entity) { @@ -635,7 +626,7 @@ private BusinessObjectModel getBusinessObjectModel(final EntityPojo entity) { final BusinessObject businessObject = new BusinessObject(); businessObject.setQualifiedName(entity.getClass().getName()); - businessObject.setQueries(Arrays.asList(query)); + businessObject.setQueries(List.of(query)); businessObjectModel.getBusinessObjects().add(businessObject); return businessObjectModel; @@ -661,7 +652,7 @@ public void getJsonEntities_should_serialize_entities() throws Exception { verify(jsonEntitySerializer).serializeEntities(pojos, PARAMETER_BUSINESSDATA_CLASS_URI_VALUE); } - @Test(expected = SBusinessDataRepositoryException.class) + @Test public void getJsonEntities_should_throw_exception_if_the_serialization_fails() throws Exception { final long identifier1 = 1983L; final long identifier2 = 1990L; @@ -677,8 +668,9 @@ public void getJsonEntities_should_throw_exception_if_the_serialization_fails() when(jsonEntitySerializer.serializeEntities(pojos, PARAMETER_BUSINESSDATA_CLASS_URI_VALUE)) .thenThrow(new SBusinessDataRepositorySerializationException("exception")); - businessDataService.getJsonEntities(EntityPojo.class.getName(), identifiers, - PARAMETER_BUSINESSDATA_CLASS_URI_VALUE); + assertThatExceptionOfType(SBusinessDataRepositoryException.class) + .isThrownBy(() -> businessDataService.getJsonEntities(EntityPojo.class.getName(), identifiers, + PARAMETER_BUSINESSDATA_CLASS_URI_VALUE)); } } diff --git a/services/bonita-business-data/bonita-business-data-impl/src/test/resources/datasource/datasource-dependency-mysql.xml b/services/bonita-business-data/bonita-business-data-impl/src/test/resources/datasource/datasource-dependency-mysql.xml deleted file mode 100644 index 3b0e51a6444..00000000000 --- a/services/bonita-business-data/bonita-business-data-impl/src/test/resources/datasource/datasource-dependency-mysql.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - org.hibernate.dialect.MySQL8Dialect - com.mysql.cj.jdbc.MysqlXADataSource - localhost - 3306 - bonita - root - root - jdbc:mysql://${db.server.name}:${db.server.port}/${db.database.name}?useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true - - - - - - - - ${db.user} - ${db.password} - ${db.url} - - - - - diff --git a/services/bonita-business-data/bonita-business-data-impl/src/test/resources/datasource/datasource-dependency-oracle.xml b/services/bonita-business-data/bonita-business-data-impl/src/test/resources/datasource/datasource-dependency-oracle.xml deleted file mode 100644 index 16f356b3df2..00000000000 --- a/services/bonita-business-data/bonita-business-data-impl/src/test/resources/datasource/datasource-dependency-oracle.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - org.hibernate.dialect.Oracle12cDialect - oracle.jdbc.xa.client.OracleXADataSource - localhost - 1521 - ${db.database.name:ORCLPDB1.localdomain} - bonita - bpm - jdbc:oracle:thin:@//${db.server.name}:${db.server.port}/${db.instance.name}?oracle.net.disableOob=true - - - - - - - - ${db.user} - ${db.password} - jdbc:oracle:thin:@//${db.server.name}:${db.server.port}/${db.instance.name}?oracle.net.disableOob=true - - - - - diff --git a/services/bonita-business-data/bonita-business-data-impl/src/test/resources/datasource/datasource-dependency-sqlserver.xml b/services/bonita-business-data/bonita-business-data-impl/src/test/resources/datasource/datasource-dependency-sqlserver.xml deleted file mode 100644 index e048197594e..00000000000 --- a/services/bonita-business-data/bonita-business-data-impl/src/test/resources/datasource/datasource-dependency-sqlserver.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - org.bonitasoft.engine.persistence.SQLServerExtendedDialect - com.microsoft.sqlserver.jdbc.SQLServerXADataSource - localhost - 1533 - bonita_engine - sa - Bonita12 - jdbc:sqlserver://${db.server.name}:${db.server.port};database=${db.database.name} - - - - - - - - ${db.user} - ${db.password} - ${db.url} - - - - - \ No newline at end of file diff --git a/services/bonita-cache/build.gradle b/services/bonita-cache/build.gradle index ee4e5997ce5..03e4dfa6244 100644 --- a/services/bonita-cache/build.gradle +++ b/services/bonita-cache/build.gradle @@ -9,7 +9,6 @@ dependencies { annotationProcessor libs.lombok compileOnly libs.lombok - testImplementation libs.junit4 testImplementation libs.mockitoCore testImplementation libs.logback } diff --git a/services/bonita-classloader/build.gradle b/services/bonita-classloader/build.gradle index 5713c52ebab..71652441a06 100644 --- a/services/bonita-classloader/build.gradle +++ b/services/bonita-classloader/build.gradle @@ -13,7 +13,6 @@ dependencies { api(libs.javaxAnnotations) testImplementation libs.mockitoCore - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.logback testImplementation libs.systemRules diff --git a/services/bonita-command/build.gradle b/services/bonita-command/build.gradle index 6b976b970b5..08f692dde44 100644 --- a/services/bonita-command/build.gradle +++ b/services/bonita-command/build.gradle @@ -6,7 +6,6 @@ dependencies { api project(':services:bonita-builder') api project(':services:bonita-events') api project(':services:bonita-persistence') - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.mockitoCore testImplementation libs.logback diff --git a/services/bonita-commons/build.gradle b/services/bonita-commons/build.gradle index 49708b6aad5..cc0b7de4739 100644 --- a/services/bonita-commons/build.gradle +++ b/services/bonita-commons/build.gradle @@ -12,16 +12,12 @@ dependencies { api libs.springContext api libs.springBootAutoconfigure api libs.slf4jApi - testImplementation libs.junit4 - testImplementation libs.junit5api testImplementation libs.assertj testImplementation libs.mockitoCore testImplementation libs.mockitoJunitJupiter testImplementation libs.systemRules testImplementation libs.systemLambda testImplementation libs.logback - testRuntimeOnly libs.junitJupiterEngine - testRuntimeOnly libs.junitVintageEngine annotationProcessor libs.lombok compileOnly libs.lombok @@ -29,10 +25,6 @@ dependencies { description = 'Bonita Engine Util Classes' -test { - useJUnitPlatform { includeEngines 'junit-jupiter', 'junit-vintage' } -} - tasks.register("sourcesJar", Jar) { from sourceSets.main.allJava archiveClassifier = 'sources' diff --git a/services/bonita-connector-executor/build.gradle b/services/bonita-connector-executor/build.gradle index edfc5419217..01addcd96d1 100644 --- a/services/bonita-connector-executor/build.gradle +++ b/services/bonita-connector-executor/build.gradle @@ -9,7 +9,6 @@ dependencies { api project(':services:bonita-session') testImplementation libs.assertj testImplementation libs.mockitoCore - testImplementation libs.junit4 testImplementation libs.systemRules annotationProcessor libs.lombok compileOnly libs.lombok diff --git a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/dbconfig/MySQLDataSourceConfig.java b/services/bonita-connector-executor/src/main/java/org/bonitasoft/engine/connector/BonitaConnectorExecutorFactory.java similarity index 59% rename from platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/dbconfig/MySQLDataSourceConfig.java rename to services/bonita-connector-executor/src/main/java/org/bonitasoft/engine/connector/BonitaConnectorExecutorFactory.java index 1a6cb2d298a..fd177a98723 100644 --- a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/dbconfig/MySQLDataSourceConfig.java +++ b/services/bonita-connector-executor/src/main/java/org/bonitasoft/engine/connector/BonitaConnectorExecutorFactory.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2019 Bonitasoft S.A. + * Copyright (C) 2024 Bonitasoft S.A. * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble * This library is free software; you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Foundation @@ -11,20 +11,12 @@ * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301, USA. **/ -package org.bonitasoft.platform.setup.dbconfig; +package org.bonitasoft.engine.connector; -import org.springframework.context.annotation.Profile; -import org.springframework.context.annotation.PropertySource; -import org.springframework.stereotype.Component; +import java.util.concurrent.ThreadPoolExecutor; -/** - * This is enough to get a Datasource that spring creates using parameters provided in properties. - * - * @author Emmanuel Duchastenier - */ -@Component -@PropertySource("classpath:/mysql.properties") -@Profile("mysql") -public class MySQLDataSourceConfig { +public interface BonitaConnectorExecutorFactory { + + ThreadPoolExecutor create(); } diff --git a/services/bonita-connector-executor/src/main/java/org/bonitasoft/engine/connector/impl/ConnectorExecutorImpl.java b/services/bonita-connector-executor/src/main/java/org/bonitasoft/engine/connector/impl/ConnectorExecutorImpl.java index 05213aceaa4..0d051a16914 100644 --- a/services/bonita-connector-executor/src/main/java/org/bonitasoft/engine/connector/impl/ConnectorExecutorImpl.java +++ b/services/bonita-connector-executor/src/main/java/org/bonitasoft/engine/connector/impl/ConnectorExecutorImpl.java @@ -18,14 +18,9 @@ import java.util.Arrays; import java.util.Collection; import java.util.Map; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.RejectedExecutionHandler; -import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Collectors; @@ -36,6 +31,7 @@ import io.micrometer.core.instrument.Tags; import lombok.extern.slf4j.Slf4j; import org.bonitasoft.engine.commons.exceptions.SBonitaRuntimeException; +import org.bonitasoft.engine.connector.BonitaConnectorExecutorFactory; import org.bonitasoft.engine.connector.ConnectorExecutionResult; import org.bonitasoft.engine.connector.ConnectorExecutor; import org.bonitasoft.engine.connector.SConnector; @@ -47,6 +43,9 @@ import org.bonitasoft.engine.sessionaccessor.SessionIdNotSetException; import org.bonitasoft.engine.tracking.TimeTracker; import org.bonitasoft.engine.tracking.TimeTrackerRecords; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; +import org.springframework.stereotype.Component; /** * Execute connectors directly @@ -56,72 +55,44 @@ * @author Matthieu Chaffotte */ @Slf4j +@Component +@ConditionalOnSingleCandidate(ConnectorExecutor.class) public class ConnectorExecutorImpl implements ConnectorExecutor { public static final String NUMBER_OF_CONNECTORS_PENDING = "bonita.bpmengine.connector.pending"; public static final String NUMBER_OF_CONNECTORS_RUNNING = "bonita.bpmengine.connector.running"; public static final String NUMBER_OF_CONNECTORS_EXECUTED = "bonita.bpmengine.connector.executed"; + public static final String CONNECTORS_UNIT = "connectors"; private ExecutorService executorService; - + private final BonitaConnectorExecutorFactory bonitaConnectorExecutorFactory; private final SessionAccessor sessionAccessor; - private final SessionService sessionService; - private final int queueCapacity; - - private final int corePoolSize; - - private final int maximumPoolSize; - - private final long keepAliveTimeSeconds; - private final TimeTracker timeTracker; - private MeterRegistry meterRegistry; - private long tenantId; - private ExecutorServiceMetricsProvider executorServiceMetricsProvider; + private final MeterRegistry meterRegistry; + private final long tenantId; + private final ExecutorServiceMetricsProvider executorServiceMetricsProvider; private final AtomicLong runningWorks = new AtomicLong(); private Counter executedWorkCounter; private Gauge numberOfConnectorsPending; private Gauge numberOfConnectorsRunning; - /** - * The handling of threads relies on the JVM - * The rules to create new thread are: - * - If the number of threads is less than the corePoolSize, create a new Thread to run a new task. - * - If the number of threads is equal (or greater than) the corePoolSize, put the task into the queue. - * - If the queue is full, and the number of threads is less than the maxPoolSize, create a new thread to run tasks - * in. - * - If the queue is full, and the number of threads is greater than or equal to maxPoolSize, reject the task. - * - * @param queueCapacity - * The maximum number of execution of connector to queue for each thread - * @param corePoolSize - * the number of threads to keep in the pool, even - * if they are idle, unless {@code allowCoreThreadTimeOut} is set - * @param maximumPoolSize - * the maximum number of threads to allow in the - * pool - * @param keepAliveTimeSeconds - * when the number of threads is greater than - * the core, this is the maximum time that excess idle threads - * will wait for new tasks before terminating. (in seconds) - */ - public ConnectorExecutorImpl(final int queueCapacity, final int corePoolSize, - final int maximumPoolSize, final long keepAliveTimeSeconds, final SessionAccessor sessionAccessor, - final SessionService sessionService, final TimeTracker timeTracker, final MeterRegistry meterRegistry, - long tenantId, ExecutorServiceMetricsProvider executorServiceMetricsProvider) { - this.queueCapacity = queueCapacity; - this.corePoolSize = corePoolSize; - this.maximumPoolSize = maximumPoolSize; - this.keepAliveTimeSeconds = keepAliveTimeSeconds; + public ConnectorExecutorImpl(final SessionAccessor sessionAccessor, + final SessionService sessionService, + final TimeTracker timeTracker, + final MeterRegistry meterRegistry, + @Value("${tenantId}") long tenantId, + ExecutorServiceMetricsProvider executorServiceMetricsProvider, + BonitaConnectorExecutorFactory bonitaConnectorExecutorFactory) { this.sessionAccessor = sessionAccessor; this.sessionService = sessionService; this.timeTracker = timeTracker; this.meterRegistry = meterRegistry; this.tenantId = tenantId; this.executorServiceMetricsProvider = executorServiceMetricsProvider; + this.bonitaConnectorExecutorFactory = bonitaConnectorExecutorFactory; } @Override @@ -187,7 +158,7 @@ void disconnectSilently(final SConnector sConnector) { try { sConnector.disconnect(); } catch (final Exception t) { - log.warn("An error occurred while disconnecting the connector: " + sConnector, t); + log.warn("An error occurred while disconnecting the connector: {}", sConnector, t); } } @@ -283,46 +254,26 @@ public boolean isCompleted() { } } - private final class QueueRejectedExecutionHandler implements RejectedExecutionHandler { - - public QueueRejectedExecutionHandler() { - - } - - @Override - public void rejectedExecution(final Runnable task, final ThreadPoolExecutor executor) { - log.warn("The work was rejected. Requeue work : {}", task.toString()); - try { - executor.getQueue().put(task); - } catch (final InterruptedException e) { - throw new RejectedExecutionException("Queuing " + task + " got interrupted.", e); - } - } - - } - @Override public void start() { if (executorService == null) { - final BlockingQueue workQueue = new ArrayBlockingQueue<>(queueCapacity); - final RejectedExecutionHandler handler = new QueueRejectedExecutionHandler(); - final ConnectorExecutorThreadFactory threadFactory = new ConnectorExecutorThreadFactory( - "ConnectorExecutor"); + var threadPoolExecutor = bonitaConnectorExecutorFactory.create(); executorService = executorServiceMetricsProvider .bind(meterRegistry, - new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTimeSeconds, - TimeUnit.SECONDS, - workQueue, threadFactory, handler), - "bonita-connector-executor", tenantId); + threadPoolExecutor, + "bonita-connector-executor", + tenantId); Tags tags = Tags.of("tenant", String.valueOf(tenantId)); - numberOfConnectorsPending = Gauge.builder(NUMBER_OF_CONNECTORS_PENDING, workQueue, Collection::size) - .tags(tags).baseUnit("connectors").description("Connectors pending in the execution queue") + numberOfConnectorsPending = Gauge + .builder(NUMBER_OF_CONNECTORS_PENDING, threadPoolExecutor.getQueue(), Collection::size) + .tags(tags).baseUnit(CONNECTORS_UNIT).description("Connectors pending in the execution queue") .register(meterRegistry); numberOfConnectorsRunning = Gauge.builder(NUMBER_OF_CONNECTORS_RUNNING, runningWorks, AtomicLong::get) - .tags(tags).baseUnit("connectors").description("Connectors currently executing") + .tags(tags).baseUnit(CONNECTORS_UNIT).description("Connectors currently executing") .register(meterRegistry); executedWorkCounter = Counter.builder(NUMBER_OF_CONNECTORS_EXECUTED) - .tags(tags).baseUnit("connectors").description("Total connectors executed since last server start") + .tags(tags).baseUnit(CONNECTORS_UNIT) + .description("Total connectors executed since last server start") .register(meterRegistry); } } diff --git a/services/bonita-connector-executor/src/main/java/org/bonitasoft/engine/connector/impl/ConnectorSingleThreadExecutorFactory.java b/services/bonita-connector-executor/src/main/java/org/bonitasoft/engine/connector/impl/ConnectorSingleThreadExecutorFactory.java new file mode 100644 index 00000000000..192ee9dd664 --- /dev/null +++ b/services/bonita-connector-executor/src/main/java/org/bonitasoft/engine/connector/impl/ConnectorSingleThreadExecutorFactory.java @@ -0,0 +1,62 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.engine.connector.impl; + +import static java.util.concurrent.TimeUnit.*; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadPoolExecutor; + +import org.bonitasoft.engine.connector.BonitaConnectorExecutorFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; +import org.springframework.stereotype.Component; + +@Component +@ConditionalOnSingleCandidate(BonitaConnectorExecutorFactory.class) +public class ConnectorSingleThreadExecutorFactory implements BonitaConnectorExecutorFactory { + + private final int queueCapacity; + + public ConnectorSingleThreadExecutorFactory(@Value("${bonita.tenant.connector.queueCapacity}") int queueCapacity) { + this.queueCapacity = queueCapacity; + } + + @Override + public ThreadPoolExecutor create() { + return new ThreadPoolExecutor(1, 1, 0L, MILLISECONDS, + new ArrayBlockingQueue<>(queueCapacity), new ConnectorExecutorThreadFactory("ConnectorExecutor"), + new QueueRejectedExecutionHandler()); + } + + public static class QueueRejectedExecutionHandler implements RejectedExecutionHandler { + + private static final Logger log = LoggerFactory.getLogger(QueueRejectedExecutionHandler.class); + + @Override + public void rejectedExecution(final Runnable task, final ThreadPoolExecutor executor) { + log.warn("The work was rejected. Requeue work : {}", task); + try { + executor.getQueue().put(task); + } catch (final InterruptedException e) { + throw new RejectedExecutionException("Queuing " + task + " got interrupted.", e); + } + } + + } +} diff --git a/services/bonita-connector-executor/src/test/java/org/bonitasoft/engine/connector/impl/ConnectorExecutorImplIT.java b/services/bonita-connector-executor/src/test/java/org/bonitasoft/engine/connector/impl/ConnectorExecutorImplIT.java index b6d127ce586..0d3d36a1c4c 100644 --- a/services/bonita-connector-executor/src/test/java/org/bonitasoft/engine/connector/impl/ConnectorExecutorImplIT.java +++ b/services/bonita-connector-executor/src/test/java/org/bonitasoft/engine/connector/impl/ConnectorExecutorImplIT.java @@ -56,9 +56,13 @@ public class ConnectorExecutorImplIT { @Before public void setUp() { - connectorExecutor = new ConnectorExecutorImpl(10, 5, 100, 100, sessionAccessor, + connectorExecutor = new ConnectorExecutorImpl(sessionAccessor, sessionService, - timeTracker, new SimpleMeterRegistry(), 12L, new DefaultExecutorServiceMetricsProvider()); + timeTracker, + new SimpleMeterRegistry(), + 12L, + new DefaultExecutorServiceMetricsProvider(), + new ConnectorSingleThreadExecutorFactory(10)); connectorExecutor.start(); } diff --git a/services/bonita-connector-executor/src/test/java/org/bonitasoft/engine/connector/impl/ConnectorExecutorImplTest.java b/services/bonita-connector-executor/src/test/java/org/bonitasoft/engine/connector/impl/ConnectorExecutorImplTest.java index acf10b714b3..289981ad6ff 100644 --- a/services/bonita-connector-executor/src/test/java/org/bonitasoft/engine/connector/impl/ConnectorExecutorImplTest.java +++ b/services/bonita-connector-executor/src/test/java/org/bonitasoft/engine/connector/impl/ConnectorExecutorImplTest.java @@ -15,7 +15,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; import java.time.Duration; import java.util.Collections; @@ -72,9 +73,12 @@ public void before() { // So that micrometer updates its counters every 1 ms: k -> k.equals("simple.step") ? Duration.ofMillis(1).toString() : null, Clock.SYSTEM); - connectorExecutorImpl = new ConnectorExecutorImpl(1, 1, 1, 1, sessionAccessor, sessionService, + connectorExecutorImpl = new ConnectorExecutorImpl(sessionAccessor, sessionService, timeTracker, - meterRegistry, TENANT_ID, new DefaultExecutorServiceMetricsProvider()); + meterRegistry, + TENANT_ID, + new DefaultExecutorServiceMetricsProvider(), + new ConnectorSingleThreadExecutorFactory(1)); connectorExecutorImpl.start(); } diff --git a/services/bonita-data-instance/build.gradle b/services/bonita-data-instance/build.gradle index 1b9d96b5bcc..11de58ba99c 100644 --- a/services/bonita-data-instance/build.gradle +++ b/services/bonita-data-instance/build.gradle @@ -9,7 +9,6 @@ dependencies { api project(':services:bonita-events') api project(':services:bonita-log') api project(':services:bonita-archive') - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.mockitoCore testImplementation libs.logback diff --git a/services/bonita-events/build.gradle b/services/bonita-events/build.gradle index 5adbfe16cf6..b88437c7dd7 100644 --- a/services/bonita-events/build.gradle +++ b/services/bonita-events/build.gradle @@ -3,7 +3,6 @@ dependencies { api project(':services:bonita-commons') testImplementation libs.mockitoCore - testImplementation libs.junit4 testImplementation libs.logback } diff --git a/services/bonita-expression/build.gradle b/services/bonita-expression/build.gradle index 92721bd6850..e8cf3a7d82f 100644 --- a/services/bonita-expression/build.gradle +++ b/services/bonita-expression/build.gradle @@ -9,7 +9,6 @@ dependencies { compileOnly libs.lombok api libs.bundles.groovy api libs.commonsLang - testImplementation libs.junit4 testImplementation libs.logback testImplementation libs.mockitoCore testImplementation libs.assertj diff --git a/services/bonita-identity/build.gradle b/services/bonita-identity/build.gradle index e7c91beb2ad..0cb45a9bc83 100644 --- a/services/bonita-identity/build.gradle +++ b/services/bonita-identity/build.gradle @@ -8,7 +8,6 @@ dependencies { api project(':services:bonita-commons') api project(':services:bonita-events') api libs.jakartaActivation - testImplementation libs.junit4 testImplementation libs.mockitoCore testImplementation libs.assertj diff --git a/services/bonita-incident/build.gradle b/services/bonita-incident/build.gradle index bad6767d7da..68d45815503 100644 --- a/services/bonita-incident/build.gradle +++ b/services/bonita-incident/build.gradle @@ -1,7 +1,6 @@ dependencies { api project(':bpm:bonita-common') api project(':bpm:bonita-core:bonita-home-server') - testImplementation libs.junit4 testImplementation libs.mockitoCore testImplementation libs.systemRules testRuntimeOnly libs.logback diff --git a/services/bonita-lock/build.gradle b/services/bonita-lock/build.gradle index 324a1f2a0c8..261379dc561 100644 --- a/services/bonita-lock/build.gradle +++ b/services/bonita-lock/build.gradle @@ -3,7 +3,6 @@ dependencies { api project(':services:bonita-commons') api project(':services:bonita-session') - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.logback } diff --git a/services/bonita-log/build.gradle b/services/bonita-log/build.gradle index c2c9225c483..b51a2c518f6 100644 --- a/services/bonita-log/build.gradle +++ b/services/bonita-log/build.gradle @@ -7,7 +7,6 @@ dependencies { api project(':services:bonita-builder') api project(':services:bonita-platform') api project(':services:bonita-transaction') - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.mockitoCore testImplementation libs.logback diff --git a/services/bonita-page/build.gradle b/services/bonita-page/build.gradle index 1a567ca13f9..c7928587de0 100644 --- a/services/bonita-page/build.gradle +++ b/services/bonita-page/build.gradle @@ -9,7 +9,6 @@ dependencies { testImplementation libs.assertj testImplementation libs.mockitoCore - testImplementation libs.junit4 testImplementation libs.logback testImplementation testFixtures(project(':bpm:bonita-common')) diff --git a/services/bonita-persistence/build.gradle b/services/bonita-persistence/build.gradle index 3e39adfc1cb..b3b79f45cb5 100644 --- a/services/bonita-persistence/build.gradle +++ b/services/bonita-persistence/build.gradle @@ -1,7 +1,3 @@ -plugins { - id('bonita-tests') -} - dependencies { api libs.commonsLang api project(':services:bonita-events') @@ -14,16 +10,20 @@ dependencies { api project(':services:bonita-commons') api project(':services:bonita-lock') api libs.slf4jApi + implementation(libs.javaxAnnotations) - testImplementation libs.junit4 - testImplementation libs.mockitoCore - testImplementation libs.assertj + compileOnly libs.jakartaTransactionApi annotationProcessor libs.lombok compileOnly libs.lombok - testRuntimeOnly libs.logback + + testImplementation libs.mockitoCore + testImplementation libs.assertj testImplementation libs.systemRules + testAnnotationProcessor libs.lombok testImplementation libs.lombok + + testRuntimeOnly libs.logback } diff --git a/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/CustomDataTypesRegistration.java b/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/CustomDataTypesRegistration.java index 748f1047355..4ca8b54df58 100644 --- a/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/CustomDataTypesRegistration.java +++ b/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/CustomDataTypesRegistration.java @@ -16,6 +16,7 @@ import java.util.HashSet; import java.util.Set; +import lombok.Getter; import org.hibernate.boot.SessionFactoryBuilder; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.boot.spi.SessionFactoryBuilderFactory; @@ -27,6 +28,7 @@ public class CustomDataTypesRegistration implements SessionFactoryBuilderFactory private static final org.slf4j.Logger logger = LoggerFactory.getLogger(CustomDataTypesRegistration.class); + @Getter private static Set typeOverrides = new HashSet<>(); @Override @@ -39,11 +41,8 @@ public SessionFactoryBuilder getSessionFactoryBuilder(final MetadataImplementor return defaultBuilder; } - static void addTypeOverride(BasicType type) { + public static void addTypeOverride(BasicType type) { typeOverrides.add(type); } - public static Set getTypeOverrides() { - return typeOverrides; - } } diff --git a/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/HibernateConfigurationProviderImpl.java b/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/HibernateConfigurationProviderImpl.java index 031990fc526..8e43fe9be5a 100644 --- a/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/HibernateConfigurationProviderImpl.java +++ b/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/HibernateConfigurationProviderImpl.java @@ -13,7 +13,7 @@ **/ package org.bonitasoft.engine.persistence; -import static org.bonitasoft.engine.services.Vendor.*; +import static org.bonitasoft.engine.services.Vendor.POSTGRES; import java.util.ArrayList; import java.util.Collections; @@ -23,6 +23,7 @@ import javax.persistence.SharedCacheMode; +import lombok.Getter; import org.bonitasoft.engine.services.Vendor; import org.hibernate.Interceptor; import org.hibernate.SessionFactory; @@ -30,11 +31,11 @@ import org.hibernate.boot.MetadataBuilder; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.SessionFactoryBuilder; -import org.hibernate.boot.registry.BootstrapServiceRegistry; import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.mapping.PersistentClass; +import org.hibernate.service.ServiceRegistry; import org.hibernate.type.BasicType; /** @@ -47,9 +48,12 @@ public class HibernateConfigurationProviderImpl implements HibernateConfiguratio private final HibernateResourcesConfigurationProvider hibernateResourcesConfigurationProvider; protected final Properties properties; private final List mappingExclusions; - private Vendor vendor; + @Getter + protected Vendor vendor; + @Getter private SessionFactory sessionFactory; - private List> mappedClasses = new ArrayList<>(); + @Getter + private final List> mappedClasses = new ArrayList<>(); public HibernateConfigurationProviderImpl(final Properties properties, final HibernateResourcesConfigurationProvider hibernateResourcesConfigurationProvider, @@ -76,27 +80,45 @@ public Map getCacheQueries() { @Override public void bootstrap(Properties extraHibernateProperties) { - BootstrapServiceRegistryBuilder bootstrapRegistryBuilder = new BootstrapServiceRegistryBuilder(); - BootstrapServiceRegistry bootstrapRegistry = bootstrapRegistryBuilder.build(); - StandardServiceRegistryBuilder standardRegistryBuilder = new StandardServiceRegistryBuilder(bootstrapRegistry); + StandardServiceRegistryBuilder standardRegistryBuilder = new StandardServiceRegistryBuilder( + new BootstrapServiceRegistryBuilder().build()); Properties allProps = gatherAllProperties(extraHibernateProperties, standardRegistryBuilder); - this.vendor = Vendor.fromHibernateDialectProperty(allProps.getProperty("hibernate.dialect")); StandardServiceRegistry standardRegistry = standardRegistryBuilder.build(); + + this.vendor = Vendor.fromHibernateDialectProperty(allProps.getProperty("hibernate.dialect")); + setCustomHibernateDataTypesAndProperties(); + + Metadata metadata = buildHibernateMetadata(standardRegistry); + + this.sessionFactory = applyInterceptors(metadata, allProps).build(); + + for (PersistentClass entityBinding : metadata.getEntityBindings()) { + mappedClasses.add(entityBinding.getMappedClass()); + } + } + + /** + * Set custom Hibernate data types using {@link CustomDataTypesRegistration} and set Hibernate system properties. + */ + protected void setCustomHibernateDataTypesAndProperties() { switch (vendor) { - case ORACLE: - case SQLSERVER: - case MYSQL: - System.setProperty("hibernate.dialect.storage_engine", "innodb"); - case OTHER: - CustomDataTypesRegistration.addTypeOverride(new XMLType()); - break; - case POSTGRES: + case POSTGRES -> { CustomDataTypesRegistration.addTypeOverride(new PostgresMaterializedBlobType()); CustomDataTypesRegistration.addTypeOverride(new PostgresMaterializedClobType()); CustomDataTypesRegistration.addTypeOverride(new PostgresXMLType()); - break; + } + case OTHER -> CustomDataTypesRegistration.addTypeOverride(new XMLType()); + default -> throw new IllegalStateException("Unsupported vendor: " + vendor); } + } + /** + * Build the hibernate metadata from the provided resources and entities. + * + * @param standardRegistry the standard registry of services needed to create metadata sources + * @return the hibernate metadata + */ + private Metadata buildHibernateMetadata(ServiceRegistry standardRegistry) { MetadataSources metadataSources = new MetadataSources(standardRegistry) { @Override @@ -116,31 +138,33 @@ public MetadataBuilder getMetadataBuilder() { for (Class entity : hibernateResourcesConfigurationProvider.getEntities()) { metadataSources.addAnnotatedClass(entity); } + return metadataSources.buildMetadata(); + } - Metadata metadata = metadataSources.buildMetadata(); + /** + * Apply interceptors to a new session factory. + * + * @param metadata the hibernate metadata + * @param allProps the hibernate properties + * @return a new session factory builder + * @throws IllegalStateException if an interceptor class is unknown or cannot be instantiated + */ + protected SessionFactoryBuilder applyInterceptors(Metadata metadata, Properties allProps) + throws IllegalStateException { SessionFactoryBuilder sessionFactoryBuilder = metadata.getSessionFactoryBuilder(); final String className = allProps.getProperty("hibernate.interceptor"); if (className != null && !className.isEmpty()) { try { - final Interceptor interceptor = (Interceptor) Class.forName(className).newInstance(); - sessionFactoryBuilder.applyInterceptor(interceptor); - } catch (final ClassNotFoundException | IllegalAccessException | InstantiationException cnfe) { - throw new IllegalStateException("Unknown interceptor class " + className, cnfe); + sessionFactoryBuilder.applyInterceptor( + (Interceptor) Class.forName(className).getDeclaredConstructor().newInstance()); + } catch (final ReflectiveOperationException e) { + throw new IllegalStateException("Unknown interceptor class " + className, e); } } if (vendor == POSTGRES) { sessionFactoryBuilder.applyInterceptor(new PostgresInterceptor()); } - if (vendor == SQLSERVER) { - sessionFactoryBuilder.applyInterceptor(new SQLServerInterceptor()); - } - if (vendor == ORACLE) { - sessionFactoryBuilder.applyInterceptor(new OracleInterceptor()); - } - this.sessionFactory = sessionFactoryBuilder.build(); - for (PersistentClass entityBinding : metadata.getEntityBindings()) { - mappedClasses.add(entityBinding.getMappedClass()); - } + return sessionFactoryBuilder; } protected void applyCacheMode(MetadataBuilder metadataBuilder) { @@ -150,12 +174,8 @@ protected void applyCacheMode(MetadataBuilder metadataBuilder) { protected Properties gatherAllProperties(Properties extraHibernateProperties, StandardServiceRegistryBuilder standardRegistryBuilder) { Properties allProps = new Properties(); - for (Map.Entry extraProp : properties.entrySet()) { - allProps.put(extraProp.getKey(), extraProp.getValue()); - } - for (Map.Entry extraProp : extraHibernateProperties.entrySet()) { - allProps.put(extraProp.getKey(), extraProp.getValue()); - } + allProps.putAll(properties); + allProps.putAll(extraHibernateProperties); for (Map.Entry prop : allProps.entrySet()) { standardRegistryBuilder.applySetting(prop.getKey().toString(), prop.getValue()); @@ -163,16 +183,4 @@ protected Properties gatherAllProperties(Properties extraHibernateProperties, return allProps; } - public Vendor getVendor() { - return vendor; - } - - public SessionFactory getSessionFactory() { - return sessionFactory; - } - - public List> getMappedClasses() { - return mappedClasses; - } - } diff --git a/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/HibernatePersistenceService.java b/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/HibernatePersistenceService.java index b862634b51e..f1394ef8b85 100644 --- a/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/HibernatePersistenceService.java +++ b/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/HibernatePersistenceService.java @@ -35,7 +35,6 @@ import org.bonitasoft.engine.services.PersistenceService; import org.bonitasoft.engine.services.SPersistenceException; import org.bonitasoft.engine.services.UpdateDescriptor; -import org.bonitasoft.engine.services.Vendor; import org.bonitasoft.engine.sessionaccessor.ReadSessionAccessor; import org.bonitasoft.engine.sessionaccessor.STenantIdNotSetException; import org.hibernate.AssertionFailure; @@ -90,9 +89,6 @@ public HibernatePersistenceService(final ReadSessionAccessor sessionAccessor, sessionFactory = hbmConfigurationProvider.getSessionFactory(); this.queryBuilderFactory = queryBuilderFactory; - if (hbmConfigurationProvider.getVendor() == Vendor.SQLSERVER) { - this.queryBuilderFactory.setOrderByBuilder(new SQLServerOrderByBuilder()); - } statistics = sessionFactory.getStatistics(); classMapping = hbmConfigurationProvider.getMappedClasses(); classAliasMappings = hbmConfigurationProvider.getClassAliasMappings(); diff --git a/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/OracleInterceptor.java b/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/OracleInterceptor.java deleted file mode 100644 index 3157d2fc7ad..00000000000 --- a/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/OracleInterceptor.java +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright (C) 2023 Bonitasoft S.A. - * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble - * This library is free software; you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Foundation - * version 2.1 of the License. - * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * You should have received a copy of the GNU Lesser General Public License along with this - * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth - * Floor, Boston, MA 02110-1301, USA. - **/ -package org.bonitasoft.engine.persistence; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.hibernate.EmptyInterceptor; - -/** - * Make search case insensitive in oracle by using upper() function - */ -public class OracleInterceptor extends EmptyInterceptor { - - /* - * Pattern to find like clauses in sql query : - * (?<= WHERE | OR | AND ) : preceded by WHERE, OR or AND - * (?:[ \(]*) : followed by 0 or more spaces or ( (non-capturing group) - * ((?:(?! WHERE | OR | AND |\\)).)*) : followed by anything except WHERE, OR, AND or ) 0 or more times (capturing - * group) - * (\\)?) : followed by 0 or 1 ) (capturing group) - * ( +LIKE +) : followed by 1 or more spaces, LIKE and 1 or more spaces (capturing group) - * ((?:[^ ]+(?: *\|\| *[^ ]*)*)) : followed by any character except space 1 or more times - * and 0 or more times (space, ||, space and 0 or more times any character except space) (capturing group) - */ - public static final Pattern LIKE_PATTERN = Pattern.compile( - "(?<= WHERE | OR | AND )(?:[ \\(]*)((?:(?! WHERE | OR | AND |\\)).)*)(\\)?)( +LIKE +)((?:[^ ]+(?: *\\|\\| *[^ ]*)*))", - Pattern.CASE_INSENSITIVE); - - @Override - public String onPrepareStatement(final String sql) { - if (sql.contains("like '") || sql.contains("LIKE '") || sql.contains("like ?") || sql.contains("LIKE ?")) { - Matcher matcher = LIKE_PATTERN.matcher(sql); - String newSQL = sql; - while (matcher.find()) { - newSQL = newSQL.replace(matcher.group(1) + matcher.group(2) + matcher.group(3) + matcher.group(4), - "UPPER(" + matcher.group(1) + ")" - + matcher.group(2) + matcher.group(3) - + "UPPER(" + matcher.group(4) + ")"); - } - return newSQL; - } - return sql; - } -} diff --git a/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/SQLServerOrderByBuilder.java b/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/SQLServerOrderByBuilder.java deleted file mode 100644 index 9a5dfe99cff..00000000000 --- a/services/bonita-persistence/src/main/java/org/bonitasoft/engine/persistence/SQLServerOrderByBuilder.java +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (C) 2019 Bonitasoft S.A. - * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble - * This library is free software; you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Foundation - * version 2.1 of the License. - * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * You should have received a copy of the GNU Lesser General Public License along with this - * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth - * Floor, Boston, MA 02110-1301, USA. - **/ -package org.bonitasoft.engine.persistence; - -/** - * @author Baptiste Mesta - */ -public class SQLServerOrderByBuilder implements OrderByBuilder { - - @Override - public void appendOrderBy(StringBuilder builder, String fieldName, OrderByType orderByType) { - switch (orderByType) { - case ASC: - case DESC: - builder.append(fieldName).append(" ").append(orderByType.getSqlKeyword()); - break; - case ASC_NULLS_FIRST: - builder.append("CASE WHEN ").append(fieldName).append(" IS NULL THEN 0 ELSE 1 END ASC, ") - .append(fieldName).append(" ASC"); - break; - case ASC_NULLS_LAST: - builder.append("CASE WHEN ").append(fieldName).append(" IS NULL THEN 0 ELSE 1 END DESC, ") - .append(fieldName).append(" ASC"); - break; - case DESC_NULLS_FIRST: - builder.append("CASE WHEN ").append(fieldName).append(" IS NULL THEN 0 ELSE 1 END ASC, ") - .append(fieldName).append(" DESC"); - break; - case DESC_NULLS_LAST: - builder.append("CASE WHEN ").append(fieldName).append(" IS NULL THEN 0 ELSE 1 END DESC, ") - .append(fieldName).append(" DESC"); - break; - } - } -} diff --git a/services/bonita-persistence/src/test/java/org/bonitasoft/engine/persistence/OracleInterceptorTest.java b/services/bonita-persistence/src/test/java/org/bonitasoft/engine/persistence/OracleInterceptorTest.java deleted file mode 100644 index e5552125919..00000000000 --- a/services/bonita-persistence/src/test/java/org/bonitasoft/engine/persistence/OracleInterceptorTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Copyright (C) 2024 Bonitasoft S.A. - * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble - * This library is free software; you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Foundation - * version 2.1 of the License. - * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * You should have received a copy of the GNU Lesser General Public License along with this - * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth - * Floor, Boston, MA 02110-1301, USA. - **/ -package org.bonitasoft.engine.persistence; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.*; - -import org.junit.Test; - -public class OracleInterceptorTest { - - private String sql = "select * from ( select sgatewayin0_.id as col_0_0_ from flownode_instance sgatewayin0_ " - + "where sgatewayin0_.kind='gate' and sgatewayin0_.stateId<>3 " - + "and (sgatewayin0_.stateId<>61 or sgatewayin0_.hitBys like 'FINISH:%' " - + "or sgatewayin0_.stateCategory='ABORTING' or sgatewayin0_.stateCategory='CANCELLING') " - + "and sgatewayin0_.lastUpdateDate<:1 order by sgatewayin0_.id ) where rownum <= :2"; - - private String preparedStatement = "select * from ( select sgatewayin0_.id as col_0_0_ from flownode_instance sgatewayin0_ " - + "where sgatewayin0_.kind='gate' and sgatewayin0_.stateId<>3 " - + "and (sgatewayin0_.stateId<>61 or sgatewayin0_.hitBys like ? " - + "or sgatewayin0_.stateCategory='ABORTING' or sgatewayin0_.stateCategory='CANCELLING') " - + "and sgatewayin0_.lastUpdateDate<:1 order by sgatewayin0_.id ) where rownum <= ?"; - - private String preparedStatementWithConcat = "select * from ( select distinct sprocessde2_.id as id1_47_, " - + "sprocessde2_.version as version14_47_ from actor sactor0_ cross join actormember sactormemb1_ " - + "cross join process_definition sprocessde2_ where sactor0_.scopeId=sprocessde2_.processId and " - + "sactor0_.id=sactormemb1_.actorId and (sactormemb1_.groupId in (select sgroup3_.id from group_ " - + "sgroup3_ cross join group_ sgroup4_ where ((sgroup3_.parentPath||'/'||sgroup3_.name||'/') " - + "like '/' || sgroup4_.name || '/' || '%' or sgroup3_.id=?) and sgroup4_.id=?)) and " - + "(sactormemb1_.actorId not in (select sactormemb5_.actorId from actormember sactormemb5_ " - + "where sactormemb5_.groupId<>sactormemb1_.groupId and (sactormemb5_.groupId not in " - + "(select sgroup6_.id from group_ sgroup6_ cross join group_ sgroup7_ where " - + "(sgroup6_.parentPath||'/'||sgroup6_.name||'/' like sgroup7_.name||'/'||'%' or sgroup6_.id=?) " - + "and sgroup7_.id=?)))) order by sprocessde2_.name ASC, sprocessde2_.id ASC ) where rownum <= ?"; - private OracleInterceptor oracleInterceptor = new OracleInterceptor(); - - @Test - public void should_uppercase_like_on_sql() { - assertThat(oracleInterceptor.onPrepareStatement(sql)).isEqualTo( - "select * from ( select sgatewayin0_.id as col_0_0_ from flownode_instance sgatewayin0_ " - + "where sgatewayin0_.kind='gate' and sgatewayin0_.stateId<>3 " - + "and (sgatewayin0_.stateId<>61 or UPPER(sgatewayin0_.hitBys) like UPPER('FINISH:%') " - + "or sgatewayin0_.stateCategory='ABORTING' or sgatewayin0_.stateCategory='CANCELLING') " - + "and sgatewayin0_.lastUpdateDate<:1 order by sgatewayin0_.id ) where rownum <= :2"); - } - - @Test - public void should_uppercase_like_on_prepared_statement() { - assertThat(oracleInterceptor.onPrepareStatement(preparedStatement)).isEqualTo( - "select * from ( select sgatewayin0_.id as col_0_0_ from flownode_instance sgatewayin0_ " - + "where sgatewayin0_.kind='gate' and sgatewayin0_.stateId<>3 " - + "and (sgatewayin0_.stateId<>61 or UPPER(sgatewayin0_.hitBys) like UPPER(?) " - + "or sgatewayin0_.stateCategory='ABORTING' or sgatewayin0_.stateCategory='CANCELLING') " - + "and sgatewayin0_.lastUpdateDate<:1 order by sgatewayin0_.id ) where rownum <= ?"); - } - - @Test - public void should_uppercase_like_on_prepared_statement_with_concat() { - assertThat(oracleInterceptor.onPrepareStatement(preparedStatementWithConcat)).isEqualTo( - "select * from ( select distinct sprocessde2_.id as id1_47_, " - + "sprocessde2_.version as version14_47_ from actor sactor0_ cross join actormember sactormemb1_ " - + "cross join process_definition sprocessde2_ where sactor0_.scopeId=sprocessde2_.processId and " - + "sactor0_.id=sactormemb1_.actorId and (sactormemb1_.groupId in (select sgroup3_.id from group_ " - + "sgroup3_ cross join group_ sgroup4_ where ((UPPER(sgroup3_.parentPath||'/'||sgroup3_.name||'/')) " - + "like UPPER('/' || sgroup4_.name || '/' || '%') or sgroup3_.id=?) and sgroup4_.id=?)) and " - + "(sactormemb1_.actorId not in (select sactormemb5_.actorId from actormember sactormemb5_ " - + "where sactormemb5_.groupId<>sactormemb1_.groupId and (sactormemb5_.groupId not in " - + "(select sgroup6_.id from group_ sgroup6_ cross join group_ sgroup7_ where " - + "(UPPER(sgroup6_.parentPath||'/'||sgroup6_.name||'/') like UPPER(sgroup7_.name||'/'||'%') or sgroup6_.id=?) " - + "and sgroup7_.id=?)))) order by sprocessde2_.name ASC, sprocessde2_.id ASC ) where rownum <= ?"); - } -} diff --git a/services/bonita-persistence/src/test/java/org/bonitasoft/engine/persistence/SQLServerOrderByBuilderTest.java b/services/bonita-persistence/src/test/java/org/bonitasoft/engine/persistence/SQLServerOrderByBuilderTest.java deleted file mode 100644 index 58c6b99703f..00000000000 --- a/services/bonita-persistence/src/test/java/org/bonitasoft/engine/persistence/SQLServerOrderByBuilderTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Copyright (C) 2019 Bonitasoft S.A. - * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble - * This library is free software; you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Foundation - * version 2.1 of the License. - * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * You should have received a copy of the GNU Lesser General Public License along with this - * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth - * Floor, Boston, MA 02110-1301, USA. - **/ -package org.bonitasoft.engine.persistence; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.Before; -import org.junit.Test; - -/** - * @author Laurent Leseigneur - */ -public class SQLServerOrderByBuilderTest { - - private StringBuilder builder; - - private SQLServerOrderByBuilder sqlServerInterceptor; - - @Before - public void before() { - builder = new StringBuilder(); - sqlServerInterceptor = new SQLServerOrderByBuilder(); - } - - @Test - public void should_sort_asc() { - //when - sqlServerInterceptor.appendOrderBy(builder, "field", OrderByType.ASC); - - //then - assertThat(builder.toString()).isEqualTo("field ASC"); - } - - @Test - public void should_sort_asc_with_nulls_first() { - //when - sqlServerInterceptor.appendOrderBy(builder, "field", OrderByType.ASC_NULLS_FIRST); - - //then - assertThat(builder.toString()).isEqualTo("CASE WHEN field IS NULL THEN 0 ELSE 1 END ASC, field ASC"); - } - - @Test - public void should_sort_asc_with_nulls_last() { - //when - sqlServerInterceptor.appendOrderBy(builder, "field", OrderByType.ASC_NULLS_LAST); - - //then - assertThat(builder.toString()).isEqualTo("CASE WHEN field IS NULL THEN 0 ELSE 1 END DESC, field ASC"); - } - - @Test - public void should_sort_desc() { - //when - sqlServerInterceptor.appendOrderBy(builder, "field", OrderByType.DESC); - - //then - assertThat(builder.toString()).isEqualTo("field DESC"); - } - - @Test - public void should_sort_desc_with_nulls_first() { - //when - sqlServerInterceptor.appendOrderBy(builder, "field", OrderByType.DESC_NULLS_FIRST); - - //then - assertThat(builder.toString()).isEqualTo("CASE WHEN field IS NULL THEN 0 ELSE 1 END ASC, field DESC"); - } - - @Test - public void should_sort_desc_with_nulls_last() { - //when - sqlServerInterceptor.appendOrderBy(builder, "field", OrderByType.DESC_NULLS_LAST); - - //then - assertThat(builder.toString()).isEqualTo("CASE WHEN field IS NULL THEN 0 ELSE 1 END DESC, field DESC"); - } -} diff --git a/services/bonita-platform-authentication/build.gradle b/services/bonita-platform-authentication/build.gradle index ce90d36d0ab..82f38f0f172 100644 --- a/services/bonita-platform-authentication/build.gradle +++ b/services/bonita-platform-authentication/build.gradle @@ -2,7 +2,6 @@ dependencies { api project(':services:bonita-commons') - testImplementation libs.junit4 testImplementation libs.mockitoCore testImplementation libs.logback } diff --git a/services/bonita-platform-command/build.gradle b/services/bonita-platform-command/build.gradle index e3d86472012..24ea8f13a7e 100644 --- a/services/bonita-platform-command/build.gradle +++ b/services/bonita-platform-command/build.gradle @@ -4,7 +4,6 @@ dependencies { api project(':services:bonita-log') api project(':services:bonita-commons') api project(':services:bonita-persistence') - testImplementation libs.junit4 testImplementation libs.mockitoCore testImplementation libs.logback diff --git a/services/bonita-platform/build.gradle b/services/bonita-platform/build.gradle index cebab73d134..bdd7acbade3 100644 --- a/services/bonita-platform/build.gradle +++ b/services/bonita-platform/build.gradle @@ -6,7 +6,6 @@ dependencies { api project(':services:bonita-persistence') api project(':services:bonita-commons') testImplementation project(':services:bonita-events') - testImplementation libs.junit4 testImplementation libs.mockitoCore testImplementation libs.assertj testImplementation libs.logback diff --git a/services/bonita-platform/src/main/java/org/bonitasoft/engine/platform/impl/PlatformRetrieverImpl.java b/services/bonita-platform/src/main/java/org/bonitasoft/engine/platform/impl/PlatformRetrieverImpl.java index 2c978848a25..832cf617d9c 100644 --- a/services/bonita-platform/src/main/java/org/bonitasoft/engine/platform/impl/PlatformRetrieverImpl.java +++ b/services/bonita-platform/src/main/java/org/bonitasoft/engine/platform/impl/PlatformRetrieverImpl.java @@ -37,7 +37,7 @@ public PlatformRetrieverImpl(final PersistenceService platformPersistenceService public SPlatform getPlatform() throws SPlatformNotFoundException { try { SPlatform platform = platformPersistenceService - .selectOne(new SelectOneDescriptor(QUERY_GET_PLATFORM, null, SPlatform.class)); + .selectOne(new SelectOneDescriptor<>(QUERY_GET_PLATFORM, null, SPlatform.class)); if (platform == null) { throw new SPlatformNotFoundException("No platform found"); } diff --git a/services/bonita-profile/build.gradle b/services/bonita-profile/build.gradle index b98a44a2eab..b6a0cf79b7f 100644 --- a/services/bonita-profile/build.gradle +++ b/services/bonita-profile/build.gradle @@ -8,7 +8,6 @@ dependencies { api project(':services:bonita-events') api project(':services:bonita-builder') api project(':services:bonita-identity') - testImplementation libs.junit4 testImplementation libs.mockitoCore annotationProcessor libs.lombok diff --git a/services/bonita-profile/src/main/java/org/bonitasoft/engine/profile/impl/ProfileServiceImpl.java b/services/bonita-profile/src/main/java/org/bonitasoft/engine/profile/impl/ProfileServiceImpl.java index 54ae134fe49..f8a75be28ed 100644 --- a/services/bonita-profile/src/main/java/org/bonitasoft/engine/profile/impl/ProfileServiceImpl.java +++ b/services/bonita-profile/src/main/java/org/bonitasoft/engine/profile/impl/ProfileServiceImpl.java @@ -13,20 +13,11 @@ **/ package org.bonitasoft.engine.profile.impl; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import org.bonitasoft.engine.commons.NullCheckingUtil; import org.bonitasoft.engine.commons.exceptions.SBonitaException; -import org.bonitasoft.engine.persistence.OrderByType; -import org.bonitasoft.engine.persistence.QueryOptions; -import org.bonitasoft.engine.persistence.SBonitaReadException; -import org.bonitasoft.engine.persistence.SelectByIdDescriptor; -import org.bonitasoft.engine.persistence.SelectListDescriptor; -import org.bonitasoft.engine.persistence.SelectOneDescriptor; +import org.bonitasoft.engine.persistence.*; import org.bonitasoft.engine.profile.ProfileService; import org.bonitasoft.engine.profile.builder.impl.SProfileLogBuilderImpl; import org.bonitasoft.engine.profile.builder.impl.SProfileMemberLogBuilderImpl; @@ -48,11 +39,7 @@ import org.bonitasoft.engine.queriablelogger.model.builder.SPersistenceLogBuilder; import org.bonitasoft.engine.recorder.Recorder; import org.bonitasoft.engine.recorder.SRecorderException; -import org.bonitasoft.engine.recorder.model.DeleteAllRecord; -import org.bonitasoft.engine.recorder.model.DeleteRecord; -import org.bonitasoft.engine.recorder.model.EntityUpdateDescriptor; -import org.bonitasoft.engine.recorder.model.InsertRecord; -import org.bonitasoft.engine.recorder.model.UpdateRecord; +import org.bonitasoft.engine.recorder.model.*; import org.bonitasoft.engine.services.PersistenceService; import org.bonitasoft.engine.services.QueriableLoggerService; import org.bonitasoft.engine.session.SessionService; @@ -359,7 +346,7 @@ public long getNumberOfProfileMembers(final String querySuffix, final QueryOptio @Override public List getProfileMembers(final List profileIds) throws SBonitaReadException { - if (profileIds == null || profileIds.size() == 0) { + if (profileIds == null || profileIds.isEmpty()) { return Collections.emptyList(); } final QueryOptions queryOptions = new QueryOptions(0, QueryOptions.UNLIMITED_NUMBER_OF_RESULTS, diff --git a/services/bonita-resources/build.gradle b/services/bonita-resources/build.gradle index 3a9e2721ab0..098f52c7b0c 100644 --- a/services/bonita-resources/build.gradle +++ b/services/bonita-resources/build.gradle @@ -3,7 +3,6 @@ dependencies { api project(':services:bonita-persistence') api project(':services:bonita-commons') - testImplementation libs.junit4 testImplementation libs.mockitoCore testImplementation libs.systemRules testImplementation libs.assertj diff --git a/services/bonita-scheduler/build.gradle b/services/bonita-scheduler/build.gradle index 7e0871c8110..7dd25e0d864 100644 --- a/services/bonita-scheduler/build.gradle +++ b/services/bonita-scheduler/build.gradle @@ -13,7 +13,6 @@ dependencies { exclude(module: "HikariCP-java7") // Same reason } api libs.micrometerCore - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.mockitoCore testImplementation libs.logback diff --git a/services/bonita-scheduler/src/test/java/org/bonitasoft/engine/scheduler/impl/AbstractQuartzJobTest.java b/services/bonita-scheduler/src/test/java/org/bonitasoft/engine/scheduler/impl/AbstractQuartzJobTest.java index 2362aa51ca8..ce6c591b947 100644 --- a/services/bonita-scheduler/src/test/java/org/bonitasoft/engine/scheduler/impl/AbstractQuartzJobTest.java +++ b/services/bonita-scheduler/src/test/java/org/bonitasoft/engine/scheduler/impl/AbstractQuartzJobTest.java @@ -52,7 +52,7 @@ public void before() { @Test public void should_not_unschedule_job_on_exception() throws Exception { // job should never throw an exception and be handled by the JobWrapper - // we do not unschedule the job in that case. we don't want to loose the job + // we do not unschedule the job in that case. we don't want to lose the job doReturn(jobThatFails()).when(schedulerService).getPersistedJob(any()); try { diff --git a/services/bonita-session/build.gradle b/services/bonita-session/build.gradle index 2d8203bf4b9..fc1f790ef77 100644 --- a/services/bonita-session/build.gradle +++ b/services/bonita-session/build.gradle @@ -3,7 +3,6 @@ dependencies { api project(':services:bonita-commons') api project(':services:bonita-builder') - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.mockitoCore testImplementation libs.logback diff --git a/services/bonita-temporary-content/build.gradle b/services/bonita-temporary-content/build.gradle index 3a9e2721ab0..098f52c7b0c 100644 --- a/services/bonita-temporary-content/build.gradle +++ b/services/bonita-temporary-content/build.gradle @@ -3,7 +3,6 @@ dependencies { api project(':services:bonita-persistence') api project(':services:bonita-commons') - testImplementation libs.junit4 testImplementation libs.mockitoCore testImplementation libs.systemRules testImplementation libs.assertj diff --git a/services/bonita-time-tracker/build.gradle b/services/bonita-time-tracker/build.gradle index 91c56f33d2d..01a1c00acf6 100644 --- a/services/bonita-time-tracker/build.gradle +++ b/services/bonita-time-tracker/build.gradle @@ -3,7 +3,6 @@ dependencies { api project(':services:bonita-commons') api libs.commonsCollections - testImplementation libs.junit4 testImplementation libs.mockitoCore testImplementation libs.assertj testImplementation libs.logback diff --git a/services/bonita-transaction/build.gradle b/services/bonita-transaction/build.gradle index 29b82b85eef..ebd860c0353 100644 --- a/services/bonita-transaction/build.gradle +++ b/services/bonita-transaction/build.gradle @@ -6,7 +6,6 @@ dependencies { compileOnly libs.lombok testImplementation libs.mockitoCore - testImplementation libs.junit4 testImplementation libs.assertj testImplementation libs.narayanaJta testImplementation libs.jbossLogging diff --git a/services/bonita-work/build.gradle b/services/bonita-work/build.gradle index a1e4536403d..d47127c4558 100644 --- a/services/bonita-work/build.gradle +++ b/services/bonita-work/build.gradle @@ -7,7 +7,6 @@ dependencies { api project(':services:bonita-transaction') api libs.springJdbc api libs.springContext - testImplementation libs.junit4 testImplementation libs.awaitility testImplementation libs.assertj testImplementation libs.mockitoCore diff --git a/services/bonita-work/src/main/java/org/bonitasoft/engine/work/BonitaExecutorService.java b/services/bonita-work/src/main/java/org/bonitasoft/engine/work/BonitaExecutorService.java index bf11bef2552..e8799ead9fe 100644 --- a/services/bonita-work/src/main/java/org/bonitasoft/engine/work/BonitaExecutorService.java +++ b/services/bonita-work/src/main/java/org/bonitasoft/engine/work/BonitaExecutorService.java @@ -13,6 +13,8 @@ **/ package org.bonitasoft.engine.work; +import java.util.concurrent.Future; +import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** @@ -38,8 +40,10 @@ public interface BonitaExecutorService { * * @param work */ - void submit(WorkDescriptor work); + Future submit(WorkDescriptor work); boolean awaitTermination(long workTerminationTimeout, TimeUnit seconds) throws InterruptedException; + ThreadPoolExecutor getExecutor(); + } diff --git a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/dbconfig/OracleDataSourceConfig.java b/services/bonita-work/src/main/java/org/bonitasoft/engine/work/BonitaWorkExecutorFactory.java similarity index 59% rename from platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/dbconfig/OracleDataSourceConfig.java rename to services/bonita-work/src/main/java/org/bonitasoft/engine/work/BonitaWorkExecutorFactory.java index 5ae5b2ceb16..6b3f4148d60 100644 --- a/platform/platform-setup/src/main/java/org/bonitasoft/platform/setup/dbconfig/OracleDataSourceConfig.java +++ b/services/bonita-work/src/main/java/org/bonitasoft/engine/work/BonitaWorkExecutorFactory.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2019 Bonitasoft S.A. + * Copyright (C) 2024 Bonitasoft S.A. * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble * This library is free software; you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Foundation @@ -11,20 +11,12 @@ * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301, USA. **/ -package org.bonitasoft.platform.setup.dbconfig; +package org.bonitasoft.engine.work; -import org.springframework.context.annotation.Profile; -import org.springframework.context.annotation.PropertySource; -import org.springframework.stereotype.Component; +import java.util.concurrent.ThreadPoolExecutor; -/** - * This is enough to get a Datasource that spring creates using parameters provided in properties. - * - * @author Emmanuel Duchastenier - */ -@Component -@PropertySource("classpath:/oracle.properties") -@Profile("oracle") -public class OracleDataSourceConfig { +public interface BonitaWorkExecutorFactory { + + ThreadPoolExecutor create(); } diff --git a/services/bonita-work/src/main/java/org/bonitasoft/engine/work/BonitaThreadPoolExecutor.java b/services/bonita-work/src/main/java/org/bonitasoft/engine/work/DefaultBonitaExecutorService.java similarity index 68% rename from services/bonita-work/src/main/java/org/bonitasoft/engine/work/BonitaThreadPoolExecutor.java rename to services/bonita-work/src/main/java/org/bonitasoft/engine/work/DefaultBonitaExecutorService.java index b2d724b4eb3..7d95c6f791c 100644 --- a/services/bonita-work/src/main/java/org/bonitasoft/engine/work/BonitaThreadPoolExecutor.java +++ b/services/bonita-work/src/main/java/org/bonitasoft/engine/work/DefaultBonitaExecutorService.java @@ -15,14 +15,7 @@ import java.util.Collection; import java.util.HashMap; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; -import java.util.concurrent.Future; -import java.util.concurrent.RejectedExecutionHandler; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicLong; import io.micrometer.core.instrument.Counter; @@ -34,41 +27,34 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** - * @author Julien Reboul - * @author Baptiste Mesta - */ - -public class BonitaThreadPoolExecutor extends ThreadPoolExecutor implements BonitaExecutorService { +public class DefaultBonitaExecutorService implements BonitaExecutorService { - private Logger log = LoggerFactory.getLogger(BonitaThreadPoolExecutor.class); + private static final Logger log = LoggerFactory.getLogger(DefaultBonitaExecutorService.class); public static final String NUMBER_OF_WORKS_PENDING = "bonita.bpmengine.work.pending"; public static final String NUMBER_OF_WORKS_RUNNING = "bonita.bpmengine.work.running"; public static final String NUMBER_OF_WORKS_EXECUTED = "bonita.bpmengine.work.executed"; + public static final String WORKS_UNIT = "works"; - private final BlockingQueue workQueue; private final WorkFactory workFactory; private final EngineClock engineClock; private final WorkExecutionCallback workExecutionCallback; - private WorkExecutionAuditor workExecutionAuditor; - private MeterRegistry meterRegistry; + private final WorkExecutionAuditor workExecutionAuditor; + private final MeterRegistry meterRegistry; private final AtomicLong runningWorks = new AtomicLong(); private final Counter executedWorkCounter; private final Gauge numberOfWorksPending; private final Gauge numberOfWorksRunning; - - public BonitaThreadPoolExecutor(final int corePoolSize, - final int maximumPoolSize, - final long keepAliveTime, - final TimeUnit unit, - final BlockingQueue workQueue, - final ThreadFactory threadFactory, - final RejectedExecutionHandler handler, WorkFactory workFactory, EngineClock engineClock, - WorkExecutionCallback workExecutionCallback, - WorkExecutionAuditor workExecutionAuditor, MeterRegistry meterRegistry, long tenantId) { - super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); - this.workQueue = workQueue; + private final ThreadPoolExecutor executor; + + public DefaultBonitaExecutorService(final ThreadPoolExecutor executor, + final WorkFactory workFactory, + final EngineClock engineClock, + final WorkExecutionCallback workExecutionCallback, + final WorkExecutionAuditor workExecutionAuditor, + final MeterRegistry meterRegistry, + final long tenantId) { + this.executor = executor; this.workFactory = workFactory; this.engineClock = engineClock; this.workExecutionCallback = workExecutionCallback; @@ -76,44 +62,39 @@ public BonitaThreadPoolExecutor(final int corePoolSize, this.meterRegistry = meterRegistry; Tags tags = Tags.of("tenant", String.valueOf(tenantId)); - numberOfWorksPending = Gauge.builder(NUMBER_OF_WORKS_PENDING, workQueue, Collection::size) - .tags(tags).baseUnit("works").description("Works pending in the execution queue") + numberOfWorksPending = Gauge.builder(NUMBER_OF_WORKS_PENDING, executor.getQueue(), Collection::size) + .tags(tags).baseUnit(WORKS_UNIT).description("Works pending in the execution queue") .register(meterRegistry); numberOfWorksRunning = Gauge.builder(NUMBER_OF_WORKS_RUNNING, runningWorks, AtomicLong::get) - .tags(tags).baseUnit("works").description("Works currently executing") + .tags(tags).baseUnit(WORKS_UNIT).description("Works currently executing") .register(meterRegistry); executedWorkCounter = Counter.builder(NUMBER_OF_WORKS_EXECUTED) - .tags(tags).baseUnit("works").description("total works executed since last server start") + .tags(tags).baseUnit(WORKS_UNIT).description("total works executed since last server start") .register(meterRegistry); } - @Override - public void clearAllQueues() { - workQueue.clear(); + public ThreadPoolExecutor getExecutor() { + return executor; } @Override - public Future submit(final Runnable task) { - // only submit if not shutdown - if (!isShutdown()) { - execute(task); - } - return null; + public void clearAllQueues() { + executor.getQueue().clear(); } @Override public void shutdownAndEmptyQueue() { - super.shutdown(); - log.info("Clearing queue of work, had {} elements", workQueue.size()); - workQueue.clear(); + executor.shutdown(); + log.info("Clearing queue of work, had {} elements", executor.getQueue().size()); + executor.getQueue().clear(); meterRegistry.remove(numberOfWorksPending); meterRegistry.remove(numberOfWorksRunning); meterRegistry.remove(executedWorkCounter); } @Override - public void submit(WorkDescriptor work) { - submit(() -> { + public Future submit(WorkDescriptor work) { + return executor.submit(() -> { if (isRequiringDelayedExecution(work)) { // Future implementation should use a real delay e.g. using a ScheduledThreadPoolExecutor // Will be executed later @@ -152,6 +133,11 @@ public void submit(WorkDescriptor work) { }); } + @Override + public boolean awaitTermination(long workTerminationTimeout, TimeUnit seconds) throws InterruptedException { + return executor.awaitTermination(workTerminationTimeout, seconds); + } + private boolean isRequiringDelayedExecution(WorkDescriptor work) { return work.getExecutionThreshold() != null && work.getExecutionThreshold().isAfter(engineClock.now()); } diff --git a/services/bonita-work/src/main/java/org/bonitasoft/engine/work/DefaultBonitaExecutorServiceFactory.java b/services/bonita-work/src/main/java/org/bonitasoft/engine/work/DefaultBonitaExecutorServiceFactory.java index 6b6f0fa693f..7be3bea0385 100644 --- a/services/bonita-work/src/main/java/org/bonitasoft/engine/work/DefaultBonitaExecutorServiceFactory.java +++ b/services/bonita-work/src/main/java/org/bonitasoft/engine/work/DefaultBonitaExecutorServiceFactory.java @@ -13,12 +13,7 @@ **/ package org.bonitasoft.engine.work; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; import io.micrometer.core.instrument.MeterRegistry; import org.bonitasoft.engine.commons.time.EngineClock; @@ -45,83 +40,55 @@ @Component("bonitaExecutorServiceFactory") public class DefaultBonitaExecutorServiceFactory implements BonitaExecutorServiceFactory { - private Logger logger = LoggerFactory.getLogger(DefaultBonitaExecutorServiceFactory.class); - private final int corePoolSize; - private final int queueCapacity; - private final int maximumPoolSize; - private final long keepAliveTimeSeconds; - private final EngineClock engineClock; - private final WorkFactory workFactory; + private static final String BONITA_WORK_EXECUTOR = "bonita-work-executor"; + private final Logger logger = LoggerFactory.getLogger(DefaultBonitaExecutorServiceFactory.class); + private final long tenantId; - private final WorkExecutionAuditor workExecutionAuditor; private final MeterRegistry meterRegistry; private final ExecutorServiceMetricsProvider executorServiceMetricsProvider; + private final BonitaWorkExecutorFactory bonitaWorkExecutorFactory; + private final EngineClock engineClock; + private final WorkFactory workFactory; + private final WorkExecutionAuditor workExecutionAuditor; - public DefaultBonitaExecutorServiceFactory( - WorkFactory workFactory, - @Value("${tenantId}") long tenantId, - @Value("${bonita.tenant.work.corePoolSize}") int corePoolSize, - @Value("${bonita.tenant.work.queueCapacity}") int queueCapacity, - @Value("${bonita.tenant.work.maximumPoolSize}") int maximumPoolSize, - @Value("${bonita.tenant.work.keepAliveTimeSeconds}") long keepAliveTimeSeconds, + public DefaultBonitaExecutorServiceFactory(@Value("${tenantId}") long tenantId, + MeterRegistry meterRegistry, EngineClock engineClock, + WorkFactory workFactory, WorkExecutionAuditor workExecutionAuditor, - MeterRegistry meterRegistry, - ExecutorServiceMetricsProvider executorServiceMetricsProvider) { - this.workFactory = workFactory; + ExecutorServiceMetricsProvider executorServiceMetricsProvider, + BonitaWorkExecutorFactory bonitaWorkExecutorFactory) { this.tenantId = tenantId; - this.corePoolSize = corePoolSize; - this.queueCapacity = queueCapacity; - this.maximumPoolSize = maximumPoolSize; - this.keepAliveTimeSeconds = keepAliveTimeSeconds; - this.engineClock = engineClock; - this.workExecutionAuditor = workExecutionAuditor; this.meterRegistry = meterRegistry; + this.workFactory = workFactory; + this.workExecutionAuditor = workExecutionAuditor; + this.engineClock = engineClock; this.executorServiceMetricsProvider = executorServiceMetricsProvider; + this.bonitaWorkExecutorFactory = bonitaWorkExecutorFactory; } @Override public BonitaExecutorService createExecutorService(WorkExecutionCallback workExecutionCallback) { - final BlockingQueue workQueue = new ArrayBlockingQueue<>(queueCapacity); - final RejectedExecutionHandler handler = new QueueRejectedExecutionHandler(); - final WorkerThreadFactory threadFactory = new WorkerThreadFactory("Bonita-Worker", tenantId, maximumPoolSize); - - final BonitaThreadPoolExecutor bonitaThreadPoolExecutor = new BonitaThreadPoolExecutor(corePoolSize, - maximumPoolSize, keepAliveTimeSeconds, TimeUnit.SECONDS, - workQueue, threadFactory, handler, workFactory, engineClock, workExecutionCallback, - workExecutionAuditor, meterRegistry, tenantId); + final ThreadPoolExecutor bonitaThreadPoolExecutor = bonitaWorkExecutorFactory.create(); + final BonitaExecutorService bonitaExecutorService = new DefaultBonitaExecutorService(bonitaThreadPoolExecutor, + workFactory, + engineClock, + workExecutionCallback, + workExecutionAuditor, + meterRegistry, + tenantId); logger.info( - "Creating a new Thread pool to handle works: " + bonitaThreadPoolExecutor); + "Creating a new Thread pool to handle works: {}", bonitaThreadPoolExecutor); //TODO this returns the timed executor service, this should be used instead of the BonitaExecutorService but we should change it everywhere executorServiceMetricsProvider - .bindMetricsOnly(meterRegistry, bonitaThreadPoolExecutor, "bonita-work-executor", tenantId); - return bonitaThreadPoolExecutor; + .bindMetricsOnly(meterRegistry, bonitaThreadPoolExecutor, BONITA_WORK_EXECUTOR, tenantId); + return bonitaExecutorService; } @Override public void unbind() { - executorServiceMetricsProvider.unbind(meterRegistry, "bonita-work-executor", tenantId); - } - - private final class QueueRejectedExecutionHandler implements RejectedExecutionHandler { - - public QueueRejectedExecutionHandler() { - } - - @Override - public void rejectedExecution(final Runnable task, final ThreadPoolExecutor executor) { - if (executor.isShutdown()) { - logger.info("Tried to run work " + task - + " but the work service is shutdown. work will be restarted with the node"); - } else { - throw new RejectedExecutionException( - "Unable to run the task " - + task - + "\n your work queue is full you might consider changing your configuration to scale more. See parameter 'queueCapacity' in bonita.home configuration files."); - } - } - + executorServiceMetricsProvider.unbind(meterRegistry, BONITA_WORK_EXECUTOR, tenantId); } } diff --git a/services/bonita-work/src/main/java/org/bonitasoft/engine/work/WorkDescriptor.java b/services/bonita-work/src/main/java/org/bonitasoft/engine/work/WorkDescriptor.java index bc82988ceed..9f1a9dd41d8 100644 --- a/services/bonita-work/src/main/java/org/bonitasoft/engine/work/WorkDescriptor.java +++ b/services/bonita-work/src/main/java/org/bonitasoft/engine/work/WorkDescriptor.java @@ -30,10 +30,10 @@ */ public class WorkDescriptor implements Serializable { - private String uuid = UUID.randomUUID().toString(); - private String type; + private final String uuid = UUID.randomUUID().toString(); + private final String type; private Long tenantId; - private Map parameters; + private final Map parameters; private int retryCount = 0; private Instant executionThreshold; private int executionCount = 0; diff --git a/services/bonita-work/src/main/java/org/bonitasoft/engine/work/WorkSingleThreadPoolExecutorFactory.java b/services/bonita-work/src/main/java/org/bonitasoft/engine/work/WorkSingleThreadPoolExecutorFactory.java new file mode 100644 index 00000000000..49028ef142b --- /dev/null +++ b/services/bonita-work/src/main/java/org/bonitasoft/engine/work/WorkSingleThreadPoolExecutorFactory.java @@ -0,0 +1,81 @@ +/** + * Copyright (C) 2024 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.engine.work; + +import java.util.concurrent.*; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; +import org.springframework.stereotype.Component; + +@Component +@ConditionalOnSingleCandidate(BonitaWorkExecutorFactory.class) +public class WorkSingleThreadPoolExecutorFactory implements BonitaWorkExecutorFactory { + + private final int queueCapacity; + private final long tenantId; + + public WorkSingleThreadPoolExecutorFactory(@Value("${tenantId}") long tenantId, + @Value("${bonita.tenant.work.queueCapacity}") int queueCapacity) { + this.queueCapacity = queueCapacity; + this.tenantId = tenantId; + } + + @Override + public ThreadPoolExecutor create() { + return new SingleThreadPoolExecutor(new ArrayBlockingQueue<>(queueCapacity), + new WorkerThreadFactory("Bonita-Worker", tenantId)); + } + + public static class SingleThreadPoolExecutor extends ThreadPoolExecutor { + + public SingleThreadPoolExecutor(final BlockingQueue workQueue, + final ThreadFactory threadFactory) { + super(1, 1, 0, TimeUnit.MILLISECONDS, workQueue, threadFactory, new QueueRejectedExecutionHandler()); + } + + @Override + public Future submit(final Runnable task) { + // only submit if not shutdown + if (!isShutdown()) { + return super.submit(task); + + } + return null; + } + + } + + public static class QueueRejectedExecutionHandler implements RejectedExecutionHandler { + + private static final Logger logger = LoggerFactory.getLogger(QueueRejectedExecutionHandler.class); + + @Override + public void rejectedExecution(final Runnable task, final ThreadPoolExecutor executor) { + if (executor.isShutdown()) { + logger.info( + "Tried to run work {} but the work service is shutdown. work will be restarted with the node", + task); + } else { + throw new RejectedExecutionException( + "Unable to run the task " + + task + + "\n your work queue is full you might consider changing your configuration to scale more. See parameter 'bonita.tenant.work.queueCapacity' in bonita-tenant-community.properties configuration files."); + } + } + + } +} diff --git a/services/bonita-work/src/main/java/org/bonitasoft/engine/work/WorkerThreadFactory.java b/services/bonita-work/src/main/java/org/bonitasoft/engine/work/WorkerThreadFactory.java index 67728569061..ddd514ba3cb 100644 --- a/services/bonita-work/src/main/java/org/bonitasoft/engine/work/WorkerThreadFactory.java +++ b/services/bonita-work/src/main/java/org/bonitasoft/engine/work/WorkerThreadFactory.java @@ -36,6 +36,10 @@ public WorkerThreadFactory(final String name, final long tenantId, final int max this.padding = guessPadding(maximumPoolSize); } + public WorkerThreadFactory(final String name, final long tenantId) { + this(name, tenantId, 1); + } + /** * @param maximumPoolSize */ diff --git a/services/bonita-work/src/test/java/org/bonitasoft/engine/work/BonitaThreadPoolExecutorTest.java b/services/bonita-work/src/test/java/org/bonitasoft/engine/work/BonitaThreadPoolExecutorTest.java deleted file mode 100644 index 3eef82f0dec..00000000000 --- a/services/bonita-work/src/test/java/org/bonitasoft/engine/work/BonitaThreadPoolExecutorTest.java +++ /dev/null @@ -1,286 +0,0 @@ -/** - * Copyright (C) 2017-2019 Bonitasoft S.A. - * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble - * This library is free software; you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Foundation - * version 2.1 of the License. - * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * You should have received a copy of the GNU Lesser General Public License along with this - * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth - * Floor, Boston, MA 02110-1301, USA. - **/ -package org.bonitasoft.engine.work; - -import static java.time.temporal.ChronoUnit.SECONDS; -import static org.assertj.core.api.Assertions.assertThat; -import static org.awaitility.Awaitility.await; - -import java.time.Duration; -import java.time.Instant; -import java.util.Map; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -import io.micrometer.core.instrument.Clock; -import io.micrometer.core.instrument.Gauge; -import io.micrometer.core.instrument.simple.SimpleMeterRegistry; -import org.bonitasoft.engine.commons.time.FixedEngineClock; -import org.bonitasoft.engine.work.audit.WorkExecutionAuditor; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; - -/** - * @author Baptiste Mesta. - */ -public class BonitaThreadPoolExecutorTest { - - public static final long TENANT_ID = 13L; - @Rule - public MockitoRule mockitoRule = MockitoJUnit.rule(); - @Mock - private WorkExecutionAuditor workExecutionAuditor; - private MyWorkExecutionCallback workExecutionCallback = new MyWorkExecutionCallback(); - private BonitaThreadPoolExecutor bonitaThreadPoolExecutor; - private static int threadNumber = 3; - private FixedEngineClock engineClock = new FixedEngineClock(Instant.now()); - private WorkFactory workFactory = new LocalWorkFactory(2); - private SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry( - // So that micrometer updates its counters every 1 ms: - k -> k.equals("simple.step") ? Duration.ofMillis(1).toString() : null, - Clock.SYSTEM); - - @Before - public void before() throws Exception { - bonitaThreadPoolExecutor = new BonitaThreadPoolExecutor(threadNumber, threadNumber // - , 1_000, TimeUnit.SECONDS // - , new ArrayBlockingQueue<>(1_000) // - , new WorkerThreadFactory("test-worker", 1, threadNumber) // - , (r, executor) -> { - } // - , workFactory, engineClock, workExecutionCallback, workExecutionAuditor, - meterRegistry, TENANT_ID); - } - - @Test - public void should_call_on_success_callback_when_work_executed_properly() { - WorkDescriptor workDescriptor = WorkDescriptor.create("NORMAL"); - - bonitaThreadPoolExecutor.submit(workDescriptor); - - await().until(() -> workExecutionCallback.isOnSuccessCalled()); - assertThat(workExecutionCallback.isOnFailureCalled()).isFalse(); - } - - @Test - public void should_call_on_failure_callback_when_work_executed_properly() { - WorkDescriptor workDescriptor = WorkDescriptor.create("EXCEPTION"); - - bonitaThreadPoolExecutor.submit(workDescriptor); - - await().until(() -> workExecutionCallback.isOnFailureCalled()); - assertThat(workExecutionCallback.isOnSuccessCalled()).isFalse(); - } - - @Test - public void should_execute_work_after_specified_date() throws Exception { - WorkDescriptor workDescriptor = WorkDescriptor.create("NORMAL"); - workDescriptor.mustBeExecutedAfter(Instant.now().plus(5, SECONDS)); - - bonitaThreadPoolExecutor.submit(workDescriptor); - - //should still not be executed - engineClock.addTime(1, SECONDS); - Thread.sleep(50); - assertThat(workExecutionCallback.isOnSuccessCalled()).isFalse(); - - //add time, work should be executed - engineClock.addTime(5, SECONDS); - await().until(() -> workExecutionCallback.isOnSuccessCalled()); - } - - @Test - public void should_update_meter_when_work_executes() { - Gauge currentWorkQueue = meterRegistry.find(BonitaThreadPoolExecutor.NUMBER_OF_WORKS_PENDING).gauge(); - for (int i = 0; i <= threadNumber + 3; i++) { - WorkDescriptor workDescriptor = WorkDescriptor.create("SLEEP"); - bonitaThreadPoolExecutor.submit(workDescriptor); - } - await().until(() -> currentWorkQueue.value() > 0); - } - - @Test - public void should_update_works_counters_when_enqueuing_workDescriptor_with_long_processing_time() - throws Exception { - - //when: - bonitaThreadPoolExecutor.submit(WorkDescriptor.create("NORMAL")); - bonitaThreadPoolExecutor.submit(WorkDescriptor.create("SLEEP")); - bonitaThreadPoolExecutor.submit(WorkDescriptor.create("SLEEP")); - bonitaThreadPoolExecutor.submit(WorkDescriptor.create("SLEEP")); - bonitaThreadPoolExecutor.submit(WorkDescriptor.create("SLEEP")); - bonitaThreadPoolExecutor.submit(WorkDescriptor.create("NORMAL")); - TimeUnit.MILLISECONDS.sleep(50); // give some time to the executor to process the work - - //then: - // 1 executed because normal work is submitted first. - assertThat(meterRegistry.find(BonitaThreadPoolExecutor.NUMBER_OF_WORKS_EXECUTED).counter().count()) - .as("Executed works number").isEqualTo(1); - // 3 running works because we have 3 threads in the pool and sleeping works wait for 2s to execute: - assertThat(meterRegistry.find(BonitaThreadPoolExecutor.NUMBER_OF_WORKS_RUNNING).gauge().value()) - .as("Running works number").isEqualTo(3); - // 2 pending works because all 3 threads are busy, so the last 2 works are in the queue: - assertThat(meterRegistry.find(BonitaThreadPoolExecutor.NUMBER_OF_WORKS_PENDING).gauge().value()) - .as("Pending works number").isEqualTo(2); - } - - @Test - public void should_have_no_meters_after_shutdown() throws Exception { - bonitaThreadPoolExecutor.submit(WorkDescriptor.create("NORMAL")); - TimeUnit.MILLISECONDS.sleep(50); // give some time to the executor to process the work - - bonitaThreadPoolExecutor.shutdownAndEmptyQueue(); - - assertThat(meterRegistry.getMeters()).hasSize(0); - } - - @Test - public void should_have_tenant_id_in_all_meters() { - assertThat(meterRegistry.find(BonitaThreadPoolExecutor.NUMBER_OF_WORKS_EXECUTED) - .tag("tenant", String.valueOf(TENANT_ID)).counter()).isNotNull(); - assertThat(meterRegistry.find(BonitaThreadPoolExecutor.NUMBER_OF_WORKS_RUNNING) - .tag("tenant", String.valueOf(TENANT_ID)).gauge()).isNotNull(); - assertThat(meterRegistry.find(BonitaThreadPoolExecutor.NUMBER_OF_WORKS_PENDING) - .tag("tenant", String.valueOf(TENANT_ID)).gauge()).isNotNull(); - } - - @Test - public void should_call_on_success_callback_only_when_async_work_executed_properly() throws InterruptedException { - WorkDescriptor workDescriptor = WorkDescriptor.create("ASYNC"); - - bonitaThreadPoolExecutor.submit(workDescriptor); - - TimeUnit.MILLISECONDS.sleep(50); // give some time to the executor to process the work - assertThat(workExecutionCallback.isOnSuccessCalled()).isFalse(); - assertThat(workExecutionCallback.isOnFailureCalled()).isFalse(); - - await().until(() -> workExecutionCallback.isOnSuccessCalled()); - assertThat(workExecutionCallback.isOnFailureCalled()).isFalse(); - } - - @Test - public void should_call_on_failure_callback_ony_when_async_work_executed_properly() throws InterruptedException { - WorkDescriptor workDescriptor = WorkDescriptor.create("ASYNC_EXCEPTION"); - - bonitaThreadPoolExecutor.submit(workDescriptor); - - TimeUnit.MILLISECONDS.sleep(50); // give some time to the executor to process the work - assertThat(workExecutionCallback.isOnSuccessCalled()).isFalse(); - assertThat(workExecutionCallback.isOnFailureCalled()).isFalse(); - - await().until(() -> workExecutionCallback.isOnFailureCalled()); - assertThat(workExecutionCallback.isOnSuccessCalled()).isFalse(); - assertThat(workExecutionCallback.getThrown()).hasMessage("my exception").isInstanceOf(SWorkException.class); - } - - // ================================================================================================================= - // UTILS - // ================================================================================================================= - - private static class MyWorkExecutionCallback implements WorkExecutionCallback { - - private final AtomicBoolean onSuccessCalled = new AtomicBoolean(false); - private final AtomicBoolean onFailureCalled = new AtomicBoolean(false); - private Throwable thrown; - - @Override - public void onSuccess(WorkDescriptor workDescriptor) { - onSuccessCalled.set(true); - } - - @Override - public void onFailure(WorkDescriptor work, BonitaWork bonitaWork, Map context, - Throwable thrown) { - this.thrown = thrown; - onFailureCalled.set(true); - } - - public boolean isOnSuccessCalled() { - return onSuccessCalled.get(); - } - - public boolean isOnFailureCalled() { - return onFailureCalled.get(); - } - - public Throwable getThrown() { - return thrown; - } - } - - private static class LocalWorkFactory implements WorkFactory { - - private final long workSleepPeriodInSeconds; - - private LocalWorkFactory(long workSleepPeriodInSeconds) { - this.workSleepPeriodInSeconds = workSleepPeriodInSeconds; - } - - @Override - public BonitaWork create(WorkDescriptor workDescriptor) { - return new BonitaWork() { - - @Override - public String getDescription() { - return workDescriptor.toString(); - } - - @Override - public CompletableFuture work(Map context) throws Exception { - switch (workDescriptor.getType()) { - case "EXCEPTION": - throw new Exception("classic exception"); - case "SLEEP": - TimeUnit.SECONDS.sleep(workSleepPeriodInSeconds); - break; - case "ASYNC": - return CompletableFuture.supplyAsync(() -> { - try { - TimeUnit.MILLISECONDS.sleep(200); - } catch (InterruptedException ignored) { - } - return null; - }, Executors.newSingleThreadExecutor()); - case "ASYNC_EXCEPTION": - return CompletableFuture.supplyAsync(() -> { - try { - TimeUnit.MILLISECONDS.sleep(200); - } catch (InterruptedException ignored) { - } - throw new CompletionException(new SWorkException("my exception")); - }, Executors.newSingleThreadExecutor()); - case "NORMAL": - default: - } - return CompletableFuture.completedFuture(null); - } - - @Override - public void handleFailure(Throwable e, Map context) { - // do nothing - } - }; - } - - } - -} diff --git a/services/bonita-work/src/test/java/org/bonitasoft/engine/work/DefaultBonitaExecutorServiceFactoryTest.java b/services/bonita-work/src/test/java/org/bonitasoft/engine/work/DefaultBonitaExecutorServiceFactoryTest.java index 2bf13421b27..4239d442b80 100644 --- a/services/bonita-work/src/test/java/org/bonitasoft/engine/work/DefaultBonitaExecutorServiceFactoryTest.java +++ b/services/bonita-work/src/test/java/org/bonitasoft/engine/work/DefaultBonitaExecutorServiceFactoryTest.java @@ -16,8 +16,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; -import java.util.concurrent.ThreadPoolExecutor; - import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.bonitasoft.engine.commons.time.DefaultEngineClock; import org.bonitasoft.engine.monitoring.DefaultExecutorServiceMetricsProvider; @@ -39,16 +37,20 @@ public class DefaultBonitaExecutorServiceFactoryTest { public void threadNameInExecutorService_should_contain_tenantId() { long tenantId = 999; DefaultBonitaExecutorServiceFactory defaultBonitaExecutorServiceFactory = new DefaultBonitaExecutorServiceFactory( - workFactory, tenantId, 1, - 20, 15, 10, new DefaultEngineClock(), mock(WorkExecutionAuditor.class), new SimpleMeterRegistry(), - new DefaultExecutorServiceMetricsProvider()); + tenantId, + new SimpleMeterRegistry(), + new DefaultEngineClock(), + workFactory, + mock(WorkExecutionAuditor.class), + new DefaultExecutorServiceMetricsProvider(), + new WorkSingleThreadPoolExecutorFactory(tenantId, 10)); BonitaExecutorService createExecutorService = defaultBonitaExecutorServiceFactory .createExecutorService(workExecutionCallback); Runnable r = () -> { }; - String name = ((ThreadPoolExecutor) createExecutorService).getThreadFactory().newThread(r).getName(); + String name = createExecutorService.getExecutor().getThreadFactory().newThread(r).getName(); assertThat(name).as("thread name should contains the tenantId").contains(Long.toString(tenantId)); } @@ -58,9 +60,13 @@ public void createExecutorService_should_register_ExecutorServiceMetrics() { long tenantId = 97L; final SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); DefaultBonitaExecutorServiceFactory defaultBonitaExecutorServiceFactory = new DefaultBonitaExecutorServiceFactory( - workFactory, tenantId, 1, - 20, 15, 10, new DefaultEngineClock(), mock(WorkExecutionAuditor.class), meterRegistry, - new DefaultExecutorServiceMetricsProvider()); + tenantId, + meterRegistry, + new DefaultEngineClock(), + workFactory, + mock(WorkExecutionAuditor.class), + new DefaultExecutorServiceMetricsProvider(), + new WorkSingleThreadPoolExecutorFactory(tenantId, 10)); // when: defaultBonitaExecutorServiceFactory.createExecutorService(workExecutionCallback); @@ -79,9 +85,13 @@ public void should_not_have_metrics_when_unbind_is_called() { long tenantId = 97L; final SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry(); DefaultBonitaExecutorServiceFactory defaultBonitaExecutorServiceFactory = new DefaultBonitaExecutorServiceFactory( - workFactory, tenantId, 1, - 20, 15, 10, new DefaultEngineClock(), mock(WorkExecutionAuditor.class), meterRegistry, - new DefaultExecutorServiceMetricsProvider()); + tenantId, + meterRegistry, + new DefaultEngineClock(), + workFactory, + mock(WorkExecutionAuditor.class), + new DefaultExecutorServiceMetricsProvider(), + new WorkSingleThreadPoolExecutorFactory(tenantId, 10)); // when: defaultBonitaExecutorServiceFactory.createExecutorService(workExecutionCallback); diff --git a/services/bonita-work/src/test/java/org/bonitasoft/engine/work/DefaultBonitaExecutorServiceTest.java b/services/bonita-work/src/test/java/org/bonitasoft/engine/work/DefaultBonitaExecutorServiceTest.java new file mode 100644 index 00000000000..be1680f4e32 --- /dev/null +++ b/services/bonita-work/src/test/java/org/bonitasoft/engine/work/DefaultBonitaExecutorServiceTest.java @@ -0,0 +1,273 @@ +/** + * Copyright (C) 2017-2019 Bonitasoft S.A. + * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble + * This library is free software; you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Foundation + * version 2.1 of the License. + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License along with this + * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + * Floor, Boston, MA 02110-1301, USA. + **/ +package org.bonitasoft.engine.work; + +import static java.time.temporal.ChronoUnit.SECONDS; +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +import java.time.Duration; +import java.time.Instant; +import java.util.Map; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicBoolean; + +import io.micrometer.core.instrument.Clock; +import io.micrometer.core.instrument.Gauge; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import org.bonitasoft.engine.commons.time.FixedEngineClock; +import org.bonitasoft.engine.work.audit.WorkExecutionAuditor; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +/** + * @author Baptiste Mesta. + */ +public class DefaultBonitaExecutorServiceTest { + + public static final long TENANT_ID = 13L; + @Rule + public MockitoRule mockitoRule = MockitoJUnit.rule(); + @Mock + private WorkExecutionAuditor workExecutionAuditor; + private final MyWorkExecutionCallback workExecutionCallback = new MyWorkExecutionCallback(); + private DefaultBonitaExecutorService bonitaExecutorService; + private final FixedEngineClock engineClock = new FixedEngineClock(Instant.now()); + private final WorkFactory workFactory = new LocalWorkFactory(2); + private final SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry( + // So that micrometer updates its counters every 1 ms: + k -> k.equals("simple.step") ? Duration.ofMillis(1).toString() : null, + Clock.SYSTEM); + + @Before + public void before() { + var threadPoolExecutor = new WorkSingleThreadPoolExecutorFactory.SingleThreadPoolExecutor( + new LinkedBlockingQueue<>(10), + new WorkerThreadFactory("test-worker", 1, 1)); + bonitaExecutorService = new DefaultBonitaExecutorService(threadPoolExecutor, workFactory, engineClock, + workExecutionCallback, workExecutionAuditor, + meterRegistry, TENANT_ID); + } + + @Test + public void should_call_on_success_callback_when_work_executed_properly() { + WorkDescriptor workDescriptor = WorkDescriptor.create("NORMAL"); + + bonitaExecutorService.submit(workDescriptor); + + await().until(workExecutionCallback::isOnSuccessCalled); + assertThat(workExecutionCallback.isOnFailureCalled()).isFalse(); + } + + @Test + public void should_call_on_failure_callback_when_work_executed_properly() { + WorkDescriptor workDescriptor = WorkDescriptor.create("EXCEPTION"); + + bonitaExecutorService.submit(workDescriptor); + + await().until(workExecutionCallback::isOnFailureCalled); + assertThat(workExecutionCallback.isOnSuccessCalled()).isFalse(); + } + + @Test + public void should_execute_work_after_specified_date() { + WorkDescriptor workDescriptor = WorkDescriptor.create("NORMAL"); + workDescriptor.mustBeExecutedAfter(Instant.now().plus(5, SECONDS)); + + bonitaExecutorService.submit(workDescriptor); + + //should still not be executed + engineClock.addTime(1, SECONDS); + await().atLeast(50, TimeUnit.MILLISECONDS) + .untilAsserted(() -> assertThat(workExecutionCallback.isOnSuccessCalled()).isFalse()); + + //add time, work should be executed + engineClock.addTime(5, SECONDS); + await().until(workExecutionCallback::isOnSuccessCalled); + } + + @Test + public void should_update_meter_when_work_executes() { + Gauge currentWorkQueue = meterRegistry.find(DefaultBonitaExecutorService.NUMBER_OF_WORKS_PENDING).gauge(); + for (int i = 0; i <= 4; i++) { + WorkDescriptor workDescriptor = WorkDescriptor.create("SLEEP"); + bonitaExecutorService.submit(workDescriptor); + } + await().untilAsserted(() -> assertThat(currentWorkQueue.value()).isPositive()); + } + + @Test + public void should_update_works_counters_when_enqueuing_workDescriptor_with_long_processing_time() + throws Exception { + + //when: + bonitaExecutorService.submit(WorkDescriptor.create("NORMAL")); + bonitaExecutorService.submit(WorkDescriptor.create("SLEEP")); + bonitaExecutorService.submit(WorkDescriptor.create("SLEEP")); + bonitaExecutorService.submit(WorkDescriptor.create("SLEEP")); + bonitaExecutorService.submit(WorkDescriptor.create("SLEEP")); + bonitaExecutorService.submit(WorkDescriptor.create("NORMAL")); + TimeUnit.MILLISECONDS.sleep(50); // give some time to the executor to process the work + + //then: + // 1 executed because normal work is submitted first. + assertThat(meterRegistry.find(DefaultBonitaExecutorService.NUMBER_OF_WORKS_EXECUTED).counter().count()) + .as("Executed works number").isEqualTo(1); + // 1 running works because we have 1 threads in the pool and sleeping works wait for 2s to execute: + assertThat(meterRegistry.find(DefaultBonitaExecutorService.NUMBER_OF_WORKS_RUNNING).gauge().value()) + .as("Running works number").isEqualTo(1); + // 4 pending works because the single thread is busy, so the last 4 works are in the queue: + assertThat(meterRegistry.find(DefaultBonitaExecutorService.NUMBER_OF_WORKS_PENDING).gauge().value()) + .as("Pending works number").isEqualTo(4); + } + + @Test + public void should_have_no_meters_after_shutdown() { + var work = bonitaExecutorService.submit(WorkDescriptor.create("NORMAL")); + await().until(work::isDone); + + bonitaExecutorService.shutdownAndEmptyQueue(); + + assertThat(meterRegistry.getMeters()).isEmpty(); + } + + @Test + public void should_have_tenant_id_in_all_meters() { + assertThat(meterRegistry.find(DefaultBonitaExecutorService.NUMBER_OF_WORKS_EXECUTED) + .tag("tenant", String.valueOf(TENANT_ID)).counter()).isNotNull(); + assertThat(meterRegistry.find(DefaultBonitaExecutorService.NUMBER_OF_WORKS_RUNNING) + .tag("tenant", String.valueOf(TENANT_ID)).gauge()).isNotNull(); + assertThat(meterRegistry.find(DefaultBonitaExecutorService.NUMBER_OF_WORKS_PENDING) + .tag("tenant", String.valueOf(TENANT_ID)).gauge()).isNotNull(); + } + + @Test + public void should_call_on_success_callback_only_when_async_work_executed_properly() { + WorkDescriptor workDescriptor = WorkDescriptor.create("ASYNC"); + + var work = bonitaExecutorService.submit(workDescriptor); + await().until(work::isDone); + + assertThat(workExecutionCallback.isOnSuccessCalled()).isFalse(); + assertThat(workExecutionCallback.isOnFailureCalled()).isFalse(); + + await().until(workExecutionCallback::isOnSuccessCalled); + assertThat(workExecutionCallback.isOnFailureCalled()).isFalse(); + } + + @Test + public void should_call_on_failure_callback_ony_when_async_work_executed_properly() { + WorkDescriptor workDescriptor = WorkDescriptor.create("ASYNC_EXCEPTION"); + + var work = bonitaExecutorService.submit(workDescriptor); + await().until(work::isDone); + + assertThat(workExecutionCallback.isOnSuccessCalled()).isFalse(); + assertThat(workExecutionCallback.isOnFailureCalled()).isFalse(); + + await().until(workExecutionCallback::isOnFailureCalled); + assertThat(workExecutionCallback.isOnSuccessCalled()).isFalse(); + assertThat(workExecutionCallback.getThrown()).hasMessage("my exception").isInstanceOf(SWorkException.class); + } + + // ================================================================================================================= + // UTILS + // ================================================================================================================= + + private static class MyWorkExecutionCallback implements WorkExecutionCallback { + + private final AtomicBoolean onSuccessCalled = new AtomicBoolean(false); + private final AtomicBoolean onFailureCalled = new AtomicBoolean(false); + private Throwable thrown; + + @Override + public void onSuccess(WorkDescriptor workDescriptor) { + onSuccessCalled.set(true); + } + + @Override + public void onFailure(WorkDescriptor work, BonitaWork bonitaWork, Map context, + Throwable thrown) { + this.thrown = thrown; + onFailureCalled.set(true); + } + + public boolean isOnSuccessCalled() { + return onSuccessCalled.get(); + } + + public boolean isOnFailureCalled() { + return onFailureCalled.get(); + } + + public Throwable getThrown() { + return thrown; + } + } + + private record LocalWorkFactory(long workSleepPeriodInSeconds) implements WorkFactory { + + @Override + public BonitaWork create(WorkDescriptor workDescriptor) { + return new BonitaWork() { + + @Override + public String getDescription() { + return workDescriptor.toString(); + } + + @Override + public CompletableFuture work(Map context) throws Exception { + switch (workDescriptor.getType()) { + case "EXCEPTION": + throw new Exception("classic exception"); + case "SLEEP": + TimeUnit.SECONDS.sleep(workSleepPeriodInSeconds); + break; + case "ASYNC": + return CompletableFuture.supplyAsync(() -> { + try { + TimeUnit.MILLISECONDS.sleep(200); + } catch (InterruptedException ignored) { + } + return null; + }, Executors.newSingleThreadExecutor()); + case "ASYNC_EXCEPTION": + return CompletableFuture.supplyAsync(() -> { + try { + TimeUnit.MILLISECONDS.sleep(200); + } catch (InterruptedException ignored) { + } + throw new CompletionException(new SWorkException("my exception")); + }, Executors.newSingleThreadExecutor()); + case "NORMAL": + default: + } + return CompletableFuture.completedFuture(null); + } + + @Override + public void handleFailure(Throwable e, Map context) { + // do nothing + } + }; + } + +} + +}