Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

As a programmer, I want strong modular boundaries (use Java modules introduced by project jigsaw) #208

Open
epag opened this issue Aug 21, 2024 · 78 comments

Comments

@epag
Copy link
Collaborator

epag commented Aug 21, 2024


Author Name: Jesse (Jesse)
Original Redmine Issue: 62732, https://vlab.noaa.gov/redmine/issues/62732
Original Date: 2019-04-18


Given a build of WRES
When try to use the various modules (jars) in another program or another module
Then there should be clear and strong boundaries enforced by the system

Many people worked for a long time to afford this possibility with Java 9 in "Project Jigsaw":https://openjdk.java.net/projects/jigsaw/ so now that we are past Java 8 we can start to make use of these features.


Related issue(s): #102
Redmine related issue(s): 111518, 111532, 119337


@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2019-04-18T16:03:08Z


Rename to not be relative

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2019-04-18T16:12:13Z


Again clarify title. "Jigsaw" was a project, "Modules" are the construct.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2021-07-21T20:46:39Z


Should improve startup performance as well.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2021-09-02T17:38:51Z


Bump. Probably can do it incrementally. Progress in the gradle build in the last few weeks, moving to the @implementation@ and @api@ declarations, which are kind of related to the modular boundaries and descriptions.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-04T16:15:37Z


This should be done regardless of or prior to using native-image or server mode in WRES because this will improve performance in all three situations (the current situation or mode being the third).

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T16:31:56Z


The order in which to do it, from simplest leaf modules with fewest deps up to complex trunk modules with most deps:

  1. wres-messages
  2. wres-worker
    ...

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T18:01:56Z


I added this to the @wres-messages@ section of the @build.gradle@:

    // Make this a Java Platform Module System (Java 9 jigsaw) module
    java. modularity.inferModulePath.set( true  )

I added a @wres-messages/src/main/java/module-info.java@ with these contents:

module wres.messages
{
    requires java.base;
    requires com.google.protobuf;
    exports wres.messages.generated;
    exports wres.messages;
}

Then I tried building the jar:

[wres-messages]$ ../gradlew jar

> Task :wres-messages:compileJava FAILED
/home/jesse/code/wres/wres-messages/src/main/java/wres/messages/BrokerHelper.java:21: error: package org.slf4j is not visible
import org.slf4j.Logger;
          ^
  (package org.slf4j is declared in module org.slf4j, but module wres.messages does not read it)
/home/jesse/code/wres/wres-messages/src/main/java/wres/messages/BrokerHelper.java:22: error: package org.slf4j is not visible
import org.slf4j.LoggerFactory;
          ^
  (package org.slf4j is declared in module org.slf4j, but module wres.messages does not read it)
2 errors

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':wres-messages:compileJava'.
> Compilation failed; see the compiler error output for details.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 6s
4 actionable tasks: 3 executed, 1 up-to-date

Good. It seems to have had an effect and gradle tried to build it as a module. @wres.messages@ indeed uses @org.slf4j@ so I need to add that to the @module-info.java@.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T18:03:28Z


After adding @requires org.slf4j;@ to the @module-info.java@, it built the jar:

[wres-messages]$ ../gradlew jar

Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.9.1/userguide/command_line_interface.html#sec:command_line_warnings

BUILD SUCCESSFUL in 5s
6 actionable tasks: 3 executed, 3 up-to-date

Is that it? If so, great!

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T18:12:28Z


What's inside the jar?

[build]$ cd libs/
[libs]$ ls
wres-messages-20220426-1085a15-dev.jar
[libs]$ unzip wres-messages-20220426-1085a15-dev.jar 
Archive:  wres-messages-20220426-1085a15-dev.jar
   creating: META-INF/
  inflating: META-INF/MANIFEST.MF    
  inflating: module-info.class       
   creating: wres/
   creating: wres/messages/
  inflating: wres/messages/BrokerHelper$Role.class  
  inflating: wres/messages/BrokerHelper.class  
   creating: wres/messages/generated/
  inflating: wres/messages/generated/Job$job$1.class  
  inflating: wres/messages/generated/Job$job$Builder.class  
  inflating: wres/messages/generated/Job$job$Verb$1.class  
  inflating: wres/messages/generated/Job$job$Verb.class  
  inflating: wres/messages/generated/Job$job.class  
  inflating: wres/messages/generated/Job$jobOrBuilder.class  
  inflating: wres/messages/generated/Job.class  
  inflating: wres/messages/generated/JobOutput$job_output$1.class  
  inflating: wres/messages/generated/JobOutput$job_output$Builder.class  
  inflating: wres/messages/generated/JobOutput$job_output.class  
  inflating: wres/messages/generated/JobOutput$job_outputOrBuilder.class  
  inflating: wres/messages/generated/JobOutput.class  
  inflating: wres/messages/generated/JobResult$job_result$1.class  
  inflating: wres/messages/generated/JobResult$job_result$Builder.class  
  inflating: wres/messages/generated/JobResult$job_result.class  
  inflating: wres/messages/generated/JobResult$job_resultOrBuilder.class  
  inflating: wres/messages/generated/JobResult.class  
  inflating: wres/messages/generated/JobStandardStream$job_standard_stream$1.class  
  inflating: wres/messages/generated/JobStandardStream$job_standard_stream$Builder.class  
  inflating: wres/messages/generated/JobStandardStream$job_standard_stream.class  
  inflating: wres/messages/generated/JobStandardStream$job_standard_streamOrBuilder.class  
  inflating: wres/messages/generated/JobStandardStream.class  
  inflating: wres/messages/generated/JobStatus$job_status$1.class  
  inflating: wres/messages/generated/JobStatus$job_status$Builder.class  
  inflating: wres/messages/generated/JobStatus$job_status$Report$1.class  
  inflating: wres/messages/generated/JobStatus$job_status$Report.class  
  inflating: wres/messages/generated/JobStatus$job_status.class  
  inflating: wres/messages/generated/JobStatus$job_statusOrBuilder.class  
  inflating: wres/messages/generated/JobStatus.class  
  inflating: job.proto               
  inflating: job_output.proto        
  inflating: job_result.proto        
  inflating: job_standard_stream.proto  
  inflating: job_status.proto        
  inflating: trustedCertificateAuthorities.jks  
