-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Issue #10437 - Unify Deployer ContextProvider #12583
base: jetty-12.1.x
Are you sure you want to change the base?
Conversation
...-core/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ScanningAppProvider.java
Show resolved
Hide resolved
jetty-core/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ContextProvider.java
Show resolved
Hide resolved
jetty-core/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ContextProvider.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ContextProvider.java
Outdated
Show resolved
Hide resolved
...loy/src/test/java/org/eclipse/jetty/deploy/providers/ContextProviderDeferredStartupTest.java
Show resolved
Hide resolved
...ploy/src/test/java/org/eclipse/jetty/deploy/providers/ContextProviderRuntimeUpdatesTest.java
Show resolved
Hide resolved
...etty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/ContextProviderStartupTest.java
Show resolved
Hide resolved
jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/Deployable.java
Outdated
Show resolved
Hide resolved
jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/WebAppContext.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ContextProvider.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ContextProvider.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ContextProvider.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-deploy/src/main/config/etc/jetty-deployment-manager.xml
Show resolved
Hide resolved
I'd like to see:
|
jetty-core/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ContextProvider.java
Show resolved
Hide resolved
...-core/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ScanningAppProvider.java
Outdated
Show resolved
Hide resolved
…ehaviors. + A DeploymentUnit is all the paths for a specific basename that are being tracked for deployment reasons. + New DeploymentUnitsTest test cases + A new ContextProvider.getMainDeploymentPath for defining the main path deployment heuristics for a unit
Not ready yet, more changes coming (based on conversation from @sbordet ) |
* A Unit of deployment, a basename and all the associated | ||
* paths that belong to that basename, along with state. | ||
*/ | ||
public class Unit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that Unit
should be promoted to a top level class, and App
demoted to an implementation detail. The Unit
class better captures what we're dealing with - a possible collection of files and/or directories that taken all together represent a deployable. The App
is really just a subset of that information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unit
is a component of a disk based, hot deployment based, disk scanning, local system only approach for deployment. (our ScanningAppProvider
abstract and ContextProvider
implementation).
Not all users of DeploymentManager
or all implementations of AppProvider
even use the local disk as a source for their applications. Many come from external sources, some come from build plugins, some come as a result of an action from some other trigger.
Making Unit
the top level is the wrong approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you clarify succinctly the difference between App
and Unit
using language like "A Unit is a ....", "An App is a ..."? Looking at the code App
has Path
references and so does Unit
, so in that sense they both refer to resources that can be disk based resources, so that can't be the difference.
* @return The name of the {@link org.eclipse.jetty.util.component.Environment} this provider is for. | ||
* @deprecated not used by all AppProviders, no generic replacement provided. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this interface is not named exactly accurately, and the class javadoc is misleading. According to its api, it isn't creating or providing any App
instances to the DeploymentManager
at all. Looking at it's api, it's function is really to create a ContextHandler
instance - after some other class passes in an already created instance of App
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unit
a way thatScanningAppProvider
tracks its collection ofPath
objects to anApp
via it's basename. (as long as the basename exists, this Unit exist)App
the fundamental unit used to track theApp
through the deployment lifecycle. (created as part of new deployment, used as reference for moving through lifecycle: undeploy/remove steps)ContextHandler
the feature of the Jetty Server that represents the instantiated and liveApp
While all of these seem like the same "thing" to track as a single place, it is really 3 levels of abstraction, each with its own life cycle. The Unit
has the longest lifecycle, followed by App
with a shorter lifecycle, and finally ContextHandler
with the shortest (from the point of view of a deployment manager).
A Unit
exists for as long as there are Paths
with a basename being tracked. (only lives in ScanningAppProvider
)
An App
only exists if there is an AppProvider
that creates it. (note that ScanningAppProvider
can have a Unit
with no App
if there is no main deployment path present for that Unit
)
A ContextHandler
only exists if there is a need for it in the lifecycle binding. (If a step in the lifecycle needs a ContextHandler
then that's when it gets created or accessed. Our standard lifecycle bindings will use the ContextHandler for deploy/start/stop/undeploy, but not the other bindings)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ContextHandler
can even change as the App
moves through the registered lifecycle bindings.
For example, a custom binding could wrap the ContextHandler
to add an auditing layer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The lifecycle relationships are such that neither an App
nor a ContextHandler
(in the sense of deployer) can exist without a Unit
. Sure, ContextHandler
and App
have their own lifecycles, but they ultimately depend on the existence or otherwise of the Unit
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ContextHandlerFactory would be a better name for this interface
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another feature of Unit
is that it represents a group of paths that influence the deployment process.
One aspect not made clear is that the environment configuration files (webapps/<env>.xml
, webapps/<env>-<name>.xml
, webapps/<env>.properties
, and webapps/<env>-<name>.properties
) are also considered a Unit
(with basename <env>
) that is tracked by the Scanner. (this is a feature that's been in Jetty 12.0.x since its inception). If one of those files in the unit are changed, then that triggers all associated App
s on that environment to also hot-redeploy.
* A Unit of deployment, a basename and all the associated | ||
* paths that belong to that basename, along with state. | ||
*/ | ||
public class Unit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you clarify succinctly the difference between App
and Unit
using language like "A Unit is a ....", "An App is a ..."? Looking at the code App
has Path
references and so does Unit
, so in that sense they both refer to resources that can be disk based resources, so that can't be the difference.
return app; | ||
} | ||
|
||
public void setApp(App app) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Creating the App
instance external to this class loses the relationship between the set of resources that this Unit
is holding, one of which must be used by the App
. Having this setter means that the App
can have been created using any old path, not necessarily one of the resources associated with this Unit
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is 100% correct.
A custom AppProvider
doesn't have to have the concept of Path
(main or otherwise) or anything like that.
This Unit
class wouldn't be used in that scenario.
* {@link org.eclipse.jetty.util.resource.ResourceFactory#newResource(String)} | ||
* @return The App object for this particular context definition file. | ||
* @param path The file that the main point of deployment (eg: a context XML, a WAR file, a directory, etc) | ||
* @return The App object for this particular context. | ||
*/ | ||
protected App createApp(Path path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the Unit
produced the App
then that would better control that the path
must be one of those known about by the Unit
. In fact, you should probably be able to navigate from an App
to the parent Unit
also.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not all Unit
instances have App
. (re: Environment Config files are grouped into a Unit
by its environment name, and trigger synthetic Changes to all registered App
that are managed by ContextProvider
and being tracked by our Unit
).
App
instances from other (custom) AppProviders
do not have a Unit
and are not seen by our ContextProvider
.
Only our ContextProvider
needs to know the App
for the Unit
.
Keep in mind that Unit
is just ours, not a general purpose API, like App
is.
* @return The name of the {@link org.eclipse.jetty.util.component.Environment} this provider is for. | ||
* @deprecated not used by all AppProviders, no generic replacement provided. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The lifecycle relationships are such that neither an App
nor a ContextHandler
(in the sense of deployer) can exist without a Unit
. Sure, ContextHandler
and App
have their own lifecycles, but they ultimately depend on the existence or otherwise of the Unit
.
{ | ||
// XML always win. | ||
List<Path> xmls = unit.getPaths().keySet().stream() | ||
.filter(FileID::isXml) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to filter out removed paths as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This uses the new Unit.getLivePaths()
, which filters out REMOVED state paths.
jetty-core/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ContextProvider.java
Show resolved
Hide resolved
jetty-core/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ContextProvider.java
Show resolved
Hide resolved
* @return The name of the {@link org.eclipse.jetty.util.component.Environment} this provider is for. | ||
* @deprecated not used by all AppProviders, no generic replacement provided. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ContextHandlerFactory would be a better name for this interface
* @return the main deployable path | ||
*/ | ||
@Override | ||
protected Path getMainDeploymentPath(Unit unit) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a bit strange that the logic that knows how to group different paths into a single unit is in the internal DeploymentUnits
, whilst the logic to pick which of them is the main deployment path is here, in an entirely different place. Surely both bits of logic are related and should be in the same class
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Picking the main path seems more like a ContextProvider concern.
The Unit and DeploymentUnits is go-between from the Scanner events to the ContextProvider.
if (dirs.size() > 1) | ||
throw new IllegalStateException("More than 1 Directory for deployable " + asStringList(dirs)); | ||
|
||
throw new IllegalStateException("Unable to determine main deployable for " + unit); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this really an ISE? If we have just created foo.d
or foo.properties
, then we don't have enough to deploy anything, but I don't think it is an exceptional condition. Perhaps a null return would be better, reflecting a unit that does not have a deployable path.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point.
We need a testcase for this scenario.
What would you expect the result to be?
Kind feels like a "core" deployment, not a servlet deployment.
|
||
// Calculate state of unit from Path states. | ||
Unit.State ret = null; | ||
for (Unit.State pathState : paths.values()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The algorithm here needs to be well documented in a comment so we can check if it is correct. A unit is:
- REMOVED if it is empty or all its deployable paths (xml, war, directory) are REMOVED
- CHANGED if it has at least one path that is not UNCHANGED. If that one path is ADDED, then it must have another path that is not ADDED
- ADDED if it has one or more deployable paths that are ADDED and none that are not ADDED
Note the inclusion of the concept of a deployable path (xml, war, directory), as only changes to them may result in ADDED or REMOVED. However a change to a non deployable path (properties or .d) can result in a CHANGED.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the implementation is right (also I think my description above might need improvement as well).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added some new javadoc, and some tests of Unit.calcState()
, and fixed the implementation some to address these concerns better.
A single scanner for all Environments.
Environment attributes are how the environment specific deployment configuration is controlled.
Existing properties behaviors maintained.
Currently a WIP (needs more testing and documentation)