opensagres / xdocreport

XDocReport means XML Document reporting. It's Java API to merge XML document created with MS Office (docx) or OpenOffice (odt), LibreOffice (odt) with a Java model to generate report and convert it if you need to another format (PDF, XHTML...).
https://github.com/opensagres/xdocreport
1.22k stars 372 forks source link

ServiceLoader webapp visibility issue #543

Open radist-nt opened 2 years ago

radist-nt commented 2 years ago

Method fr.opensagres.xdocreport.core.registry.AbstractRegistry.initializeIfNeeded() uses it's class classloader to load the service. The problem is that some services could be not accessible under this classloader.

Steps to reproduce:

  1. Install wildfly server (we use versions 18.0.0.Final and 21.0.0.Final)
  2. In the modules directory create module fr.opensagres.xdocreport module with xdocreport, template engines and dependencies:

    • create directory modules/fr/opensagres/xdocreport/main
    • place the following files under directory:
      • commons-collections-3.2.1.jar
      • commons-lang-2.4.jar
      • freemarker-2.3.31.jar
      • oro-2.0.8.jar
      • velocity-1.7.jar
      • xdocreport-2.0.2.jar
    • create file module.xml:
      
      <?xml version="1.0" encoding="UTF-8"?>
      <module xmlns="urn:jboss:module:1.1" name="fr.opensagres.xdocreport">
      <resources>
      <resource-root path="commons-collections-3.2.1.jar"/>
      <resource-root path="commons-lang-2.4.jar"/>
      <resource-root path="freemarker-2.3.31.jar"/>
      <resource-root path="oro-2.0.8.jar"/>
      <resource-root path="velocity-1.7.jar"/>
      <resource-root path="xdocreport-2.0.2.jar"/>
      </resources>

  3. Create webapp project from example
  4. Add the following class to the webapp project:
    
    package issue.test;

import fr.opensagres.xdocreport.document.discovery.ITemplateEngineInitializerDiscovery; import fr.opensagres.xdocreport.template.ITemplateEngine;

public class EngineInitializer implements ITemplateEngineInitializerDiscovery {

@Override
public String getId() {
    return "test";
}

@Override
public String getDescription() {
    return null;
}

@Override
public String getDocumentKind() {
    return null;
}

@Override
public void initialize(ITemplateEngine templateEngine) {
    System.out.println("initialized");
}

}

6. Add file `META-INF/services/fr.opensagres.xdocreport.document.discovery.ITemplateEngineInitializerDiscovery` with single line `issue.test.EngineInitializer` to the project
7. Add file `WEB-INF/jboss-deployment-structure.xml` to the project:

<?xml version="1.0" encoding="UTF-8"?>

8. Build webapp
9. Remove all libraries from war/WEB-INF/lib (they will be loaded from module)
10. Access to the MyReportServlet by url http://localhost:8080/issue-test/reportServlet/docx?templateEngineKind=Velocity&reportId=DocxProjectWithVelocity.docx&dispatch=view&entryName=word%2Fdocument.xml
11. Inspect the `wildfly/standalone/logs/server.log` file

**Expected behaviour**
several lines with 'initialized' message, i.e.:

2022-04-06 13:10:03,189 INFO [stdout] (default task-71) initialized 2022-04-06 13:10:03,189 INFO [stdout] (default task-71) initialized 2022-04-06 13:10:03,189 INFO [stdout] (default task-71) initialized 2022-04-06 13:10:03,189 INFO [stdout] (default task-71) initialized


This could be obtained by deploying the war file with skipped step 9 (with libraries in WEB-INF/lib) and removed jboss-deployment-structure.xml file.

**Actual behaviour**
No lines with 'initialized' message. So, ITemplateEngineInitializerDiscovery service not found.

**How to fix issue**
Use `Thread.currentThread().getContextClassLoader()` instead of (or along with) current class classloader
radist-nt commented 2 years ago

See ready eclipse project issue-test.zip

angelozerr commented 2 years ago

Any pr are welcome

radist-nt commented 2 years ago

https://github.com/opensagres/xdocreport/pull/544

radist-nt commented 2 years ago

Hmm... however, it's not a ultimate fix. xdocreport uses static singleton for TemplateEngineInitializerRegistry, so if it will be deployed as module and several war deployments will use the same TemplateEngineInitializerRegistry and initializers from the only first war deployment will be activated...