[libs]$ cat META-INF/MANIFEST.MF 
Manifest-Version: 1.0
Implementation-Title: Water Resources Evaluation Service
Implementation-Version: 20220426-1085a15-dev

[libs]$ xxd module-info.class 
0000000: cafe babe 0000 0037 0014 0700 0d01 000a  .......7........
0000010: 536f 7572 6365 4669 6c65 0100 106d 6f64  SourceFile...mod
0000020: 756c 652d 696e 666f 2e6a 6176 6101 0006  ule-info.java...
0000030: 4d6f 6475 6c65 1300 0e13 000f 0100 0731  Module.........1
0000040: 312e 302e 3135 1300 1013 0011 0100 0c32  1.0.15.........2
0000050: 2e30 2e30 2d61 6c70 6861 3714 0012 1400  .0.0-alpha7.....
0000060: 1301 000b 6d6f 6475 6c65 2d69 6e66 6f01  ....module-info.
0000070: 000d 7772 6573 2e6d 6573 7361 6765 7301  ..wres.messages.
0000080: 0009 6a61 7661 2e62 6173 6501 0013 636f  ..java.base...co
0000090: 6d2e 676f 6f67 6c65 2e70 726f 746f 6275  m.google.protobu
00000a0: 6601 0009 6f72 672e 736c 6634 6a01 0017  f...org.slf4j...
00000b0: 7772 6573 2f6d 6573 7361 6765 732f 6765  wres/messages/ge
00000c0: 6e65 7261 7465 6401 000d 7772 6573 2f6d  nerated...wres/m
00000d0: 6573 7361 6765 7380 0000 0100 0000 0000  essages.........
00000e0: 0000 0000 0200 0200 0000 0200 0300 0400  ................
00000f0: 0000 2e00 0500 0000 0000 0300 0600 0000  ................
0000100: 0700 0800 0000 0000 0900 0000 0a00 0200  ................
0000110: 0b00 0000 0000 0c00 0000 0000 0000 0000  ................
0000120: 00                                       .

Nice. Now on to @wres-worker@...

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T18:23:08Z


Hmm, no such error when building the jar for @wres-worker@ when missing @com.rabbitmq@. But after doing a clean, OK, it had the expected errors.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T18:30:03Z


Here is the @module-info.java@ for @wres-worker@:

module wres.worker
{
    requires java.base;
    requires com.google.protobuf;
    requires com.rabbitmq.client;
    requires org.slf4j;
    requires wres.messages;
}

It doesn't export anything because it's a top-level application. It only uses this handful of libraries.

What about using @jlink@ now? Can gradle do that for me? Looking...

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T18:31:20Z


A nice note here at https://docs.gradle.org/6.9.1/userguide/java_library_plugin.html#declaring_module_dependencies

Gradle currently does not automatically check if the dependency declarations are in sync. This may be added in future versions.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T18:39:31Z


Should @wres-messages@ call @protobuf@ an @api@ dependency? Maybe. Does @wres-worker@ import/use any classes from @protobuf@ that are not @wres.messages@ classes? Yeah, a couple of spots it uses a timestamp and an exception.

Edit: and it already declares protobuf an @api@ dependency, so we need to make the Java Module Directive in @module-info.java@ match the declaration in @build.gradle@, i.e. to be @requires transitive@.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T18:52:23Z


When making it match, protobuf is reported as an automatic module:

[wres-messages]$ ../gradlew jar

> Task :wres-messages:compileJava
/home/user/code/wres/wres-messages/src/main/java/module-info.java:3: warning: requires transitive directive for an automatic module
    requires transitive com.google.protobuf;
                                  ^
1 warning

BUILD SUCCESSFUL in 4s
6 actionable tasks: 2 executed, 4 up-to-date

Why the warning?
https://stackoverflow.com/questions/46750408/why-does-javac-complain-about-named-automatic-modules refers to mailing list answer at https://mail.openjdk.java.net/pipermail/jigsaw-dev/2017-October/013249.html

the main issue is that an automatic module can see classes from the classpath, but it also exports all its package so there is no encapsulation, and once you require one automatic module all automatic modules from the module path are visible.
So an automatic module is a great tool when you transitioned to the module world, but in fine, you do not want any automatic modules in you dependency graph.

So we probably do not want @requires transitive@ for protobuf, because that would add everything that protobuf has and uses? I don't quite have the picture in my head but I trust the warning. Going back to @requires@.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T18:56:43Z


I see this gradle plugin for jlink: https://plugins.gradle.org/plugin/org.beryx.jlink

It warns that it is a complex plugin and to read the docs first. Perhaps I should try jlink by hand first with @wres-worker@ which is a relatively simple application.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T18:58:11Z


Before that, a @JavaDoc@ task failure when cleaning and compiling the whole tree:

> Task :wres-messages:javadoc
/home/user/code/wres/wres-messages/src/main/java/module-info.java:6: error: package is empty or does not exist: wres.messages.generated
    exports wres.messages.generated;
                         ^
1 error

> Task :wres-messages:javadoc FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':wres-messages:javadoc'.
> Javadoc generation failed. Generated Javadoc options file (useful for troubleshooting): '/home/user/code/wres/wres-messages/build/tmp/javadoc/javadoc.options'

Edit: I had previously excluded generated code javadocs:

    javadoc
    {
        // Protobuf does not appear to generate javadoc, so neither will we.
        excludes = ['**/generated/*.java']
    }
</code>

Edit4: removing that exclusion from submodules and from wres-messages resolves the immediate issue but then creates a different issue of annoying warnings from lack of complete javadocs from protoc.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T19:46:15Z


It may be a high bar to use jlink:

