Class DevLoopBuildExtension
Maven gives a <configuration> value in the pom precedence over the
user property the same parameter exposes, so -Djetty.scan=0 on the
command line does nothing to a project that writes <scan>2</scan>,
which a generated WAR starter does by default. The plugin then redeploys the
webapp on a schedule of its own, the second driver of what the transaction
model owns: measured, one apply that reported a clean hot swap was
followed by the plugin tearing the context down and rebuilding it, losing
every page's state for a change that was already live.
Asking every project to write <scan>0</scan> is not a fix - it is a
requirement on humans and agents that a tool should not need. A build
extension is the supported way to change a model the daemon does not own: it
runs inside the application's own build, before any mojo, and edits the
effective plugin configuration in memory. Nothing is written to the project.
A second plugin shape needs more than a rewrite: Cargo's run mojo exposes no
user property on any parameter that could carry the loop's JVM flags, and
reads a Maven project property named cargo.* instead. So the
extension also sets project properties for the run, named one at a time by
PROPERTY_PREFIX.
A third needs the goal itself. A goal named on a Maven command line runs in
every project in the reactor, and TomEE's run mojo has no skip and no
packaging check to escape that with - named, it starts a server in the
reactor root and blocks the build before the application module is built.
Liberty's does start its server in the application's module alone, but runs
in the others too and replaces each sibling's jar with its
target/classes on the way. A goal bound to a phase runs only
where the model carries it, so for that shape the daemon names no goal at all
and asks the extension to add the execution here, in the application's module
alone; see BIND_PROPERTY.
Both are applied to the one module the daemon names in
MODULE_PROPERTY and to no other; see there for why an inherited
plugin makes that scope load-bearing rather than tidy.
This class lives in the daemon's jar because that jar's path is the one thing
the daemon always knows - it is already its own -javaagent - so
putting the extension anywhere else would mean a second artifact to resolve
and keep in step. It is compiled against Maven's API at provided
scope and is never loaded in the daemon's own JVM; only Maven ever sees it.
For internal use only. May be renamed or removed in a future release.
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final StringA goal to bind in that module, as<phase>:<goal>.static final StringWhat to force on it, aselement=valuepairs separated by semicolons.static final StringWhere each module's effective model is left, relative to the module's own directory.static final StringartifactIdof the module the daemon runs that plugin in.static final StringgroupId:artifactIdof the plugin to reconfigure.static final StringPrefix of a setting naming a Maven project property to put on the model, as<prefix><name>=<value>. -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidafterProjectsRead(org.apache.maven.execution.MavenSession session) Methods inherited from class org.apache.maven.AbstractMavenLifecycleParticipant
afterSessionEnd, afterSessionStart
-
Field Details
-
PLUGIN_PROPERTY
groupId:artifactIdof the plugin to reconfigure.- See Also:
-
MODULE_PROPERTY
artifactIdof the module the daemon runs that plugin in.Everything the extension forces is applied to that module and to no other, and the reason is that
getBuildPluginsis the effective model: a plugin a reactor parent declares is in every module that inherits it, the reactor root among them. Reconfiguring each one would undo the very thing the reconfiguration is for - Cargo, WildFly and both Payaras are switched off across the reactor by a-D<name>.skip=trueand switched back on for the application by a forced<skip>false</skip>, so a forcedfalseeverywhere would start a server in the reactor root, or fail there on a packaging that builds no deployment, before the build ever reached the application's own module.The artifactId alone, because that is what the daemon already names the module with: the run is
-pl :<artifactId> -am, so a reactor in which two modules answered to it is one Maven could not have been asked to run this goal in to begin with.- See Also:
-
FORCE_PROPERTY
What to force on it, aselement=valuepairs separated by semicolons. Passed rather than hard-coded so that the values stay inServerPlugin, where the rest of a server's description lives, and a second container needs no change here.- See Also:
-
PROPERTY_PREFIX
Prefix of a setting naming a Maven project property to put on the model, as<prefix><name>=<value>.The channel for a plugin whose parameter carries no user property at all, which is the shape Cargo has: every element of its run mojo that could hold the loop's JVM flags is nested and settable from a pom only, while any project property named
cargo.*is read and injected as a container configuration property. Setting one is therefore the only way in, and doing it here rather than in the pom leaves the project untouched, exactly asFORCE_PROPERTYdoes.One setting per property, rather than the
name=valuelistFORCE_PROPERTYuses, because there is no separator that would be safe: a value carried this way holds the application's whole JVM command line, and on Windows-Dvaadin.devloop.classes=alone contains semicolons.- See Also:
-
BIND_PROPERTY
A goal to bind in that module, as<phase>:<goal>.How a goal is kept to one module when the plugin offers no way of its own.
-plchooses which projects are in the reactor, not which of them a named goal runs in - it runs in all of them - and no command line can say otherwise. A goal bound to a phase runs where the model carries it, and the model is what this extension edits. So the daemon names the phase alone and asks for the goal here.Added to the plugin's executions rather than replacing them: the project may have executions of its own, and this run is still that project's build.
It is given a copy of the plugin's own
<configuration>, and that is not a convenience. Maven merges a plugin-level configuration into each execution's while it is building the model, and afterwards consults the plugin-level one for a goal named on the command line alone (DefaultLifecycleExecutionPlanCalculatorpassesallowPluginLevelConfigonly forMojoExecution.Source.CLI). An execution added after the model was built has missed that merge and would run on the mojo's defaults. Measured:<tomeeHttpPort>8892</tomeeHttpPort>and<context>ROOT</context>were both in the effective model and the server still came up on 8080 under the module'sfinalName.Within a phase Maven runs executions in the order their plugins appear in the effective model, and merges the lifecycle-injected ones in first - so
war:waris already scheduled ahead of an execution added to a pom-declared plugin atpackage, which is what the goal needs: it deploys the WAR that phase builds.- See Also:
-
MODEL_FILE
Where each module's effective model is left, relative to the module's own directory.The daemon reads poms with the JDK's XML parser and no Maven at all, which settles most questions but not the two Maven alone can answer: which profiles are active, and what a module inherits from a parent outside the checkout. Both are already decided by the time this runs, so writing them down costs nothing and saves the daemon from guessing.
Relative to the module and not to
${project.build.directory}, deliberately: the reader is the daemon, which has no Maven to ask where that directory points, so a project that moves it -<build><directory>build</directory></build>- would have the two ends looking at different paths and the model would read as simply missing.target/devloop/is where the daemon keeps everything else it writes per module, and it is the same path on the reading side; seeEffectiveModel#FILE.- See Also:
-
-
Constructor Details
-
DevLoopBuildExtension
public DevLoopBuildExtension()
-
-
Method Details
-
afterProjectsRead
public void afterProjectsRead(org.apache.maven.execution.MavenSession session) - Overrides:
afterProjectsReadin classorg.apache.maven.AbstractMavenLifecycleParticipant
-