{"id":36698450,"url":"https://github.com/moditect/layrry","last_synced_at":"2026-01-12T11:35:54.146Z","repository":{"id":37970047,"uuid":"245613071","full_name":"moditect/layrry","owner":"moditect","description":"A Runner and API for Layered Java Applications","archived":false,"fork":false,"pushed_at":"2023-07-17T11:54:18.000Z","size":3072,"stargazers_count":345,"open_issues_count":37,"forks_count":33,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-07-13T06:25:27.851Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/moditect.png","metadata":{"files":{"readme":"README.adoc","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-03-07T10:34:46.000Z","updated_at":"2025-07-07T04:41:29.000Z","dependencies_parsed_at":"2023-02-19T06:46:04.379Z","dependency_job_id":null,"html_url":"https://github.com/moditect/layrry","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/moditect/layrry","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moditect%2Flayrry","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moditect%2Flayrry/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moditect%2Flayrry/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moditect%2Flayrry/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/moditect","download_url":"https://codeload.github.com/moditect/layrry/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moditect%2Flayrry/sbom","scorecard":{"id":656032,"data":{"date":"2025-08-11","repo":{"name":"github.com/moditect/layrry","commit":"5d2e8294f2f9d0b1f74f53ed1057453b5d909ee5"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.7,"checks":[{"name":"Code-Review","score":0,"reason":"Found 1/24 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/build.yml:1","Warn: no topLevel permission defined: .github/workflows/early-access.yml:1","Warn: no topLevel permission defined: .github/workflows/release.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":9,"reason":"binaries present in source code","details":["Warn: binary detected: .mvn/wrapper/maven-wrapper.jar:1"],"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build.yml:31: update your workflow using https://app.stepsecurity.io/secureworkflow/moditect/layrry/build.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build.yml:34: update your workflow using https://app.stepsecurity.io/secureworkflow/moditect/layrry/build.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/early-access.yml:36: update your workflow using https://app.stepsecurity.io/secureworkflow/moditect/layrry/early-access.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/early-access.yml:39: update your workflow using https://app.stepsecurity.io/secureworkflow/moditect/layrry/early-access.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/early-access.yml:44: update your workflow using https://app.stepsecurity.io/secureworkflow/moditect/layrry/early-access.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/early-access.yml:64: update your workflow using https://app.stepsecurity.io/secureworkflow/moditect/layrry/early-access.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/early-access.yml:69: update your workflow using https://app.stepsecurity.io/secureworkflow/moditect/layrry/early-access.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/early-access.yml:93: update your workflow using https://app.stepsecurity.io/secureworkflow/moditect/layrry/early-access.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:39: update your workflow using https://app.stepsecurity.io/secureworkflow/moditect/layrry/release.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:44: update your workflow using https://app.stepsecurity.io/secureworkflow/moditect/layrry/release.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:103: update your workflow using https://app.stepsecurity.io/secureworkflow/moditect/layrry/release.yml/master?enable=pin","Info:   0 out of  10 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.txt:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE.txt:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":4,"reason":"2 out of the last 4 releases have a total of 2 signed artifacts.","details":["Info: signed release artifact: checksums_sha256.txt.asc: https://github.com/moditect/layrry/releases/tag/v1.0.0.Final","Info: signed release artifact: checksums_sha256.txt.asc: https://github.com/moditect/layrry/releases/tag/early-access","Warn: release artifact v1.0.0.Alpha2 not signed: https://api.github.com/repos/moditect/layrry/releases/81598003","Warn: release artifact v1.0.0.Alpha1 not signed: https://api.github.com/repos/moditect/layrry/releases/37111016","Warn: release artifact v1.0.0.Final does not have provenance: https://api.github.com/repos/moditect/layrry/releases/101695292","Warn: release artifact early-access does not have provenance: https://api.github.com/repos/moditect/layrry/releases/101694984","Warn: release artifact v1.0.0.Alpha2 does not have provenance: https://api.github.com/repos/moditect/layrry/releases/81598003","Warn: release artifact v1.0.0.Alpha1 does not have provenance: https://api.github.com/repos/moditect/layrry/releases/37111016"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 10 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-21T14:39:08.138Z","repository_id":37970047,"created_at":"2025-08-21T14:39:08.138Z","updated_at":"2025-08-21T14:39:08.138Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28338971,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T10:58:46.209Z","status":"ssl_error","status_checked_at":"2026-01-12T10:58:42.742Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-12T11:35:53.440Z","updated_at":"2026-01-12T11:35:54.138Z","avatar_url":"https://github.com/moditect.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"= Layrry - A Launcher and API for Modularized Java Applications\n:linkattrs:\n:project-owner:   moditect\n:project-name:    layrry\n:project-group:   org.moditect.layrry\n:project-version: 1.0.0.Final\n\nimage:https://github.com/{project-owner}/{project-name}/workflows/Build/badge.svg[\"Build Status\", link=\"https://github.com/{project-owner}/{project-name}/actions\"]\nimage:https://img.shields.io/maven-central/v/{project-group}/{project-name}-core.svg[Download, link=\"https://search.maven.org/#search|ga|1|{project-group}\"]\n\n_Latest version: {project-version}_\n\nhttp://andresalmiray.com/layrry-1-0-0-alpha1-has-been-released/[1.0.0.Alpha1 announcement]\n\nLayrry is a launcher and Java API for executing modularized Java applications.\n\nIt allows to assemble modularized applications based on Maven artifact coordinates of the (modular) JARs to include.\nLayrry utilizes the Java Module System's notion of link:https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ModuleLayer.html[module layers],\nallowing multiple versions of one module to be used within an application at the same time, as well as dynamically adding\nand removing modules at application runtime.\n\nThe module graph is built either declaratively (using YAML or TOML descriptors) or programmatically (using a fluent API).\n\nLearn more about Layrry in these blog posts:\n\n* link:https://www.morling.dev/blog/introducing-layrry-runner-and-api-for-modularized-java-applications/[Introducing Layrry: A Launcher and API for Modularized Java Applications]\n* link:https://www.morling.dev/blog/plugin-architectures-with-layrry-and-the-java-module-system/[Plug-in Architectures With Layrry and the Java Module System]\n* link:https://www.morling.dev/blog/class-unloading-in-layered-java-applications/[Class Unloading in Layered Java Applications]\n* link:http://andresalmiray.com/building-a-layered-modular-java-application-watch-out-for-these/[Building a layered modular Java application? Watch out for these!]\n\nLayrry also was presented at different (online) conferences and meet-ups, for example at vJUG (https://speakerdeck.com/gunnarmorling/plug-in-architectures-with-layrry-and-the-java-module-system-vjug[slides], https://www.youtube.com/watch?v=iJyys_LgG-U[recording]).\n\n== Why Layrry?\n\nThe Java Module System doesn't define any means of mapping between modules (e.g. _com.acme.crm_) and JARs providing such module\n(e.g. _acme-crm-1.0.0.Final.jar_) or retrieving modules from remote repositories using unique identifiers\n(e.g. _com.acme:acme-crm:1.0.0.Final_). Instead, it's the responsibility of the user to obtain all required JARs of a modularized\napplication and provide them via `--module-path`.\n\nFurthermore, the module system doesn't define any means of module versioning; i.e. it's the responsibility of the user to\nobtain all modules in the right version. Using the `--module-path` option, it's not possible, though, to assemble an\napplication that uses multiple versions of one and the same module. This may be desirable for transitive dependencies of\nan application, which might be required in different versions by two separate direct dependencies.\n\nThis is where Layrry comes in: utilizing the notion of module layers, it provides a declarative approach as well as an API\nfor assembling modularized applications, organized in module layers. The JARs to be included are described using Maven GAV\n(group id, artifact id, version) coordinates, solving the issue of retrieving all required JARs in the right version.\n\nModule layers allow to use different versions of one and the same module in different layers of an application (as long as\nthey are not exposed in a conflicting way on module API boundaries).\n\nModule layers and thus Layrry also allow application extensions to be added and removed dynamically at runtime. Here's\nlink:https://github.com/moditect/layrry-examples/tree/master/modular-tiles[an example] for using the Layrry plug-in API\nto dynamically modify a JavaFX application:\n\nimage:images/javafx-layrry.gif[JavaFX app based on Layrry]\n\n== Using the Layrry Launcher\n\nThe Layrry Launcher is a CLI tool which takes a configuration of a layered application and executes it. It's used like so:\n\n[source]\n[subs=\"attributes\"]\n----\nlayrry-launcher-{project-version}-all.jar --layers-config \u003cpath/to/layers.yml\u003e [program arguments]\n----\n\nE.g. like so:\n\n[source]\n[subs=\"attributes\"]\n----\nlayrry-launcher-{project-version}-all.jar --layers-config hello-world.yml Alice Bob\n----\n\nThe application layers configuration file is a YAML file which the following structure:\n\n[source,yaml]\n----\nlayers:\n  \u003cname 1\u003e:\n    modules:\n      - \"G:A:V\"\n      - \"G:A:V\"\n      - ...\n  \u003cname 2\u003e:\n    parents:\n      - \"\u003cname 1\u003e\"\n    modules:\n      - ...\n      - ...\n  \u003cname 3\u003e:\n    parents:\n      - \"\u003cname 2\"\n    directory: \"relative/path/to/directory/of/layer/directories\n\nmain:\n  module: \u003cmain module\u003e\n  class: \u003cmain class\u003e\n----\n\nEach layer comprises:\n\n* A unique name\n* The list of parent layers\n* The list of contained modules given via Maven GAV coordinates OR\n* A directory which contains one or more sub-directories, each of which represent one layer made up of the modular JARs \nwithin that sub-directory; the directory path is resolved relatively to the location of the _layrry.yml_ file. Alternatively\nthe directory may be an absolute path however *be very careful* as this may cause a non portable configuration.\n\nAs an example, consider the following application whose modules `foo` and `bar` depend on two different versions of the `greeter` module:\n\nimage:images/example.png[Layrry Example]\n\nRunning this application wouldn't be possible with the default module path, which only allows for one version of a given\nmodule. Here is how the application can be executed via Layrry, organizing all the modules in multiple layers:\n\n[source,yaml]\n----\nlayers:\n  log:\n    modules:\n      - \"org.apache.logging.log4j:log4j-api:2.20.0\"\n      - \"org.apache.logging.log4j:log4j-core:2.20.0\"\n      - \"com.example:logconfig:1.0.0\"\n  foo:\n    parents:\n      - \"log\"\n    modules:\n      - \"com.example:greeter:1.0.0\"\n      - \"com.example:foo:1.0.0\"\n  bar:\n    parents:\n      - \"log\"\n    modules:\n      - \"com.example:greeter:2.0.0\"\n      - \"com.example:bar:1.0.0\"\n  app:\n    parents:\n      - \"foo\"\n      - \"bar\"\n    modules:\n      - \"com.example:app:1.0.0\"\nmain:\n  module: com.example.app\n  class: com.example.app.App\n----\n\nAlternatively you may use TOML instead of YAML\n\n[source,toml]\n----\n[layers.log]\n  modules = [\n    \"org.apache.logging.log4j:log4j-api:2.20.0\",\n    \"org.apache.logging.log4j:log4j-core:2.20.0\",\n    \"com.example.it:it-logconfig:1.0.0\"]\n[layers.foo]\n  parents = [\"log\"]\n  modules = [\n    \"com.example.it:it-greeter:1.0.0\",\n    \"com.example.it:it-foo:1.0.0\"]\n[layers.bar]\n  parents = [\"log\"]\n  modules = [\n    \"com.example.it:it-greeter:2.0.0\",\n    \"com.example.it:it-bar:1.0.0\"]\n[layers.app]\n  parents = [\"foo\", \"bar\"]\n  modules = [\"com.example.it:it-app:1.0.0\"]\n[main]\n  module = \"com.example.app\"\n  class = \"com.example.app.App\"\n----\n\nBe sure to use `.toml` as file extension to let Layrry know which format should be parsed.\n\nYou can find the complete example in the tests of the Layrry project.\n\nThe Layrry Launcher accepts the following arguments:\n\n * --basedir: The base directory from which plugin directories will be resolved. Layrry will use the parent directory of \n the layers config file if this value is not set.\n * --layers-config: Path to the layers config file. The file must use any of the supported config formats. REQUIRED.\n * --properties: Path to additional properties in Java `.properties` format. These properties will be used to replace value\n placeholders found in the layers config file. OPTIONAL.\n\n== Using JBang\n\nlink:https://github.com/jbangdev/jbang[JBang] can launch self contained Java sources, JShell scripts, JARs. jbang has a feature\nthat allows you to try out Layrry without having to install or build Layrry yourself. You only need a JDK (11+ is preferred)\nand jbang installed. Once you do, you may invoke the previous example with\n\n[source]\n----\njbang layrry@moditect --layers-config layers.yml\n----\n\nJBang will resolve and download the appropriate Layrry bootstrap binary, then Layrry resolves the modules described in\nthe input configuration file, finally the application is launched.\n\n== Dynamic Plug-Ins\n\nLayrry also supports the dynamic addition and removal of plug-ins at runtime. For that, simply add or remove plug-in\nsub-directories to the `directory` of a layer configuration. Layrry watches the given plug-ins directory and will add or\nremove the corresponding module layer to/from the application in case a new plug-in is added or removed. The core of an\napplication can react to added or removed module layers. In order to do so, the module _org.moditect.layrry:layrry-platform_\nmust be added to the application core layer and an implementation of the `PluginLifecycleListener` interface must be\ncreated and registered as service:\n\n[source]\n----\npublic interface PluginLifecycleListener {\n    void pluginAdded(PluginDescriptor plugin);\n\n    void pluginRemoved(PluginDescriptor plugin);\n}\n----\n\nTypically, an application will retrieve application-specific services from newly added module layers:\n\n[source,java]\n----\n@Override\npublic void pluginAdded(PluginDescriptor plugin) {\n  ServiceLoader\u003cMyService\u003e services = ServiceLoader.load(\n      plugin.getModuleLayer(), MyService.class);\n\n    services.forEach(service -\u003e {\n      // only process services declared by the added layer itself, but not\n      // from ancestor layers\n      if (service.getClass().getModule().getLayer() == layer) {\n        // process service ...\n      }\n    });\n}\n----\n\nTo avoid class-loader leaks, it's vital that all references to plug-in contributed classes are released upon `pluginRemoved()`.\nNote that classes typically will not instantly be unloaded, but only upon the next full GC (when using G1).\n\nYou can find a complete example for the usage of dynamic plug-ins in the _vertx-example_ directory: \"Layrry Links\" is an\nexample application for managing golf courses, centered around a web application core built using Vert.x. Routes of the\nweb application (_/members_, _/tournaments_) are contributed by plug-ins which can be added to or removed from the\napplication at runtime. The _routes_ path shows all routes available at a given time.\n\nPlugins may be packaged in 3 ways:\n\n1. As a single JAR file. No nested JARs are allowed.\n2. As a Zip file. Multiple JARs may be packaged.\n3. As a Tar(.gz) file. Multiple JARs may be packaged.\n\nFor Zip and Tar packages, the use of a root entry matching the name of containing file is permited, however it's preferred\nif said root entry were omitted. Some examples:\n\n[source]\n.Single JAR\n----\nplugin-1.0.jar\n |- com\n |- com/acme\n |- com/acme/Plugin.class\n \\- module-info.class\n----\n\n[source]\n.Plain Zip (or Tar)\n----\nplugin-1.0.zip\n |- plugin-1.0.jar\n |- dependency-foo-1.0.0.jar\n \\- dependency-bar-1.0.0.jar\n----\n\n[source]\n.Root Zip (or Tar)\n----\nplugin-1.0.zip\n |- plugin-1.0\n |- plugin-1.0/plugin-1.0.jar\n |- plugin-1.0/dependency-foo-1.0.0.jar\n \\- plugin-1.0/dependency-bar-1.0.0.jar\n----\n\n== Parameterized Layer Configuration\n\nLayrry supports the link:https://github.com/spullara/mustache.java[Mustache] template syntax, enabling parameterization of\nthe content found in configuration files, regardless of their target format (YAML, TOML, etc). To use this feature you must\nuse a `{{property}}` expression to refer to value placeholders. Layrry makes all `System` properties available for value\nreplacement, as well as an extra set of properties that are related to OS values; these include all properties exposed by\nthe link:https://github.com/trustin/os-maven-plugin/[os-maven-plugin]. If the `--properties` command flag is passed to the\nLayrry Launcher then all properties found in the given properties file will also become available.\n\nAdditionally, Layrry resolves the following properties\n\n * `os.detected.jfxname`: specific to JavaFX. Values may be one of `linux`, `win`, `mac`.\n * `os.detected.lwjglname`: specific to LWJGL. Values may be one of `linux`, `linux-arm32`, `windows`, `windows-x86`, `macosx`.\n\nThe following example shows a parameterized TOML config file for a JavaFX application that can be run on any of the 3 platforms\nsupported by JavaFX\n\n[source,toml]\n----\n.layers.toml\n[layers.javafx]\n    modules = [\n        \"org.openjfx:javafx-base:jar:{{os.detected.jfxname}}:{{javafx_version}}\",\n        \"org.openjfx:javafx-controls:jar:{{os.detected.jfxname}}:{{javafx_version}}\",\n        \"org.openjfx:javafx-graphics:jar:{{os.detected.jfxname}}:{{javafx_version}}\",\n        \"org.openjfx:javafx-web:jar:{{os.detected.jfxname}}:{{javafx_version}}\",\n        \"org.openjfx:javafx-media:jar:{{os.detected.jfxname}}:{{javafx_version}}\"]\n[layers.core]\n    modules = [\n        \"org.kordamp.tiles:modular-tiles-model:{{project_version}}\",\n        \"org.kordamp.tiles:modular-tiles-core:{{project_version}}\",\n        \"org.kordamp.tiles:modular-tiles-app:{{project_version}}\",\n        \"org.moditect.layrry:layrry-platform:{{layrry_version}}\",\n        \"eu.hansolo:tilesfx:{{tilesfx_version}}\"]\n    parents = [\"javafx\"]\n[layers.plugins]\n    parents = [\"core\"]\n    directory = \"plugins\"\n[main]\n  module = \"org.kordamp.tiles.app\"\n  class = \"org.kordamp.tiles.app.Main\"\n----\n\n[source,java]\n[subs=\"attributes\"]\n.versions.properties\n----\nproject_version = 1.0.0\njavafx_version = 11.0.2\ntilesfx_version = 11.44\nlayrry_version = {project-version}\n----\n\nThis application can be launched as\n\n[source]\n[subs=\"attributes\"]\n----\nlayrry-launcher-{project-version}-all.jar --layers-config layers.toml --properties versions.properties\n----\n\n== Remote Configuration\n\nLayrry supports loading external configuration files (inputs to `--layers-config` and `--properties`) both from local and\nremote sources. For example, the previous `layers.toml` and `versions.properties` files could be accessed from a remote server\nthat exposes those resources via HTTPS, such as\n\n[source]\n[subs=\"attributes\"]\n----\nlayrry-launcher-{project-version}-all.jar \\\n  --basedir /home/user/joe \\\n  --layers-config https://server:port/path/to/layers.toml \\\n  --properties https://server:port/path/to/versions.properties\n----\n\nIt's important to note that setting the `--basedir` config flag is more important when remote layer configuration is in use,\nas that ensures plugin directories will be resolved from the same location, otherwise the basedir location will be inferred\nas `System.getProperty(\"user.dir\")` which may produce unexpected results when invoked from different locations.\n\nPlugin directories are always local, even if defined in remote layer configuration files. You may mix remote and local\nresources as you deem necessary, that is, the following combinations are valid:\n\n[source]\n[subs=\"attributes\"]\n.All remote\n----\nlayrry-launcher-{project-version}-all.jar \\\n  --basedir /home/user/joe \\\n  --layers-config https://server:port/path/to/layers.toml \\\n  --properties https://server:port/path/to/versions.properties\n----\n\n[source]\n[subs=\"attributes\"]\n.All local\n----\nlayrry-launcher-{project-version}-all.jar \\\n  --basedir /home/user/joe \\\n  --layers-config layers.toml \\\n  --properties versions.properties\n----\n\n[source]\n[subs=\"attributes\"]\n.Mixed\n----\nlayrry-launcher-{project-version}-all.jar \\\n  --basedir /home/user/joe \\\n  --layers-config https://server:port/path/to/layers.toml \\\n  --properties versions.properties\n----\n\n[source]\n[subs=\"attributes\"]\n----\nlayrry-launcher-{project-version}-all.jar \\\n  --basedir /home/user/joe \\\n  --layers-config layers.toml \\\n  --properties https://server:port/path/to/versions.properties\n----\n\n=== Proxy Configuration\n\nYou may need to configure a proxy when using the remote configuration feature. The following properties may be used to\nconfigure a proxy:\n\n[options=\"header\"]\n|===\n| Key                 | Description\n| use.proxy           | Whether to use any proxy or not. Defaults to `false`.\n| http.proxy          | Whether to use HTTP proxy or not. Defaults to `false`.\n| http.proxyHost      | Defaults to empty String.\n| http.proxyport      | Defaults to `80`.\n| http.proxyUser      | Defaults to empty String.\n| http.proxyPassword  | Defaults to empty String.\n| http.nonProxyHosts  | Defaults to `localhost\\|127.*\\|[::1]`.\n| https.proxy         | Whether to use HTTPS proxy or not. Defaults to `false`.\n| https.proxyHost     | Defaults to empty String.\n| https.proxyport     | Defaults to `443`.\n| https.proxyUser     | Defaults to empty String.\n| https.proxyPassword | Defaults to empty String.\n| socks.proxy         | Whether to use SOCKS proxy or not. Defaults to `false`.\n| socksProxyHost      | Defaults to empty String.\n| socksProxyPort      | Defaults to `1080`.\n| socks.proxyUser     | Defaults to empty String.\n| socks.proxyPassword | Defaults to empty String.\n|===\n\nThese properties may be set as `System` properties by passing `-Dkey=value` as part of command line arguments when using\nthe launcher, or as part of the additional properties file if `--properties` is given as an argument to the launcher.\n\n== Using the Layrry API\n\nIn addition to the YAML-based/TOML-based launcher, Layrry provides also a Java API for assembling and running layered applications.\nThis can be used in cases where the structure of layers is only known at runtime, or for implementing plug-in architectures.\n\nIn order to use Layrry programmatically, add the following dependency to your _pom.xml_:\n\n[source,xml]\n[subs=\"attributes,verbatim\"]\n----\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.moditect.layrry\u003c/groupId\u003e\n    \u003cartifactId\u003elayrry\u003c/artifactId\u003e\n    \u003cversion\u003e{project-version}\u003c/version\u003e\n\u003c/dependency\u003e\n----\n\nThen, the Layrry Java API can be used like this (showing the same example as above):\n\n[source,java]\n----\nLayers layers = Layers.builder()\n    .layer(\"log\")\n        .withModule(\"org.apache.logging.log4j:log4j-api:2.20.0\")\n        .withModule(\"org.apache.logging.log4j:log4j-core:2.20.0\")\n        .withModule(\"com.example:logconfig:1.0.0\")\n    .layer(\"foo\")\n        .withParent(\"log\")\n        .withModule(\"com.example:greeter:1.0.0\")\n        .withModule(\"com.example:foo:1.0.0\")\n    .layer(\"bar\")\n        .withParent(\"log\")\n        .withModule(\"com.example:greeter:2.0.0\")\n        .withModule(\"com.example:bar:1.0.0\")\n    .layer(\"app\")\n        .withParent(\"foo\")\n        .withParent(\"bar\")\n        .withModule(\"com.example:app:1.0.0\")\n    .build();\n\nlayers.run(\"com.example.app/com.example.app.App\", \"Alice\");\n----\n\n== Configuring Artifact Resolution\n\nLayrry relies on Maven's API to resolve artifacts. By default, Maven Local, Maven Central and every other setting configured\nat `~/.m2/settings.xml` are available to Layrry. You can tweak and configure those settings by editing the `~/.m2/settings.xml`\nfile. Alternatively you may instruct Layrry to use a different configuration file, skip querying Maven Central, or stop\nall resolutions via remote repositories.\n\n=== Disable All Remote Maven Repositories\n\n[source,java]\n.Java\n----\nLayers layers = Layers.builder()\n    .resolve(Resolvers.remote().workOffline(true))\n    .layer(...)\n----\n\n[source,yaml]\n.Yaml\n----\nresolve:\n  workOffline: true\n  ...\n----\n\n[source,toml]\n.Toml\n----\n[resolve]\n  workOffline = true\n  ...\n----\n\n=== Disable All Remote and Local Maven Repositories\n\n[source,java]\n.Java\n----\nLayers layers = Layers.builder()\n    .resolve(Resolvers.remote().enabled(false))\n    .layer(...)\n----\n\n[source,yaml]\n.Yaml\n----\nresolve:\n  remote: false\n  ...\n----\n\n[source,toml]\n.Toml\n----\n[resolve]\n  remote = false\n  ...\n----\n\n=== Use Alternate Maven Settings File\n\n[source,java]\n.Java\n----\nLayers layers = Layers.builder()\n    .resolve(Resolvers.remote()\n         .fromFile(Paths.get(\"/path/to/settings.xml\")))\n    .layer(...)\n----\n\n[source,yaml]\n.Yaml\n----\nresolve:\n  fromFile: \"/path/to/settings.xml\"\n  ...\n----\n\n[source,toml]\n.Toml\n----\n[resolve]\n  fromFile = \"/path/to/settings.xml\"\n  ...\n----\n\n== Local Artifact Resolution\n\nLayrry can resolve artifacts from additional local sources. These sources must follow specific layouts for organizing artifacts.\nCurrently `flat` and `default` layouts are supported, which are provided by Maven and Gradle plugins. Local repositories will\nalways be queried first, then any remote repositories if available.\n\n=== Flat Layout\n\nThis layout organizes all artifacts in a single directory, for example\n\n[source]\n----\nrepodir\n |-- foo-1.0.0.jar\n \\-- bar-2.0.0.jar\n----\n\n=== Default Layout\n\nThis layout organizes all artifacts following the Maven coordinates conventions, for example\n\n[source]\n----\nrepodir\n  |-- com\n  |    \\-- acme\n  |        \\-- foo\n  |            \\-- 1.0.0\n  |                \\-- foo-1.0.0.jar\n  \\-- org\n       \\-- random\n           \\-- bar\n               \\-- 2.0.0\n                   \\-- bar-2.0.0.jar\n----\n\n=== Use Local Repositories\n\n[source,java]\n.Java\n----\nLayers layers = Layers.builder()\n    .resolve(Resolvers.local()\n        .withLocalRepo(\"repoName\", Paths.get(\"/path/to/repository/directory\").toAbsolutePath(), \"flat\"))\n    ...\n----\n\n[source,yaml]\n.Yaml\n----\nresolve:\n  localRepositories:\n    repoName:\n      layout: \"flat\"\n      path: \"/path/to/repository/directory\"\n----\n\n[source,toml]\n.Toml\n----\n[resolve.localRepositories.repoName]\n  layout = \"flat\"\n  path   = \"/path/to/repository/directory\"\n----\n\nThe path may be absolute as shown in the examples or relative, in which it will be resolved relative to the\nconfig file path.\n\n== Building Layrry\n\nLayrry can be built from source by running the following command\n\n[source]\n----\n$ ./mvnw install\n----\n\nJava 11 or later is needed in order to do so.\n\n== Contributing\n\nYour contributions to Layrry are very welcomed. Please open issues with your feature suggestions as well as pull requests.\nBefore working on larger pull requests, it's suggested to reach out to link:https://twitter.com/gunnarmorling[@gunnarmorling].\n\n== License\n\nLayrry is licensed under the Apache License version 2.0.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoditect%2Flayrry","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmoditect%2Flayrry","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoditect%2Flayrry/lists"}