[wres-worker]$ find
.
./lib
./lib/conf
./lib/conf/logback.xml
./lib/wres-worker-20220426-1085a15-dev.jar
./lib/wres-messages-20220426-1085a15-dev.jar
./lib/amqp-client-5.14.2.jar
./lib/logback-classic-1.3.0-alpha14.jar
./lib/slf4j-api-2.0.0-alpha7.jar
./lib/protobuf-java-3.20.1.jar
./lib/logback-core-1.3.0-alpha14.jar
./bin
./bin/wres-worker
./bin/wres-worker.bat
[wres-worker]$ $JAVA_HOME/bin/jlink --module-path $JAVA_HOME/jmods:lib --add-modules wres.worker --output workerapp
Error: automatic module cannot be used with jlink: com.rabbitmq.client from file:///home/user/code/wres/wres-worker/build/install/wres-worker/lib/amqp-client-5.14.2.jar

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T20:00:09Z


There are facilities for generating a @module-info.java@ for 3rd-party jars, though. @jdeps@ etc.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T20:01:17Z


Back to that gradle plugin:

Using this Gradle plugin you can create a custom runtime image of your modular application with minimal effort, even if it depends on automatic modules.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T20:19:33Z


I added the plugin to @wres-worker@ and ran the @jlink@ task which on the surface worked fine:

[wres-worker]$ ../gradlew jlink

> Task :wres-worker:jlink
The module name specified in 'application.mainModule' (null) has not the expected value (wres.worker).

BUILD SUCCESSFUL in 17s
13 actionable tasks: 8 executed, 5 up-to-date

However, when running the resulting script:

[image]$ cat bin/wres-worker
#!/bin/sh
SCRIPT_NAME=$(basename "$0")
APP_NAME=${SCRIPT_NAME%.sh}

DIR="${0%/*}"



"$DIR/java" $CDS_JVM_OPTS -Xms64m -Xmx64m -XX:+HeapDumpOnOutOfMemoryError -p "$DIR/../app" -m wres.worker/wres.worker.Worker  "$@"
[image]$ time bin/wres-worker /home/user/code/wres/build/install/wres/bin/wres
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#noProviders for further details.
Exception in thread "main" java.lang.IllegalAccessError: class com.rabbitmq.client.ConnectionFactory (in module wres.merged.module) cannot access class org.slf4j.LoggerFactory (in module org.slf4j) because module wres.merged.module does not read module org.slf4j
	at wres.merged.module@20220426-1085a15-dev/com.rabbitmq.client.ConnectionFactory.<clinit>(ConnectionFactory.java:55)
	at wres.worker/wres.worker.Worker.main(Worker.java:76)

real	0m0.285s
user	0m0.161s
sys	0m0.052s

However, this probably only means we need to add @org.slf4j@ to the merged module. The plugin takes all "automatic" modules and merges them together into a mega-module proper. So perhaps I can have the additional dep added somewhere.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T20:24:48Z


That's a pretty nice sized image, though:

[image]$ du -h
23M	./lib/server
416K	./lib/security
76K	./lib/jli
94M	./lib
12K	./conf/security/policy/limited
8.0K	./conf/security/policy/unlimited
24K	./conf/security/policy
88K	./conf/security
104K	./conf
8.0K	./include/linux
212K	./include
40K	./bin
72K	./legal/java.desktop
72K	./legal/java.base
0	./legal/java.datatransfer
48K	./legal/java.xml
0	./legal/java.prefs
0	./legal/java.logging
0	./legal/java.security.sasl
0	./legal/java.naming
0	./legal/java.transaction.xa
0	./legal/java.sql
0	./legal/jdk.unsupported
192K	./legal
95M	.

95MiB including java runtime.

Ubi8 is around 216MiB sans java runtime, the @wres-worker@ image is 583MiB including the 2.8MiB of application and by deduction 364MiB of JVM. So an ubi8 image plus this jlink wres-worker image would presumably be around 311MiB instead of 583MiB.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T20:29:47Z


The jlink plugin includes a handy @suggestMergedModuleInfo@ gradle task, which I believe is showing what it generated for the unnamed module subsuming all non-truly-jpms-modules:

[wres-worker]$ ../gradlew suggestMergedModuleInfo

> Task :wres-worker:suggestMergedModuleInfo
mergedModule {
    requires 'java.naming';
    requires 'java.logging';
    requires 'java.security.sasl';
    requires 'java.sql';
    requires 'java.desktop';
    requires 'jdk.unsupported';
}

BUILD SUCCESSFUL in 5s

That's a pretty short list.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T21:02:56Z


Edit: I added this jlink block to the @wres-worker@ block of @build.gradle@ to specify the @org.slf4j@ dependency:

    jlink
    {
        // The merged module is a technique from the plugin that aggregates/merges
        // improper/automatic modules into a proper JPMS module.
        mergedModuleName = 'wres.worker.mergedDepsModule'

        mergedModule
        {
            requires 'java.base'
            requires 'org.slf4j'
        }
    }
</code>

It seems to have partially worked, maybe we need to include logback, though:

[bin]$ time ./wres-worker /home/user/code/wres/build/install/wres/bin/wres
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#noProviders for further details.
Exception in thread "main" java.lang.IllegalStateException: WRES expected to find a file '/wres_secrets/wres-worker_client_private_key_and_x509_cert.p12' with PKCS#12 format, with both a client certificate AND the private key inside, used to authenticate to the broker.
	at wres.messages/wres.messages.BrokerHelper.getSSLContextWithClientCertificate(BrokerHelper.java:313)
	at wres.worker/wres.worker.Worker.main(Worker.java:83)
Caused by: java.io.FileNotFoundException: /wres_secrets/wres-worker_client_private_key_and_x509_cert.p12 (No such file or directory)
	at java.base/java.io.FileInputStream.open0(Native Method)
	at java.base/java.io.FileInputStream.open(FileInputStream.java:219)
	at java.base/java.io.FileInputStream.<init>(FileInputStream.java:157)
	at java.base/java.io.FileInputStream.<init>(FileInputStream.java:112)
	at wres.messages/wres.messages.BrokerHelper.getSSLContextWithClientCertificate(BrokerHelper.java:306)
	... 1 more

