moditect / layrry

A Runner and API for Layered Java Applications
Apache License 2.0
335 stars 33 forks source link

Support for layer tags #57

Open thomasdarimont opened 4 years ago

thomasdarimont commented 4 years ago

Layers are a way to define module sets for applications. Those module-sets are composed of a hierarchy defined by a layers-configuration file. This model fits most application types with fixed a set of dependency- and various application-modules.

However, some applications would benefit from a more flexible layer composition at startup time or runtime. One example of this might be an application that provides some plugin system, where the plugins could be simple jar modules or complete layers on their own, e.g. if they ship with their dependencies. Such an application might want to support the execution with a different set of enabled plugins or layers, depending on the configuration or an application "profile".

For use-cases like above, it would be helpful to have a tagging mechanism for layers. A tag aware layer composition facility would enable applications to compose layers based on a set of given tags dynamically. Frameworks like spring-boot support profiles, which provide a way to segregate parts of application configuration and make it available only in specific environments. The same could be applied to layers.

Tags could also help to qualify the handling of layers. Layers could be tagged as hot-deployable, read-only, or updatable to advise a layer composition system to handle some layers differently.

Another use-case for tagged layers would be environment-specific tags, e.g. windows or linux to denote that a particular layer is only available on a specific OS.

aalmiray commented 4 years ago

Alright, to begin with let's say that Layer supports a tag property that accepts List<String>. One could express that in TOML as

[layers.log]
  tags = ["logging", "log4j"]
  modules = [
    "org.apache.logging.log4j:log4j-api:jar:2.13.1",
    "org.apache.logging.log4j:log4j-core:jar:2.13.1",
    "com.example.it:it-logconfig:1.0.0"]

Which says the log layer is used for logging and requires log4j.

There could be another layer definition such as

[layers.log2]
  tags = ["logging", "slf4j"]
  modules = [
    "org.slf4j:slf4j-simple:1.7.30",
    "com.example.it:it-logconfig:1.0.0"]

We can't use the same name log as before otherwise it would clash. Now let's assume the application requires a layer that provides log support, that is, it's tagged with logging, and given certain condition we'll instruct it to pick either the log or log2 layer; that condition is the evaluation of a program argument/System property that resolves into choosing the log4j or the slf4j tag. So far so good.

Now for a tricky part. Regardless of the choice, the core layer depends on a layer tagged with logging. Right now layers depend on explicit parents, so that what I just described would be another way to assemble the hierarchy. Thus besides direct parents we may need a requires capability kind of property that accepts a list of tags. given this, a Layer

Question:

  1. Given a layer with tags (such as log) that it's intended to be consumed by requirements and not as a parent, its name (log) is not needed. Could anonymous layers be defined? Such layers must have tags. Internally Layrry would assign an identifier during layer parsing but no other layer may refer directly to it by identifier (it's hidden) only by tags.
  2. How do we ensure that a layer tagged with logging is chosen? We know that its required by other layers. We may need to define a layer that's chosen by default if explicit tag activation does not happen.
  3. Do we want to define a default set of tags that must be activated? Say, logging and monitoring must always be active.