From 852c1d04b26d20c5f4e7f927e81b6317ed024184 Mon Sep 17 00:00:00 2001 From: Romain Bioteau Date: Wed, 27 Nov 2024 15:14:06 +0100 Subject: [PATCH] fix(classloader): always reset current classloader after an API call --- .github/workflows/build.yml | 2 +- pom.xml | 21 ++++++++++-------- .../connectors/email/EmailConnector.java | 18 +++++++++++++-- .../email/EmailConnectorRuntimeIT.java | 4 +++- .../connectors/test/BonitaContainer.java | 2 +- .../test/impl/ConnectorExecutorImpl.java | 15 ++++++++++++- src/test/resources/myDoc.docx | Bin 0 -> 12762 bytes 7 files changed, 47 insertions(+), 15 deletions(-) create mode 100644 src/test/resources/myDoc.docx diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 227eda6..b6aaf5e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -41,7 +41,7 @@ jobs: env: GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} SONAR_TOKEN: ${{secrets.SONAR_TOKEN}} - run: ./mvnw -B sonar:sonar -Dsonar.login=${{ secrets.SONAR_TOKEN }} + run: ./mvnw -B sonar:sonar - name: Copy artifacts for staging run: | diff --git a/pom.xml b/pom.xml index 569b5cd..e4534df 100644 --- a/pom.xml +++ b/pom.xml @@ -45,13 +45,13 @@ 1.6.7 - 7.13.0 + 8.0.0 5.11.3 1.6.11 - 0.8.11 - 3.10.0.2594 + 0.8.12 + 5.0.0.4389 5.8.0 3.24.2 1.2.13 @@ -312,7 +312,7 @@ org.codehaus.groovy groovy - 3.0.19 + 3.0.23 @@ -335,6 +335,9 @@ prepare-agent-integration + + ${project.build.directory}/jacoco.exec + jacoco-site @@ -432,24 +435,24 @@ maven-failsafe-plugin - integration-tests-7.13 + integration-tests-8.0 integration-test - 7.13.0 + 8.0.0 - integration-tests-7.14 + integration-test-10.2 integration-test - 7.14.0 + 10.2 @@ -474,7 +477,7 @@ org.apache.maven.plugins maven-gpg-plugin - 3.1.0 + 3.2.7 sign-artifacts diff --git a/src/main/java/org/bonitasoft/connectors/email/EmailConnector.java b/src/main/java/org/bonitasoft/connectors/email/EmailConnector.java index 9ac0707..c740638 100644 --- a/src/main/java/org/bonitasoft/connectors/email/EmailConnector.java +++ b/src/main/java/org/bonitasoft/connectors/email/EmailConnector.java @@ -470,7 +470,14 @@ private void handleAttachment(boolean html, StringBuilder messageBody, ProcessAP private void addBodyPart(ProcessAPI processAPI, List bodyParts, Document document) throws DocumentNotFoundException, MessagingException { String fileName = document.getContentFileName(); - byte[] docContent = processAPI.getDocumentContent(document.getContentStorageId()); + byte[] docContent = null; + // Workaround RUNTIME-1919 + ClassLoader currentClassloader = Thread.currentThread().getContextClassLoader(); + try { + docContent = processAPI.getDocumentContent(document.getContentStorageId()); + }finally { + Thread.currentThread().setContextClassLoader(currentClassloader); + } if (docContent != null) { String mimeType = document.getContentMimeType(); var bodyPart = new MimeBodyPart(); @@ -487,7 +494,14 @@ private Document getDocument(Object attachment, ProcessAPI processAPI) if (attachment instanceof String && !((String) attachment).trim().isEmpty()) { String docName = (String) attachment; long processInstanceId = getExecutionContext().getProcessInstanceId(); - return processAPI.getLastDocument(processInstanceId, docName); + // Workaround RUNTIME-1919 + ClassLoader currentClassloader = Thread.currentThread().getContextClassLoader(); + try{ + return processAPI.getLastDocument(processInstanceId, docName); + }finally { + Thread.currentThread().setContextClassLoader(currentClassloader); + } + } else if (attachment instanceof Document) { return (Document) attachment; } else { diff --git a/src/test/java/org/bonitasoft/connectors/email/EmailConnectorRuntimeIT.java b/src/test/java/org/bonitasoft/connectors/email/EmailConnectorRuntimeIT.java index e8a8c5a..df31cba 100644 --- a/src/test/java/org/bonitasoft/connectors/email/EmailConnectorRuntimeIT.java +++ b/src/test/java/org/bonitasoft/connectors/email/EmailConnectorRuntimeIT.java @@ -20,6 +20,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; +import java.util.List; import java.util.Map; import javax.mail.internet.MimeMessage; @@ -61,6 +62,7 @@ void test0(ConnectorExecutor executor) throws Exception { .addInput(EmailConnector.TO, Expression.stringValue("receiver@bonitasoft.com")) .addInput(EmailConnector.SUBJECT, Expression.stringValue("Testing Subject")) .addInput(EmailConnector.MESSAGE, Expression.stringValue("Hello World")) + .addInput(EmailConnector.ATTACHMENTS, Expression.groovyScript("['myDoc']", List.class.getName())) .build(); Map result = executor.execute(configuration); @@ -74,7 +76,7 @@ void test0(ConnectorExecutor executor) throws Exception { assertThat(message.getFrom()[0]).hasToString("romain.bioteau@bonitasoft.com"); assertThat(message.getRecipients(RecipientType.TO)[0]).hasToString("receiver@bonitasoft.com"); assertThat(message.getSubject()).isEqualTo("Testing Subject"); - assertThat(GreenMailUtil.getBody(message)).isEqualTo("Hello World"); + assertThat(GreenMailUtil.getBody(message)).contains("Hello World"); } } diff --git a/src/test/java/org/bonitasoft/connectors/test/BonitaContainer.java b/src/test/java/org/bonitasoft/connectors/test/BonitaContainer.java index b972413..db822b4 100644 --- a/src/test/java/org/bonitasoft/connectors/test/BonitaContainer.java +++ b/src/test/java/org/bonitasoft/connectors/test/BonitaContainer.java @@ -56,7 +56,7 @@ public class BonitaContainer extends GenericContainer { private User user; public BonitaContainer() { - this(System.getProperty("bonita.version", "7.13")); + this(System.getProperty("bonita.version", "10.2")); } public BonitaContainer(String version) { diff --git a/src/test/java/org/bonitasoft/connectors/test/impl/ConnectorExecutorImpl.java b/src/test/java/org/bonitasoft/connectors/test/impl/ConnectorExecutorImpl.java index ea38059..24d1534 100644 --- a/src/test/java/org/bonitasoft/connectors/test/impl/ConnectorExecutorImpl.java +++ b/src/test/java/org/bonitasoft/connectors/test/impl/ConnectorExecutorImpl.java @@ -30,6 +30,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.UUID; import java.util.function.Function; import java.util.function.Predicate; @@ -52,6 +53,8 @@ import org.bonitasoft.engine.bpm.process.impl.ProcessDefinitionBuilder; import org.bonitasoft.engine.expression.Expression; import org.bonitasoft.engine.expression.ExpressionBuilder; +import org.bonitasoft.engine.expression.ExpressionInterpreter; +import org.bonitasoft.engine.expression.ExpressionType; import org.bonitasoft.engine.expression.InvalidExpressionException; import org.bonitasoft.engine.operation.OperationBuilder; @@ -167,6 +170,9 @@ private DesignProcessDefinition buildConnectorInProcess(Configuration configurat var processBuilder = new ProcessDefinitionBuilder(); processBuilder.createNewInstance("PROCESS_UNDER_TEST", "1.0"); processBuilder.addActor("system"); + processBuilder.addDocumentDefinition("myDoc") + .addFile("myDoc.docx") + .addContentFileName("myDoc.docx"); var expConverter = expressionConverter(); var connectorBuilder = processBuilder.addConnector("connector-under-test", configuration.getDefinitionId(), @@ -197,8 +203,11 @@ private static Function expressionConverte try { return expBuilder.createExpression(UUID.randomUUID().toString(), exp.getContent(), + exp.getType(), exp.getReturnType(), - exp.getType()); + Objects.equals(exp.getType(), ExpressionType.TYPE_READ_ONLY_SCRIPT) ? ExpressionInterpreter.GROOVY.name(): null, + List.of() + ); } catch (InvalidExpressionException e) { throw new RuntimeException(e); } @@ -243,6 +252,10 @@ private BusinessArchive buildBusinessArchive(DesignProcessDefinition process, actorMapping.addActor(systemActor); barBuilder.setActorMapping(actorMapping); + try(var is = ConnectorExecutorImpl.class.getResourceAsStream("/myDoc.docx")){ + barBuilder.addDocumentResource(new BarResource("myDoc.docx", is.readAllBytes())); + } + return barBuilder.done(); } diff --git a/src/test/resources/myDoc.docx b/src/test/resources/myDoc.docx new file mode 100644 index 0000000000000000000000000000000000000000..1ee0b9fd400ac094a5379c896c5a94d1220a1655 GIT binary patch literal 12762 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 CM;>AT literal 0 HcmV?d00001