real	0m0.273s
user	0m0.159s
sys	0m0.086s
[bin]$ pwd
/home/user/code/wres/wres-worker/build/image/bin

That seems to be about twice as fast to get off the ground as this (default script):

[bin]$ cd ../../../
[wres-worker]$ cd build/install/wres-worker/bin/
[bin]$ time ./wres-worker /home/jesse/code/wres/build/install/wres/bin/wres
2022-04-26T16:01:38.536-0500 [main] INFO wres.worker.Worker - Using broker at host 'localhost', vhost 'wres', port '5671'
Exception in thread "main" java.lang.IllegalStateException: WRES expected to find a file '/wres_secrets/wres-worker_client_private_key_and_x509_cert.p12' with PKCS#12 format, with both a client certificate AND the private key inside, used to authenticate to the broker.
	at wres.messages.BrokerHelper.getSSLContextWithClientCertificate(BrokerHelper.java:313)
	at wres.worker.Worker.main(Worker.java:83)
Caused by: java.io.FileNotFoundException: /wres_secrets/wres-worker_client_private_key_and_x509_cert.p12 (No such file or directory)
	at java.base/java.io.FileInputStream.open0(Native Method)
	at java.base/java.io.FileInputStream.open(FileInputStream.java:219)
	at java.base/java.io.FileInputStream.<init>(FileInputStream.java:157)
	at java.base/java.io.FileInputStream.<init>(FileInputStream.java:112)
	at wres.messages.BrokerHelper.getSSLContextWithClientCertificate(BrokerHelper.java:306)
	... 1 more

real	0m0.549s
user	0m0.503s
sys	0m0.133s

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T21:12:32Z


Hmm, module paths are different from classpaths, and attempting to add @ requires ch.qos.logback;@ shows an error even in my IDE, same at @jar@ time, same for @ch.qos.logback.classic@ and/or @ch.qos.logback.core@. I have logback-classic specified as a @runtimeOnly@ dependency in gradle but to get it in the module I suppose it has to be compile time.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T21:15:33Z


Something like this, perhaps: beryx/badass-jlink-plugin#191

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T21:23:36Z


Nice. You can use the mergedModule to help include these runtime dependencies in the resulting image. After adding @requiresTransitive 'ch.qos.logback.classic'@ to the @mergedModule@ block in the @jlink@ block exposed by the @org.beryx.jlink@ plugin, it seems logback is there (and increases the runtime a little too):

[bin]$ time ./wres-worker /home/jesse/code/wres/build/install/wres/bin/wres
16:19:51.574 [main] INFO wres.worker.Worker - Using broker at host 'localhost', vhost 'wres', port '5671'
Exception in thread "main" java.lang.IllegalStateException: WRES expected to find a file '/wres_secrets/wres-worker_client_private_key_and_x509_cert.p12' with PKCS#12 format, with both a client certificate AND the private key inside, used to authenticate to the broker.
	at wres.messages/wres.messages.BrokerHelper.getSSLContextWithClientCertificate(BrokerHelper.java:313)
	at wres.worker/wres.worker.Worker.main(Worker.java:83)
Caused by: java.io.FileNotFoundException: /wres_secrets/wres-worker_client_private_key_and_x509_cert.p12 (No such file or directory)
	at java.base/java.io.FileInputStream.open0(Native Method)
	at java.base/java.io.FileInputStream.open(FileInputStream.java:219)
	at java.base/java.io.FileInputStream.<init>(FileInputStream.java:157)
	at java.base/java.io.FileInputStream.<init>(FileInputStream.java:112)
	at wres.messages/wres.messages.BrokerHelper.getSSLContextWithClientCertificate(BrokerHelper.java:306)
	... 1 more

real	0m0.337s
user	0m0.294s
sys	0m0.089s

So using the jlink image it only is shaving off about 1/5 of a second from startup. The bigger advantages will be the smaller docker images, better modularity, security.

Edit: and it is still not par because I don't see the logback.xml being applied properly here, so that string formatting could add back another 100ms, who knows?

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T21:30:43Z


Better answer probably here, mentioning that logback uses SPI: https://stackoverflow.com/questions/54777923/logback-in-a-java-9-modular-application-not-working

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-26T21:44:54Z


Or just adding @requires@ works too. I'm not sure that this is the best answer, though:

    jlink
    {
        // The merged module is a technique from the org.beryx.jlink plugin that
        // aggregates/merges improper/automatic modules into a proper JPMS
        // module.
        mergedModuleName = 'wres.worker.mergedDepsModule'

        mergedModule
        {
            requires 'java.base'
            requires 'org.slf4j'
            requires 'ch.qos.logback.classic'
        }
    }

Edit: and on clean build this does not suffice.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-27T14:31:44Z


Adding @ forceMerge 'slf4j'@ was not enough to bring logback on either.

I tried this, but it causes a different error, which makes sense on second glance because it is forcing inclusion of all dependencies of the declared modules:

    // Jlink is separate from making the jar a module and is at the application
    // level, but made possible by the use of JPMS modules.
    jlink
    {
        // The merged module is a technique from the org.beryx.jlink plugin that
        // aggregates/merges improper/automatic modules into a proper JPMS
        // module.
        mergedModuleName = 'wres.worker.mergedDepsModule'

        forceMerge 'slf4j'
        forceMerge 'logback-classic'
    }
</code>

Error:

[wres-worker]$ ../gradlew clean jar jlink

> Task :wres-worker:compileJava
Note: /home/user/code/wres/wres-worker/src/wres/worker/JobOutputMessenger.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

> Task :wres-worker:createMergedModule
Cannot derive uses clause from service loader invocation in: ch/qos/logback/classic/util/ClassicEnvUtil.loadFromServiceLoader().
/home/user/code/wres/wres-worker/build/jlinkbase/tmpjars/wres.worker.mergedDepsModule/module-info.java:49: error: package jakarta.servlet does not exist
    provides jakarta.servlet.ServletContainerInitializer with ch.qos.logback.classic.servlet.LogbackServletContainerInitializer;
                            ^
1 error

> Task :wres-worker:createMergedModule FAILED

FAILURE: Build failed with an exception.

How about add extra dependencies? Like this:

    // Jlink is separate from making the jar a module and is at the application
    // level, but made possible by the use of JPMS modules.
    jlink
    {
        // The merged module is a technique from the org.beryx.jlink plugin that
        // aggregates/merges improper/automatic modules into a proper JPMS
        // module.
        mergedModuleName = 'wres.worker.mergedDepsModule'

        //forceMerge 'slf4j'
        addExtraDependencies 'logback-classic'
    }
</code>

It builds, but logback does not come in, and a different issue occurs:

[wres-worker]$ cd build/image/bin/
[bin]$ time ./wres-worker /home/jesse/code/wres/build/install/wres/bin/wres
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#noProviders for further details.
Exception in thread "main" java.lang.IllegalAccessError: class com.rabbitmq.client.ConnectionFactory (in module wres.worker.mergedDepsModule) cannot access class org.slf4j.LoggerFactory (in module org.slf4j) because module wres.worker.mergedDepsModule does not read module org.slf4j
	at wres.worker.mergedDepsModule@20220426-1085a15-dev/com.rabbitmq.client.ConnectionFactory.<clinit>(ConnectionFactory.java:55)
	at wres.worker/wres.worker.Worker.main(Worker.java:76)

Given the multitude of options available with this plugin I am pretty confident it is a matter of finding the exact right incantation.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-27T14:37:40Z


Here is the @jlink@ command the plugin generates (found by adding @--debug@ to the @Gradlew@ command):
@2022-04-27T09:32:57.796-0500 [INFO] [org.gradle.process.internal.DefaultExecHandle] Starting process 'command '/home/user/Downloads/zulu11.56.19-ca-jdk11.0.15-linux_x64/bin/jlink''. Working directory: /home/user/code/wres/wres-worker Command: /home/user/Downloads/zulu11.56.19-ca-jdk11.0.15-linux_x64/bin/jlink -v --module-path /home/user/Downloads/zulu11.56.19-ca-jdk11.0.15-linux_x64/jmods/:/home/user/code/wres/wres-worker/build/jlinkbase/jlinkjars --add-modules wres.worker,wres.worker.mergedDepsModule --output /home/user/code/wres/wres-worker/build/image@

Do we want it added as a module there in @--add-modules@? Perhaps finding the right @jlink@ command first and then figuring out how to get the plugin to do that is better.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-27T23:56:00Z


https://github.com/nebula-plugins/gradle-aggregate-javadocs-plugin is marked archived by the owner. Well, it still seemed to work.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-28T22:41:59Z


I tried @io.freefair.aggregate-javadoc@ 6.4.3 but it didn't let me run @./gradlew tasks@.

Then I tried @me.julb.gradleplugins.aggregatejavadoc@ and it failed with the same error as the netflix (one we had earlier). This one lets me exclude whole subprojects but I don't really want to do that either. I would like them all included.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-28T22:46:13Z


This one from spring @ id "io.spring.javadoc-aggregate" version "0.0.1"@ gives an interesting verbose error:

[wres]$ ./gradlew aggregateJavadoc
> Task :aggregateJavadoc FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':aggregateJavadoc'.
> Could not resolve all files for configuration ':sourcesPath'.
   > Could not resolve org.slf4j:slf4j-api:2.0.0-alpha7.
     Required by:
         project :
      > No matching variant of org.slf4j:slf4j-api:2.0.0-alpha7 was found. The consumer was configured to find a runtime of sources, as well as attribute 'org.gradle.docselements' with value 'sources' but:
          - Variant 'compile' capability org.slf4j:slf4j-api:2.0.0-alpha7:
              - Incompatible because this component declares an API of a library and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'enforced-platform-compile' capability org.slf4j:slf4j-api-derived-enforced-platform:2.0.0-alpha7:
              - Incompatible because this component declares an API of an enforced platform and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'enforced-platform-runtime' capability org.slf4j:slf4j-api-derived-enforced-platform:2.0.0-alpha7 declares a runtime of a component:
              - Incompatible because this component declares an enforced platform and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'platform-compile' capability org.slf4j:slf4j-api-derived-platform:2.0.0-alpha7:
              - Incompatible because this component declares an API of a platform and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'platform-runtime' capability org.slf4j:slf4j-api-derived-platform:2.0.0-alpha7 declares a runtime of a component:
              - Incompatible because this component declares a platform and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'runtime' capability org.slf4j:slf4j-api:2.0.0-alpha7 declares a runtime of a component:
              - Incompatible because this component declares a library and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
   > Could not resolve jakarta.ws.rs:jakarta.ws.rs-api:3.1.0.
     Required by:
         project :
      > No matching variant of jakarta.ws.rs:jakarta.ws.rs-api:3.1.0 was found. The consumer was configured to find a runtime of sources, as well as attribute 'org.gradle.docselements' with value 'sources' but:
          - Variant 'compile' capability jakarta.ws.rs:jakarta.ws.rs-api:3.1.0:
              - Incompatible because this component declares an API of a library and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'enforced-platform-compile' capability jakarta.ws.rs:jakarta.ws.rs-api-derived-enforced-platform:3.1.0:
              - Incompatible because this component declares an API of an enforced platform and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'enforced-platform-runtime' capability jakarta.ws.rs:jakarta.ws.rs-api-derived-enforced-platform:3.1.0 declares a runtime of a component:
              - Incompatible because this component declares an enforced platform and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'platform-compile' capability jakarta.ws.rs:jakarta.ws.rs-api-derived-platform:3.1.0:
              - Incompatible because this component declares an API of a platform and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'platform-runtime' capability jakarta.ws.rs:jakarta.ws.rs-api-derived-platform:3.1.0 declares a runtime of a component:
              - Incompatible because this component declares a platform and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'runtime' capability jakarta.ws.rs:jakarta.ws.rs-api:3.1.0 declares a runtime of a component:
              - Incompatible because this component declares a library and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
   > Could not resolve jakarta.annotation:jakarta.annotation-api:2.1.0.
     Required by:
         project :
      > No matching variant of jakarta.annotation:jakarta.annotation-api:2.1.0 was found. The consumer was configured to find a runtime of sources, as well as attribute 'org.gradle.docselements' with value 'sources' but:
          - Variant 'compile' capability jakarta.annotation:jakarta.annotation-api:2.1.0:
              - Incompatible because this component declares an API of a library and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'enforced-platform-compile' capability jakarta.annotation:jakarta.annotation-api-derived-enforced-platform:2.1.0:
              - Incompatible because this component declares an API of an enforced platform and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'enforced-platform-runtime' capability jakarta.annotation:jakarta.annotation-api-derived-enforced-platform:2.1.0 declares a runtime of a component:
              - Incompatible because this component declares an enforced platform and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'platform-compile' capability jakarta.annotation:jakarta.annotation-api-derived-platform:2.1.0:
              - Incompatible because this component declares an API of a platform and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'platform-runtime' capability jakarta.annotation:jakarta.annotation-api-derived-platform:2.1.0 declares a runtime of a component:
              - Incompatible because this component declares a platform and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'runtime' capability jakarta.annotation:jakarta.annotation-api:2.1.0 declares a runtime of a component:
              - Incompatible because this component declares a library and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
   > Could not resolve jakarta.xml.bind:jakarta.xml.bind-api:3.0.1.
     Required by:
         project :
      > No matching variant of jakarta.xml.bind:jakarta.xml.bind-api:3.0.1 was found. The consumer was configured to find a runtime of sources, as well as attribute 'org.gradle.docselements' with value 'sources' but:
          - Variant 'compile' capability jakarta.xml.bind:jakarta.xml.bind-api:3.0.1:
              - Incompatible because this component declares an API of a library and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'enforced-platform-compile' capability jakarta.xml.bind:jakarta.xml.bind-api-derived-enforced-platform:3.0.1:
              - Incompatible because this component declares an API of an enforced platform and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'enforced-platform-runtime' capability jakarta.xml.bind:jakarta.xml.bind-api-derived-enforced-platform:3.0.1 declares a runtime of a component:
              - Incompatible because this component declares an enforced platform and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'platform-compile' capability jakarta.xml.bind:jakarta.xml.bind-api-derived-platform:3.0.1:
              - Incompatible because this component declares an API of a platform and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'platform-runtime' capability jakarta.xml.bind:jakarta.xml.bind-api-derived-platform:3.0.1 declares a runtime of a component:
              - Incompatible because this component declares a platform and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'runtime' capability jakarta.xml.bind:jakarta.xml.bind-api:3.0.1 declares a runtime of a component:
              - Incompatible because this component declares a library and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
   > Could not resolve org.eclipse.jetty:jetty-server:11.0.9.
     Required by:
         project :
      > No matching variant of org.eclipse.jetty:jetty-server:11.0.9 was found. The consumer was configured to find a runtime of sources, as well as attribute 'org.gradle.docselements' with value 'sources' but:
          - Variant 'compile' capability org.eclipse.jetty:jetty-server:11.0.9:
              - Incompatible because this component declares an API of a library and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'enforced-platform-compile' capability org.eclipse.jetty:jetty-server-derived-enforced-platform:11.0.9:
              - Incompatible because this component declares an API of an enforced platform and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'enforced-platform-runtime' capability org.eclipse.jetty:jetty-server-derived-enforced-platform:11.0.9 declares a runtime of a component:
              - Incompatible because this component declares an enforced platform and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'platform-compile' capability org.eclipse.jetty:jetty-server-derived-platform:11.0.9:
              - Incompatible because this component declares an API of a platform and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'platform-runtime' capability org.eclipse.jetty:jetty-server-derived-platform:11.0.9 declares a runtime of a component:
              - Incompatible because this component declares a platform and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'runtime' capability org.eclipse.jetty:jetty-server:11.0.9 declares a runtime of a component:
              - Incompatible because this component declares a library and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
   > Could not resolve org.eclipse.jetty:jetty-webapp:11.0.9.
     Required by:
         project :
      > No matching variant of org.eclipse.jetty:jetty-webapp:11.0.9 was found. The consumer was configured to find a runtime of sources, as well as attribute 'org.gradle.docselements' with value 'sources' but:
          - Variant 'compile' capability org.eclipse.jetty:jetty-webapp:11.0.9:
              - Incompatible because this component declares an API of a library and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'enforced-platform-compile' capability org.eclipse.jetty:jetty-webapp-derived-enforced-platform:11.0.9:
              - Incompatible because this component declares an API of an enforced platform and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'enforced-platform-runtime' capability org.eclipse.jetty:jetty-webapp-derived-enforced-platform:11.0.9 declares a runtime of a component:
              - Incompatible because this component declares an enforced platform and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'platform-compile' capability org.eclipse.jetty:jetty-webapp-derived-platform:11.0.9:
              - Incompatible because this component declares an API of a platform and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'platform-runtime' capability org.eclipse.jetty:jetty-webapp-derived-platform:11.0.9 declares a runtime of a component:
              - Incompatible because this component declares a platform and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'runtime' capability org.eclipse.jetty:jetty-webapp:11.0.9 declares a runtime of a component:
              - Incompatible because this component declares a library and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
   > Could not resolve org.glassfish.jersey.containers:jersey-container-servlet-core:3.1.0-M2.
     Required by:
         project :
      > No matching variant of org.glassfish.jersey.containers:jersey-container-servlet-core:3.1.0-M2 was found. The consumer was configured to find a runtime of sources, as well as attribute 'org.gradle.docselements' with value 'sources' but:
          - Variant 'compile' capability org.glassfish.jersey.containers:jersey-container-servlet-core:3.1.0-M2:
              - Incompatible because this component declares an API of a library and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'enforced-platform-compile' capability org.glassfish.jersey.containers:jersey-container-servlet-core-derived-enforced-platform:3.1.0-M2:
              - Incompatible because this component declares an API of an enforced platform and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'enforced-platform-runtime' capability org.glassfish.jersey.containers:jersey-container-servlet-core-derived-enforced-platform:3.1.0-M2 declares a runtime of a component:
              - Incompatible because this component declares an enforced platform and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'platform-compile' capability org.glassfish.jersey.containers:jersey-container-servlet-core-derived-platform:3.1.0-M2:
              - Incompatible because this component declares an API of a platform and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'platform-runtime' capability org.glassfish.jersey.containers:jersey-container-servlet-core-derived-platform:3.1.0-M2 declares a runtime of a component:
              - Incompatible because this component declares a platform and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'runtime' capability org.glassfish.jersey.containers:jersey-container-servlet-core:3.1.0-M2 declares a runtime of a component:
              - Incompatible because this component declares a library and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
   > Could not resolve com.google.guava:guava:31.1-jre.
     Required by:
         project :
      > No matching variant of com.google.guava:guava:31.1-jre was found. The consumer was configured to find a runtime of sources, as well as attribute 'org.gradle.docselements' with value 'sources' but:
          - Variant 'compile' capability com.google.guava:guava:31.1-jre:
              - Incompatible because this component declares an API of a library and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'enforced-platform-compile' capability com.google.guava:guava-derived-enforced-platform:31.1-jre:
              - Incompatible because this component declares an API of an enforced platform and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'enforced-platform-runtime' capability com.google.guava:guava-derived-enforced-platform:31.1-jre declares a runtime of a component:
              - Incompatible because this component declares an enforced platform and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'platform-compile' capability com.google.guava:guava-derived-platform:31.1-jre:
              - Incompatible because this component declares an API of a platform and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'platform-runtime' capability com.google.guava:guava-derived-platform:31.1-jre declares a runtime of a component:
              - Incompatible because this component declares a platform and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'runtime' capability com.google.guava:guava:31.1-jre declares a runtime of a component:
              - Incompatible because this component declares a library and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
   > Could not resolve edu.ucar:cdm-core:5.4.2.
     Required by:
         project :
      > No matching variant of edu.ucar:cdm-core:5.4.2 was found. The consumer was configured to find a runtime of sources, as well as attribute 'org.gradle.docselements' with value 'sources' but:
          - Variant 'compile' capability edu.ucar:cdm-core:5.4.2:
              - Incompatible because this component declares an API of a library and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'enforced-platform-compile' capability edu.ucar:cdm-core-derived-enforced-platform:5.4.2:
              - Incompatible because this component declares an API of an enforced platform and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'enforced-platform-runtime' capability edu.ucar:cdm-core-derived-enforced-platform:5.4.2 declares a runtime of a component:
              - Incompatible because this component declares an enforced platform and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'platform-compile' capability edu.ucar:cdm-core-derived-platform:5.4.2:
              - Incompatible because this component declares an API of a platform and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'platform-runtime' capability edu.ucar:cdm-core-derived-platform:5.4.2 declares a runtime of a component:
              - Incompatible because this component declares a platform and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'runtime' capability edu.ucar:cdm-core:5.4.2 declares a runtime of a component:
              - Incompatible because this component declares a library and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
   > Could not resolve org.apache.commons:commons-math3:3.6.1.
     Required by:
         project :
      > No matching variant of org.apache.commons:commons-math3:3.6.1 was found. The consumer was configured to find a runtime of sources, as well as attribute 'org.gradle.docselements' with value 'sources' but:
          - Variant 'compile' capability org.apache.commons:commons-math3:3.6.1:
              - Incompatible because this component declares an API of a library and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'enforced-platform-compile' capability org.apache.commons:commons-math3-derived-enforced-platform:3.6.1:
              - Incompatible because this component declares an API of an enforced platform and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'enforced-platform-runtime' capability org.apache.commons:commons-math3-derived-enforced-platform:3.6.1 declares a runtime of a component:
              - Incompatible because this component declares an enforced platform and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'platform-compile' capability org.apache.commons:commons-math3-derived-platform:3.6.1:
              - Incompatible because this component declares an API of a platform and the consumer needed a runtime of documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'platform-runtime' capability org.apache.commons:commons-math3-derived-platform:3.6.1 declares a runtime of a component:
              - Incompatible because this component declares a platform and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)
          - Variant 'runtime' capability org.apache.commons:commons-math3:3.6.1 declares a runtime of a component:
              - Incompatible because this component declares a library and the consumer needed documentation
              - Other compatible attributes:
                  - Doesn't say anything about org.gradle.docselements (required 'sources')
                  - Doesn't say anything about the documentation type (required sources)

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 5s
30 actionable tasks: 4 executed, 26 up-to-date

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-28T23:07:10Z


It looks like the @JavaDoc@ command is conscious of modules, etc., so perhaps it has the ability to make an aggregated view starting with the top module.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-28T23:15:06Z


And javadoc needs the @module-info.java@ or else it complains. If I take the @wres-worker@ @build/tmp/javadoc/javadoc.options@ and pass those args to @JavaDoc@, no problem, but if I remove the @module-info.java@ from the list of sources to that same command, it complains.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-29T17:11:57Z


What are the next jars to modularize?

[wres]$ du -h --max-depth=0 wres-*
16K     wres-broker
1.6M	wres-config
3.9M	wres-datamodel
928K	wres-events
156K	wres-eventsbroker
28K	wres-external-services-tests
176K	wres-grid
15M	wres-io
548K	wres-messages
4.0M	wres-metrics
100K	wres-redis
2.9M	wres-statistics
400K	wres-system
536K	wres-tasker
322M	wres-thredds-facade
236K	wres-util
904K	wres-vis
196K	wres-worker

Or

[wres]$ du -h -k --max-depth=0 wres-* | sort -n
16	wres-broker
28	wres-external-services-tests
100	wres-redis
156	wres-eventsbroker
176	wres-grid
196	wres-worker
236	wres-util
400	wres-system
536	wres-tasker
548	wres-messages
904	wres-vis
928	wres-events
1552	wres-config
2884	wres-statistics
3992	wres-datamodel
4020	wres-metrics
15084	wres-io
329204	wres-thredds-facade

@wres-grid@, @wres-system@, @wres-util@ look like decent candidates based on size and probably the dep tree too.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-29T17:16:16Z


@wres-util@ depends on @wres-datamodel@.
@wres-system@ depends on @wres-util@ (and therefore transitively @wres-datamodel@).
@wres-grid@ depends on @wres-config@, @wres-util@, @wres-system@, and @wres-datamodel@.

@wres-datamodel@ depends on @wres-config@ and @wres-statistics@. Wait, what? Why does @wres-datamodel@ depend on @wres-statistics@??

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-29T17:18:35Z


Ah. @wres-statistics@ has all the data model for statistics, i.e. protobuf descriptions, etc., and then @wres-datamodel@ uses those.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-29T17:22:15Z


@wres-statistics@ depends on @wres-config@.

Or as gradle puts it:

runtimeClasspath - Runtime classpath of source set 'main'.
+--- project :wres-system
|    +--- project :wres-util
|    |    +--- project :wres-datamodel
|    |    |    +--- project :wres-statistics
...
|    |    |    |    +--- project :wres-config

So the natural order would be:

  1. wres-config
  2. wres-statistics
  3. wres-datamodel
  4. wres-util
  5. wres-system

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: James (James)
Original Date: 2022-04-29T17:35:39Z


@wres-statistics@ depends on @wres-config@? Will have to take a closer look at that. It shouldn't, as I recall. It is basically a bunch of generated classes (java bindings for protobufs), plus one tiny utility class.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: James (James)
Original Date: 2022-04-29T17:42:38Z


Yeah, clean-up on aisle @wres-statistics@. I guess there was more in there at some point.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: James (James)
Original Date: 2022-04-29T17:49:08Z


commit:wres|fde40c13c9e6a433a1a5c016be7bb9da8cd927c2.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: James (James)
Original Date: 2022-04-29T17:58:11Z


> Task :wres-statistics:dependencies

------------------------------------------------------------
Project ':wres-statistics'
------------------------------------------------------------
.
.
.
runtimeClasspath - Runtime classpath of source set 'main'.
\--- com.google.protobuf:protobuf-java:3.20.1

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-29T18:07:27Z


And right away, we find that @wres-config@ has the most baggage of any of 'em, XML and jaxb, xjc, and the lot.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-29T18:08:41Z


Oh, nice. That means @wres-statistics@ can be modularized easily.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-04-29T19:58:10Z


Customer issue #104204 and associated issue #104251

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-05-02T16:22:18Z


commit:eb11e4b5a8f1af2f86b2490a5064b24285c43459 makes @wres-statistics@ a JPMS module.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-05-02T19:22:27Z


@wres-config@ is not as straightforward and it seems related to all these old jaxb2 dependencies.

But it looks like progress is happening toward use of the jakarta namespace, e.g. highsource/jaxb2-basics#134

2022/04/26 update:

v0.13.1 has been released. Moving forward to v2.3.x and v3.x (jakarta support). Please open GitHub issues moving forward.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: James (James)
Original Date: 2022-05-04T12:33:38Z


I get these warnings when running in the IDE. I am not bothered, because they are warnings (edit: and don't lead to errors that prevent success) and I don't see them when running normally. Still, reporting here.

WARNING: Unknown module: wres.statistics specified to --patch-module
WARNING: Unknown module: wres.statistics specified to --add-reads

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-05-04T13:47:01Z


Good to know.

It has been so long since I have tried running within IntelliJ IDEA that it looks like my old configs won't run.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-05-04T13:56:30Z


I was able to run scenario505 after some finagling. But that was with IntelliJ IDEA 2021.3.2. I'm updating now.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-05-04T16:12:27Z


I can't find that message (@warning: Unknown module: wres.statistics specified to --patch-module@) locally, is it when you build or run? I cannot easily display the background build task when running either, so is it showing up there?

I have @IntelliJ IDEA 2021.3.3 (Community Edition)@ using @runtime version: 11.0.15+10-LTS amd64@ @vm: OpenJDK 64-Bit Server VM by Azul Systems, Inc.@ on GNU/Linux.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-05-04T16:23:00Z


Maybe a @clean@ and then @installDist@? Does it still show up then?

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: James (James)
Original Date: 2022-05-04T16:30:55Z


No, build is fine, this is when I run. I wouldn't sweat it, there is no issue when I run the app using the run script, so it is unlikely to be our software.

I cleaned, yes. I can probably track it down, but I just have zero motivation to do so (vs. other things) because nothing is broken.

edit: in other words, I wasn't posting for help - although I appreciate the suggestions - more as a record of an observation.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: Jesse (Jesse)
Original Date: 2022-05-04T19:54:48Z


Fair enough.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: James (James)
Original Date: 2022-05-20T12:02:13Z


Noting again that this work broke the @aggregateJavadocs@ task, which means that we do not currently have aggregated javadocs associated with a build.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: James (James)
Original Date: 2022-05-20T12:16:07Z


James wrote:

Noting again that this work broke the @aggregateJavadocs@ task, which means that we do not currently have aggregated javadocs associated with a build.

@io.freefair.aggregate-javadoc@ looks like a good option, but only when we upgrade to gradle 7.4.2 or later:

https://docs.freefair.io/gradle-plugins/current/reference/#_system_requirements

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: James (James)
Original Date: 2023-01-12T11:51:41Z


See #62732-80. Worth a try in due course. It would be nice to bring back our aggregated docs.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: James (James)
Original Date: 2023-01-12T12:06:13Z


James wrote:

See #62732-80. Worth a try in due course. It would be nice to bring back our aggregated docs.

Although this is a cause for pessimism:

freefair/gradle-plugins#409

We'll see. Should probably break into a separate ticket.

@epag
Copy link
Collaborator Author

epag commented Aug 21, 2024


Original Redmine Comment
Author Name: James (James)
Original Date: 2023-01-12T15:02:18Z


Broken out the javadoc issue, back to the backlog for this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant