Discussion:
Extension does not work from .mvn/extensions.xml
J. Lewis Muir
2018-11-14 21:24:13 UTC
Permalink
Hello, all!

I have an extension

https://github.com/imca-cat/profile-activation-advanced

that allows property-based profile activation based on an MVEL
expression.

My problem is that it works

===
$ mvn help:active-profiles validate
...
The following profiles are active:

- foo_env-development (source: org.example.foo:foo:1.0.0)
...
===

when loaded via Maven's lib/ext directory or when specified on the
command line with "-Dmaven.ext.class.path=<path-to-extension-jars>", but
does *not* work

===
$ mvn help:active-profiles validate
...
The following profiles are active:

...
===

when loaded via a project's .mvn/extensions.xml file.

The extension hijacks the normal property activator like this

@Component(role = ProfileActivator.class, hint = "property")
public class AdvancedProfileActivator implements ProfileActivator {
...
}

and evaluates the property value as an MVEL expression if the property
name equals "mvel" or "mvel(" <properties-map-identifier> ")".

Does anyone know why it would work from Maven's lib/ext directory, but
not from a project's .mvn/extensions.xml file? Or does anyone know how
to debug this?

Is it possible that the hijack doesn't work when loaded from a
project's .mvn/extensions.xml because the original profile activator is
found on the class path *before* the AdvancedProfileActivator of the
extension, but when the extension JAR is placed in Maven's lib/ext,
the AdvancedProfileActivator is found on the class path *before* the
original profile activator? (Just a wild guess.)

The full source code of the extension's profile activator is at

https://github.com/imca-cat/profile-activation-advanced/blob/master/src/main/java/org/imca_cat/maven/profile_activation_advanced/AdvancedProfileActivator.java

To reproduce the problem, simply create a new Maven project directory
containing the following pom.xml file:

===
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example.foo</groupId>
<artifactId>foo</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<profiles>
<profile>
<id>foo_env-development</id>
<activation>
<property>
<name>mvel</name>
<value>(!isdef foo_env) || foo_env == "development"</value>
</property>
</activation>
</profile>
</profiles>
</project>
===

(The foo_env-development profile should activate if the foo_env property
(or system property) is not set or is set to the string "development".)

Create .mvn/extensions.xml:

===
<?xml version="1.0" encoding="UTF-8"?>
<extensions xmlns="http://maven.apache.org/EXTENSIONS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/EXTENSIONS/1.0.0
http://maven.apache.org/xsd/core-extensions-1.0.0.xsd">
<extension>
<groupId>org.imca-cat.maven</groupId>
<artifactId>profile-activation-advanced</artifactId>
<version>0.1.0</version>
</extension>
</extensions>
===

Run the following command:

===
$ mvn help:active-profiles validate
===

It should report that the foo_env-development profile is active (because
the foo_env property is not set), but it does not. :-(

I previously asked on the Maven User list

https://lists.apache.org/thread.html/99ee87ba1bc86d98652173482b3a5882a52e344fad18df2cd50e8750@%3Cusers.maven.apache.org%3E

but did not receive any replies.

Thank you for your help!

Lewis

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-***@maven.apache.org
For additional commands, e-mail: dev-***@maven.apache.org
Romain Manni-Bucau
2018-11-14 21:31:15 UTC
Permalink
Hi Lewis

You can debug using mvnDebug but i think it is cause there is already a
property handler -
https://github.com/apache/maven/blob/master/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/PropertyProfileActivator.java
- so depending the scanning order you take one or the other. Try using
another marker maybe or making yours higher priority probably.
Post by J. Lewis Muir
Hello, all!
I have an extension
https://github.com/imca-cat/profile-activation-advanced
that allows property-based profile activation based on an MVEL
expression.
My problem is that it works
===
$ mvn help:active-profiles validate
...
- foo_env-development (source: org.example.foo:foo:1.0.0)
...
===
when loaded via Maven's lib/ext directory or when specified on the
command line with "-Dmaven.ext.class.path=<path-to-extension-jars>", but
does *not* work
===
$ mvn help:active-profiles validate
...
...
===
when loaded via a project's .mvn/extensions.xml file.
The extension hijacks the normal property activator like this
@Component(role = ProfileActivator.class, hint = "property")
public class AdvancedProfileActivator implements ProfileActivator {
...
}
and evaluates the property value as an MVEL expression if the property
name equals "mvel" or "mvel(" <properties-map-identifier> ")".
Does anyone know why it would work from Maven's lib/ext directory, but
not from a project's .mvn/extensions.xml file? Or does anyone know how
to debug this?
Is it possible that the hijack doesn't work when loaded from a
project's .mvn/extensions.xml because the original profile activator is
found on the class path *before* the AdvancedProfileActivator of the
extension, but when the extension JAR is placed in Maven's lib/ext,
the AdvancedProfileActivator is found on the class path *before* the
original profile activator? (Just a wild guess.)
The full source code of the extension's profile activator is at
https://github.com/imca-cat/profile-activation-advanced/blob/master/src/main/java/org/imca_cat/maven/profile_activation_advanced/AdvancedProfileActivator.java
To reproduce the problem, simply create a new Maven project directory
===
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example.foo</groupId>
<artifactId>foo</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<profiles>
<profile>
<id>foo_env-development</id>
<activation>
<property>
<name>mvel</name>
<value>(!isdef foo_env) || foo_env == "development"</value>
</property>
</activation>
</profile>
</profiles>
</project>
===
(The foo_env-development profile should activate if the foo_env property
(or system property) is not set or is set to the string "development".)
===
<?xml version="1.0" encoding="UTF-8"?>
<extensions xmlns="http://maven.apache.org/EXTENSIONS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/EXTENSIONS/1.0.0
http://maven.apache.org/xsd/core-extensions-1.0.0.xsd">
<extension>
<groupId>org.imca-cat.maven</groupId>
<artifactId>profile-activation-advanced</artifactId>
<version>0.1.0</version>
</extension>
</extensions>
===
===
$ mvn help:active-profiles validate
===
It should report that the foo_env-development profile is active (because
the foo_env property is not set), but it does not. :-(
I previously asked on the Maven User list
but did not receive any replies.
Thank you for your help!
Lewis
---------------------------------------------------------------------
J. Lewis Muir
2018-11-15 23:06:31 UTC
Permalink
On Wed, Nov 14, 2018 at 3:31 PM Romain Manni-Bucau
Post by Romain Manni-Bucau
You can debug using mvnDebug but i think it is cause there is already a
property handler -
https://github.com/apache/maven/blob/master/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/PropertyProfileActivator.java
- so depending the scanning order you take one or the other. Try using
another marker maybe or making yours higher priority probably.
Hi, Romain!

Thank you for your reply!

What do you mean by "using another marker"?

How can I make mine have higher priority?

I looked at

http://codehaus-plexus.github.io/plexus-containers/plexus-component-annotations/apidocs/

and the Component annotation has a number of elements, but none of
them look like they would let me assign a priority (e.g., an element
named "priority"). I also don't see an annotation that looks like it
would let me assign a priority (e.g., an annotation named "Priority").

The closest I could find to the concept of a priority was a Stack
Overflow answer

https://stackoverflow.com/a/41970497

where the author talks about a solution which I think refers to this commit

https://github.com/Code-House/maven-osgi-resolver/commit/e0b9797657d90eb35a8a166efbf3e01c09fd4189

where he adds a dependency on org.eclipse.sisu:org.eclipse.sisu.inject
and adds a Priority annotation

http://www.eclipse.org/sisu/docs/api/org.eclipse.sisu.inject/reference/org/eclipse/sisu/Priority.html

However, in the very next commit, the author removes the Priority
annotation believing it to be unnecessary

https://github.com/Code-House/maven-osgi-resolver/commit/67e3b31d18d1efb0b8f279a1bbacfa39b88d3236

I understand Sisu to be this project

http://www.eclipse.org/sisu/

but I don't know much else about it.

I'm also a little concerned with what I see in DefaultModelBuilderFactory

https://github.com/apache/maven/blob/master/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java

in its newProfileActivators method: it creates an instance of
PropertyProfileActivator which would seem to bypass any injection
(including that of my AdvancedProfileActivator). The class comment
says, though,

This class is only meant as a utility for developers that want to
employ the model builder outside of the Maven build system, Maven
plugins should always acquire model builder instances via dependency
injection.

So maybe I don't have to worry about it?

Thanks!

Lewis

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-***@maven.apache.org
For additional commands, e-mail: dev-***@maven.apache.org
Romain Manni-Bucau
2018-11-16 06:02:07 UTC
Permalink
For the marker i was thinking about "property" so your activation would be
"el:name" or anything else - idea just being not intrusive and impacting
for actual property activation.

Did you try to use an extension rewritting the model after it is read and
before it is executed with a lifecycle participant? Sounds easier to
implement since you just convert it to an active or not activation of a
built in type.
The IoC uses guice so it is notr trivial to use @priority but there are
ways to do so, that said i dont think you need checking the profile logic.

The default model builder is used when there is no IoC so shouldn't be used
here. If your activator is registered it is injected and then used in the
isActive loop if it returns true for presentInConfig call (check
DefaultProfileSelector).
This is likely where you will have to debug.
Post by J. Lewis Muir
On Wed, Nov 14, 2018 at 3:31 PM Romain Manni-Bucau
Post by Romain Manni-Bucau
You can debug using mvnDebug but i think it is cause there is already a
property handler -
https://github.com/apache/maven/blob/master/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/PropertyProfileActivator.java
Post by Romain Manni-Bucau
- so depending the scanning order you take one or the other. Try using
another marker maybe or making yours higher priority probably.
Hi, Romain!
Thank you for your reply!
What do you mean by "using another marker"?
How can I make mine have higher priority?
I looked at
http://codehaus-plexus.github.io/plexus-containers/plexus-component-annotations/apidocs/
and the Component annotation has a number of elements, but none of
them look like they would let me assign a priority (e.g., an element
named "priority"). I also don't see an annotation that looks like it
would let me assign a priority (e.g., an annotation named "Priority").
The closest I could find to the concept of a priority was a Stack
Overflow answer
https://stackoverflow.com/a/41970497
where the author talks about a solution which I think refers to this commit
https://github.com/Code-House/maven-osgi-resolver/commit/e0b9797657d90eb35a8a166efbf3e01c09fd4189
where he adds a dependency on org.eclipse.sisu:org.eclipse.sisu.inject
and adds a Priority annotation
http://www.eclipse.org/sisu/docs/api/org.eclipse.sisu.inject/reference/org/eclipse/sisu/Priority.html
However, in the very next commit, the author removes the Priority
annotation believing it to be unnecessary
https://github.com/Code-House/maven-osgi-resolver/commit/67e3b31d18d1efb0b8f279a1bbacfa39b88d3236
I understand Sisu to be this project
http://www.eclipse.org/sisu/
but I don't know much else about it.
I'm also a little concerned with what I see in DefaultModelBuilderFactory
https://github.com/apache/maven/blob/master/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java
in its newProfileActivators method: it creates an instance of
PropertyProfileActivator which would seem to bypass any injection
(including that of my AdvancedProfileActivator). The class comment
says, though,
This class is only meant as a utility for developers that want to
employ the model builder outside of the Maven build system, Maven
plugins should always acquire model builder instances via dependency
injection.
So maybe I don't have to worry about it?
Thanks!
Lewis
---------------------------------------------------------------------
J. Lewis Muir
2018-11-16 19:36:09 UTC
Permalink
On Fri, Nov 16, 2018 at 12:02 AM Romain Manni-Bucau
Post by Romain Manni-Bucau
For the marker i was thinking about "property" so your activation would be
"el:name" or anything else - idea just being not intrusive and impacting
for actual property activation.
I see. I thought that, in order for the hijack to work, it needed to
use the same role hint; no? I'll change the hint element to
"paa:property" (for Profile Activation Advanced property) or something
similar.
Post by Romain Manni-Bucau
Did you try to use an extension rewritting the model after it is read and
before it is executed with a lifecycle participant? Sounds easier to
implement since you just convert it to an active or not activation of a
built in type.
No, I didn't try that. That's an interesting idea! The lifecycle
participant would give me a MavenSession object. I can get to
ActivationProperty objects via

MavenSession.getProjects()
MavenProject.getModel()
Model.getProfiles()
Profile.getActivation()
Activation.getProperty()

but this is just the model, not how the model is interpreted (i.e.,
how the profile is determined to be active or not). I could examine
the ActivationProperty objects, and if they are the special ones I
want to handle (i.e., name is "mvel" or "mvel("
<properties-map-identifier> ")"), then I could evaluate the MVEL
expression and replace the ActivationProperty objects with ones that
would evaluate to true or false always (e.g., a property name I know
does not exist and using the negation operator or not to artificially
cause it to always evaluate to true or false). That seems like a
hack, but maybe it's OK. (?)

And I wouldn't have the ProfileActivationContext object that I would
have in the ProfileActivator.isActive method. But I guess I could
work around that by getting the things I need directly from the
MavenSession object (i.e., MavenSession.getSystemProperties() and
MavenSession.getUserProperties()), but would that be considered
correct, or would that likely break stuff?

Am I anywhere near understanding what you're suggesting?
Post by Romain Manni-Bucau
ways to do so, that said i dont think you need checking the profile logic.
OK, I'll put this approach on the back burner and only come back to it
if I can't get the lifecycle participant approach to work.
Post by Romain Manni-Bucau
The default model builder is used when there is no IoC so shouldn't be used
here.
OK, great.
Post by Romain Manni-Bucau
If your activator is registered it is injected and then used in the
isActive loop if it returns true for presentInConfig call (check
DefaultProfileSelector).
This is likely where you will have to debug.
But my problem is getting my activator to be injected instead of the
regular one. I think that's where the @Priority annotation comes in.
But I think you're suggesting the lifecycle participant approach would
be easier, so I'm trying that now.

Thank you!

Lewis

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-***@maven.apache.org
For additional commands, e-mail: dev-***@maven.apache.org
Romain Manni-Bucau
2018-11-16 21:35:18 UTC
Permalink
Post by J. Lewis Muir
On Fri, Nov 16, 2018 at 12:02 AM Romain Manni-Bucau
Post by Romain Manni-Bucau
For the marker i was thinking about "property" so your activation would
be
Post by Romain Manni-Bucau
"el:name" or anything else - idea just being not intrusive and impacting
for actual property activation.
I see. I thought that, in order for the hijack to work, it needed to
use the same role hint; no? I'll change the hint element to
"paa:property" (for Profile Activation Advanced property) or something
similar.
I didnt find in the code where the hint matches, just saw a chain so should
work if i didnt miss a later filtering. That said my naming advise was for
the pom content more than the code (to not interpret default property tag).
Post by J. Lewis Muir
Post by Romain Manni-Bucau
Did you try to use an extension rewritting the model after it is read and
before it is executed with a lifecycle participant? Sounds easier to
implement since you just convert it to an active or not activation of a
built in type.
No, I didn't try that. That's an interesting idea! The lifecycle
participant would give me a MavenSession object. I can get to
ActivationProperty objects via
MavenSession.getProjects()
MavenProject.getModel()
Model.getProfiles()
Profile.getActivation()
Activation.getProperty()
but this is just the model, not how the model is interpreted (i.e.,
how the profile is determined to be active or not). I could examine
the ActivationProperty objects, and if they are the special ones I
want to handle (i.e., name is "mvel" or "mvel("
<properties-map-identifier> ")"), then I could evaluate the MVEL
expression and replace the ActivationProperty objects with ones that
would evaluate to true or false always (e.g., a property name I know
does not exist and using the negation operator or not to artificially
cause it to always evaluate to true or false). That seems like a
hack, but maybe it's OK. (?)
And I wouldn't have the ProfileActivationContext object that I would
have in the ProfileActivator.isActive method. But I guess I could
work around that by getting the things I need directly from the
MavenSession object (i.e., MavenSession.getSystemProperties() and
MavenSession.getUserProperties()), but would that be considered
correct, or would that likely break stuff?
Am I anywhere near understanding what you're suggesting?
You can mutate this model, this is all the trick ;)
Post by J. Lewis Muir
Post by Romain Manni-Bucau
ways to do so, that said i dont think you need checking the profile
logic.
OK, I'll put this approach on the back burner and only come back to it
if I can't get the lifecycle participant approach to work.
Post by Romain Manni-Bucau
The default model builder is used when there is no IoC so shouldn't be
used
Post by Romain Manni-Bucau
here.
OK, great.
Post by Romain Manni-Bucau
If your activator is registered it is injected and then used in the
isActive loop if it returns true for presentInConfig call (check
DefaultProfileSelector).
This is likely where you will have to debug.
But my problem is getting my activator to be injected instead of the
But I think you're suggesting the lifecycle participant approach would
be easier, so I'm trying that now.
Not instead but also. Instead of 3 impl you will get 4.
Post by J. Lewis Muir
Thank you!
Lewis
---------------------------------------------------------------------
J. Lewis Muir
2018-11-16 23:09:40 UTC
Permalink
On Fri, Nov 16, 2018 at 3:35 PM Romain Manni-Bucau
Post by Romain Manni-Bucau
I didnt find in the code where the hint matches, just saw a chain so should
work if i didnt miss a later filtering.
Where in the code is that?
Post by Romain Manni-Bucau
That said my naming advise was for
the pom content more than the code (to not interpret default property tag).
I see. But if I add a new tag, then the POM wouldn't validate against
the DTD, right? That seems like an undesirable path to take, no?

And even if I did change the POM content to have, let's say, an
advancedProperty element under the XPath
/project/profiles/profile/activation, what object in the model would
be created when Maven reads the POM? It seems to me that it won't
know how to create an object for this part of the POM in
MavenXpp3Reader, so I don't understand how it would work. I would
need it to be able to create an AdvancedActivationProperty, but I
don't see a way to make it able to do that.
Post by Romain Manni-Bucau
Post by J. Lewis Muir
Am I anywhere near understanding what you're suggesting?
You can mutate this model, this is all the trick ;)
So, the hack I outlined is what you were thinking? I don't see how to
do it any other way.
Post by Romain Manni-Bucau
Post by J. Lewis Muir
But my problem is getting my activator to be injected instead of the
But I think you're suggesting the lifecycle participant approach would
be easier, so I'm trying that now.
Not instead but also. Instead of 3 impl you will get 4.
I see. I guess I don't know where to hook into the model, then. I
can't find anything in the model that implements the is-active
computation for a Profile or Activation, so I don't see how to hook
into it other than mutating the model with the hack I previously
proposed which was to evaluate the MVEL expression and replace the
ActivationProperty with one with a specially constructed name and
value that would always evaluate to the just computed result of the
MVEL expression.

So, in the approach where I have 4 implementations, how do I get Maven
to use my AdvancedProfileActivator? I assumed this was done based on
the Component annotation hint element, and I thought the hint had to
match the element under the activation element in the POM (e.g.,
<activation><property>...</property></activation> means the hint for
Maven's PropertyProfileActivator must be "property", which it is).
So, for <activation><advancedProperty>...</advancedProperty></activation>,
the hint for my AdvancedProfileActivator must be "advancedProperty".
If that's right, then that makes sense to me. But I still don't know
how to get Maven to create an instance of AdvancedActivationProperty
in the model when it reads the POM.

Sorry to not be understanding things. Thanks for your help! I really
appreciate it!

Lewis

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-***@maven.apache.org
For additional commands, e-mail: dev-***@maven.apache.org
Romain Manni-Bucau
2018-11-17 07:53:38 UTC
Permalink
Post by J. Lewis Muir
On Fri, Nov 16, 2018 at 3:35 PM Romain Manni-Bucau
Post by Romain Manni-Bucau
I didnt find in the code where the hint matches, just saw a chain so
should
Post by Romain Manni-Bucau
work if i didnt miss a later filtering.
Where in the code is that?
The profile selector impl
Post by J. Lewis Muir
Post by Romain Manni-Bucau
That said my naming advise was for
the pom content more than the code (to not interpret default property
tag).
I see. But if I add a new tag, then the POM wouldn't validate against
the DTD, right? That seems like an undesirable path to take, no?
Idea is just to split them logically, property.name=yourprefix:xxxx not
technically
Post by J. Lewis Muir
And even if I did change the POM content to have, let's say, an
advancedProperty element under the XPath
/project/profiles/profile/activation, what object in the model would
be created when Maven reads the POM? It seems to me that it won't
know how to create an object for this part of the POM in
MavenXpp3Reader, so I don't understand how it would work. I would
need it to be able to create an AdvancedActivationProperty, but I
don't see a way to make it able to do that.
Post by Romain Manni-Bucau
Post by J. Lewis Muir
Am I anywhere near understanding what you're suggesting?
You can mutate this model, this is all the trick ;)
So, the hack I outlined is what you were thinking? I don't see how to
do it any other way.
Post by Romain Manni-Bucau
Post by J. Lewis Muir
But my problem is getting my activator to be injected instead of the
But I think you're suggesting the lifecycle participant approach would
be easier, so I'm trying that now.
Not instead but also. Instead of 3 impl you will get 4.
I see. I guess I don't know where to hook into the model, then. I
can't find anything in the model that implements the is-active
computation for a Profile or Activation, so I don't see how to hook
into it other than mutating the model with the hack I previously
proposed which was to evaluate the MVEL expression and replace the
ActivationProperty with one with a specially constructed name and
value that would always evaluate to the just computed result of the
MVEL expression.
Idea was to set an activation which will match true with default impls
Post by J. Lewis Muir
So, in the approach where I have 4 implementations, how do I get Maven
to use my AdvancedProfileActivator? I assumed this was done based on
the Component annotation hint element, and I thought the hint had to
match the element under the activation element in the POM (e.g.,
<activation><property>...</property></activation> means the hint for
Maven's PropertyProfileActivator must be "property", which it is).
So, for <activation><advancedProperty>...</advancedProperty></activation>,
the hint for my AdvancedProfileActivator must be "advancedProperty".
If that's right, then that makes sense to me. But I still don't know
how to get Maven to create an instance of AdvancedActivationProperty
in the model when it reads the POM.
If you have plexus plugin it will do
Post by J. Lewis Muir
Sorry to not be understanding things. Thanks for your help! I really
appreciate it!
Lewis
---------------------------------------------------------------------
J. Lewis Muir
2018-11-17 16:05:44 UTC
Permalink
On Sat, Nov 17, 2018 at 1:53 AM Romain Manni-Bucau
Post by Romain Manni-Bucau
Post by J. Lewis Muir
Post by Romain Manni-Bucau
Not instead but also. Instead of 3 impl you will get 4.
I see. I guess I don't know where to hook into the model, then. I
can't find anything in the model that implements the is-active
computation for a Profile or Activation, so I don't see how to hook
into it other than mutating the model with the hack I previously
proposed which was to evaluate the MVEL expression and replace the
ActivationProperty with one with a specially constructed name and
value that would always evaluate to the just computed result of the
MVEL expression.
Idea was to set an activation which will match true with default impls
OK, I'm just trying to make sure I understanding that. The default
activation impls are ActivationFile (file), ActivationOS (os),
ActivationProperty (property), and String (jdk). The default
activator impls are FileProfileActivator,
OperatingSystemProfileActivator, PropertyProfileActivator, and
JdkVersionProfileActivator. The idea would match true with these
default impls, right? And the only way to make it match true with
these default impls would be to replace the ActivationProperty
instances in the model that need the special MVEL evaluation with new
ActivationProperty instances that will always evaluate to true or
false according to the pre-computed MVEL evaluation results, right?
In this approach, there would be no new impls (i.e., no
AdvancedActivationProperty and no AdvancedProfileActivator).

Another thought I had is that I could modify the active-profiles list
of the MavenProject instances (i.e., MavenProject.setActiveProfiles)
of the model to include or exclude the profiles with the special MVEL
activation based on the result of evaluating those MVEL expressions.
Then I wouldn't need to do the hack of changing the ActivationProperty
instances to always evaluate to true or false according to the
pre-computed result of the MVEL evaluation. Wouldn't that work?
This, however, does not seem the same as your description of the idea
of setting an activation that would "match true with default impls."
Post by Romain Manni-Bucau
Post by J. Lewis Muir
So, in the approach where I have 4 implementations, how do I get Maven
to use my AdvancedProfileActivator? I assumed this was done based on
the Component annotation hint element, and I thought the hint had to
match the element under the activation element in the POM (e.g.,
<activation><property>...</property></activation> means the hint for
Maven's PropertyProfileActivator must be "property", which it is).
So, for <activation><advancedProperty>...</advancedProperty></activation>,
the hint for my AdvancedProfileActivator must be "advancedProperty".
If that's right, then that makes sense to me. But I still don't know
how to get Maven to create an instance of AdvancedActivationProperty
in the model when it reads the POM.
If you have plexus plugin it will do
Hmm, so to date I've been implementing this as a core extension, not
as a Plexus plugin (if I'm understanding terminology correctly). Are
you suggesting it would be better to implement this as a Plexus
plugin?

Also, based on your previous comments, I don't think you're suggesting
at all doing this thing of adding a new tag (e.g.,
<activation><advancedProperty>...</advancedProperty></activation>),
since you said you were thinking of the separation logically, not
physically in the XML.

Thank you!

Lewis

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-***@maven.apache.org
For additional commands, e-mail: dev-***@maven.apache.org
Romain Manni-Bucau
2018-11-17 17:32:36 UTC
Permalink
Post by J. Lewis Muir
On Sat, Nov 17, 2018 at 1:53 AM Romain Manni-Bucau
Post by Romain Manni-Bucau
Post by J. Lewis Muir
Post by Romain Manni-Bucau
Not instead but also. Instead of 3 impl you will get 4.
I see. I guess I don't know where to hook into the model, then. I
can't find anything in the model that implements the is-active
computation for a Profile or Activation, so I don't see how to hook
into it other than mutating the model with the hack I previously
proposed which was to evaluate the MVEL expression and replace the
ActivationProperty with one with a specially constructed name and
value that would always evaluate to the just computed result of the
MVEL expression.
Idea was to set an activation which will match true with default impls
OK, I'm just trying to make sure I understanding that. The default
activation impls are ActivationFile (file), ActivationOS (os),
ActivationProperty (property), and String (jdk). The default
activator impls are FileProfileActivator,
OperatingSystemProfileActivator, PropertyProfileActivator, and
JdkVersionProfileActivator. The idea would match true with these
default impls, right? And the only way to make it match true with
these default impls would be to replace the ActivationProperty
instances in the model that need the special MVEL evaluation with new
ActivationProperty instances that will always evaluate to true or
false according to the pre-computed MVEL evaluation results, right?
In this approach, there would be no new impls (i.e., no
AdvancedActivationProperty and no AdvancedProfileActivator).
Another thought I had is that I could modify the active-profiles list
of the MavenProject instances (i.e., MavenProject.setActiveProfiles)
of the model to include or exclude the profiles with the special MVEL
activation based on the result of evaluating those MVEL expressions.
Then I wouldn't need to do the hack of changing the ActivationProperty
instances to always evaluate to true or false according to the
pre-computed result of the MVEL evaluation. Wouldn't that work?
This, however, does not seem the same as your description of the idea
of setting an activation that would "match true with default impls."
Here you change the activation to match a default logic evaluation or you
change profiles and model to be pre activated. Personally i prefer to keep
profile cause it eases debugging but both work.
Post by J. Lewis Muir
Post by Romain Manni-Bucau
Post by J. Lewis Muir
So, in the approach where I have 4 implementations, how do I get Maven
to use my AdvancedProfileActivator? I assumed this was done based on
the Component annotation hint element, and I thought the hint had to
match the element under the activation element in the POM (e.g.,
<activation><property>...</property></activation> means the hint for
Maven's PropertyProfileActivator must be "property", which it is).
So, for
<activation><advancedProperty>...</advancedProperty></activation>,
Post by Romain Manni-Bucau
Post by J. Lewis Muir
the hint for my AdvancedProfileActivator must be "advancedProperty".
If that's right, then that makes sense to me. But I still don't know
how to get Maven to create an instance of AdvancedActivationProperty
in the model when it reads the POM.
If you have plexus plugin it will do
Hmm, so to date I've been implementing this as a core extension, not
as a Plexus plugin (if I'm understanding terminology correctly). Are
you suggesting it would be better to implement this as a Plexus
plugin?
This is not two things incompatible actually but yes. In short an extension
integrates with maven lifecycle and plexus with maven ioc (lower level).
Post by J. Lewis Muir
Also, based on your previous comments, I don't think you're suggesting
at all doing this thing of adding a new tag (e.g.,
<activation><advancedProperty>...</advancedProperty></activation>),
since you said you were thinking of the separation logically, not
physically in the XML.
Would break several tooling to do that so likely not a good bet.
Post by J. Lewis Muir
Thank you!
Lewis
---------------------------------------------------------------------
J. Lewis Muir
2018-11-19 21:28:02 UTC
Permalink
On Sat, Nov 17, 2018 at 11:32 AM Romain Manni-Bucau
Post by Romain Manni-Bucau
Post by J. Lewis Muir
Post by Romain Manni-Bucau
Idea was to set an activation which will match true with default impls
OK, I'm just trying to make sure I understanding that. The default
activation impls are ActivationFile (file), ActivationOS (os),
ActivationProperty (property), and String (jdk). The default
activator impls are FileProfileActivator,
OperatingSystemProfileActivator, PropertyProfileActivator, and
JdkVersionProfileActivator. The idea would match true with these
default impls, right? And the only way to make it match true with
these default impls would be to replace the ActivationProperty
instances in the model that need the special MVEL evaluation with new
ActivationProperty instances that will always evaluate to true or
false according to the pre-computed MVEL evaluation results, right?
In this approach, there would be no new impls (i.e., no
AdvancedActivationProperty and no AdvancedProfileActivator).
Another thought I had is that I could modify the active-profiles list
of the MavenProject instances (i.e., MavenProject.setActiveProfiles)
of the model to include or exclude the profiles with the special MVEL
activation based on the result of evaluating those MVEL expressions.
Then I wouldn't need to do the hack of changing the ActivationProperty
instances to always evaluate to true or false according to the
pre-computed result of the MVEL evaluation. Wouldn't that work?
This, however, does not seem the same as your description of the idea
of setting an activation that would "match true with default impls."
Here you change the activation to match a default logic evaluation or you
change profiles and model to be pre activated. Personally i prefer to keep
profile cause it eases debugging but both work.
Hmm, I can't get it to work. :-( I created my own lifecycle
participant by extending AbstractMavenLifecycleParticipant and
overrode afterProjectsRead, but the profile activation has already
been evaluated by the time this method is called. That means I would
have to trigger evaluation again after I changed the
ActivationProperty to always evaluate to true or false to match the
result of the MVEL expression evaluation.

I could re-evaluate the profile activation with
DefaultProfileSelector, but if something else is injecting a different
ProfileSelector, then hard-coding DefaultProfileSelector would mess
that up. Is there a way to instantiate the ProfileSelector that Maven
would normally instantiate?

And on top of that, I just tried a hack of manually adding the profile
to the MavenProject's active-profiles list

List<Profile> activeProfiles = project.getActiveProfiles();
activeProfiles.add(profileActivatedByMvel);
project.setActiveProfiles(activeProfiles);

and it seems to have no effect: running "mvn help:active-profiles
validate" in a test project that uses the extension shows no active
profiles.

I also tried overriding
AbstractMavenLifecycleParticipant.afterSessionStart, but this seems to
be too early: the MavenSession doesn't have any projects.

Thank you!

Lewis

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-***@maven.apache.org
For additional commands, e-mail: dev-***@maven.apache.org
Romain Manni-Bucau
2018-11-19 22:16:16 UTC
Permalink
Time to push your code and an example on github to encourage help/people to
run it ;)
Post by J. Lewis Muir
On Sat, Nov 17, 2018 at 11:32 AM Romain Manni-Bucau
Post by Romain Manni-Bucau
Post by J. Lewis Muir
Post by Romain Manni-Bucau
Idea was to set an activation which will match true with default
impls
Post by Romain Manni-Bucau
Post by J. Lewis Muir
OK, I'm just trying to make sure I understanding that. The default
activation impls are ActivationFile (file), ActivationOS (os),
ActivationProperty (property), and String (jdk). The default
activator impls are FileProfileActivator,
OperatingSystemProfileActivator, PropertyProfileActivator, and
JdkVersionProfileActivator. The idea would match true with these
default impls, right? And the only way to make it match true with
these default impls would be to replace the ActivationProperty
instances in the model that need the special MVEL evaluation with new
ActivationProperty instances that will always evaluate to true or
false according to the pre-computed MVEL evaluation results, right?
In this approach, there would be no new impls (i.e., no
AdvancedActivationProperty and no AdvancedProfileActivator).
Another thought I had is that I could modify the active-profiles list
of the MavenProject instances (i.e., MavenProject.setActiveProfiles)
of the model to include or exclude the profiles with the special MVEL
activation based on the result of evaluating those MVEL expressions.
Then I wouldn't need to do the hack of changing the ActivationProperty
instances to always evaluate to true or false according to the
pre-computed result of the MVEL evaluation. Wouldn't that work?
This, however, does not seem the same as your description of the idea
of setting an activation that would "match true with default impls."
Here you change the activation to match a default logic evaluation or you
change profiles and model to be pre activated. Personally i prefer to
keep
Post by Romain Manni-Bucau
profile cause it eases debugging but both work.
Hmm, I can't get it to work. :-( I created my own lifecycle
participant by extending AbstractMavenLifecycleParticipant and
overrode afterProjectsRead, but the profile activation has already
been evaluated by the time this method is called. That means I would
have to trigger evaluation again after I changed the
ActivationProperty to always evaluate to true or false to match the
result of the MVEL expression evaluation.
I could re-evaluate the profile activation with
DefaultProfileSelector, but if something else is injecting a different
ProfileSelector, then hard-coding DefaultProfileSelector would mess
that up. Is there a way to instantiate the ProfileSelector that Maven
would normally instantiate?
And on top of that, I just tried a hack of manually adding the profile
to the MavenProject's active-profiles list
List<Profile> activeProfiles = project.getActiveProfiles();
activeProfiles.add(profileActivatedByMvel);
project.setActiveProfiles(activeProfiles);
and it seems to have no effect: running "mvn help:active-profiles
validate" in a test project that uses the extension shows no active
profiles.
I also tried overriding
AbstractMavenLifecycleParticipant.afterSessionStart, but this seems to
be too early: the MavenSession doesn't have any projects.
Thank you!
Lewis
---------------------------------------------------------------------
J. Lewis Muir
2018-11-20 04:55:58 UTC
Permalink
On Mon, Nov 19, 2018 at 4:16 PM Romain Manni-Bucau
Post by Romain Manni-Bucau
Time to push your code and an example on github to encourage help/people to
run it ;)
OK, here's how to get the extension with the proof of concept code and
install it locally:

===
$ git clone https://github.com/imca-cat/profile-activation-advanced.git
$ cd profile-activation-advanced
$ git checkout lifecycle-participant-poc
$ mvn clean install
===

The proof of concept extension just changes the value of any profile
property activation with a name of "paa:mvel" to the string "!false".
It does not evaluate any MVEL expression at the moment; it's just a
proof of concept for changing the model. Since the system property
"paa:mvel" is not defined, the altered property activation should
evaluate to true, but I don't know how to get Maven to re-evaluate the
property activations after I've changed them.

And here's how to get and run a small test that uses the locally
installed extension:

===
$ git clone https://github.com/jlmuir/profile-activation-advanced-test.git
$ cd profile-activation-advanced-test
$ mvn help:active-profiles validate
===

I'm expecting the "mvn help:active-profiles validate" command to show
that the foo_env-development profile is active with output like

===
The following profiles are active:

- foo_env-development (source: org.example.foo:foo:1.0.0)
===

but it does not. So, it seems the extension is not successfully
changing the model (i.e., not successfully activating the
foo_env-development profile).

Thank you!

Lewis

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-***@maven.apache.org
For additional commands, e-mail: dev-***@maven.apache.org
Romain Manni-Bucau
2018-11-20 08:30:01 UTC
Permalink
Ok so let me try to write a step by step:

1. you have to use lib/ext folder and not extensions.xml cause it is loaded
too late
2. you have to override the property activator as you mentionned cause
otherwise your profile is added (through plexus) in the list of activator,
set the activation to true and then property one sets it to false

To do 2 you just have to use sisu @Priority and ensure the hint is property:

@org.eclipse.sisu.Priority(1)
@Component(role = ProfileActivator.class, hint = "property")
public class AdvancedProfileActivator implements ProfileActivator {}


Romain Manni-Bucau
@rmannibucau <https://twitter.com/rmannibucau> | Blog
<https://rmannibucau.metawerx.net/> | Old Blog
<http://rmannibucau.wordpress.com> | Github <https://github.com/rmannibucau> |
LinkedIn <https://www.linkedin.com/in/rmannibucau> | Book
<https://www.packtpub.com/application-development/java-ee-8-high-performance>
Post by J. Lewis Muir
On Mon, Nov 19, 2018 at 4:16 PM Romain Manni-Bucau
Post by Romain Manni-Bucau
Time to push your code and an example on github to encourage help/people
to
Post by Romain Manni-Bucau
run it ;)
OK, here's how to get the extension with the proof of concept code and
===
$ git clone https://github.com/imca-cat/profile-activation-advanced.git
$ cd profile-activation-advanced
$ git checkout lifecycle-participant-poc
$ mvn clean install
===
The proof of concept extension just changes the value of any profile
property activation with a name of "paa:mvel" to the string "!false".
It does not evaluate any MVEL expression at the moment; it's just a
proof of concept for changing the model. Since the system property
"paa:mvel" is not defined, the altered property activation should
evaluate to true, but I don't know how to get Maven to re-evaluate the
property activations after I've changed them.
And here's how to get and run a small test that uses the locally
===
$ git clone https://github.com/jlmuir/profile-activation-advanced-test.git
$ cd profile-activation-advanced-test
$ mvn help:active-profiles validate
===
I'm expecting the "mvn help:active-profiles validate" command to show
that the foo_env-development profile is active with output like
===
- foo_env-development (source: org.example.foo:foo:1.0.0)
===
but it does not. So, it seems the extension is not successfully
changing the model (i.e., not successfully activating the
foo_env-development profile).
Thank you!
Lewis
---------------------------------------------------------------------
J. Lewis Muir
2018-11-20 18:23:14 UTC
Permalink
On Tue, Nov 20, 2018 at 2:30 AM Romain Manni-Bucau
Post by Romain Manni-Bucau
1. you have to use lib/ext folder and not extensions.xml cause it is loaded
too late
Unfortunately, that's a deal breaker. Using Maven's lib/ext is the
original situation I reported when I started this thread (i.e., it
worked from Maven's lib/ext, but not from the project's
.mvn/extensions.xml.) There's no way I can get the developers of the
software I'm planning to use this in to install the extension in
Maven's lib/ext; it has to be able to work from the project's
.mvn/extensions.xml. I guess this is the end of the road, then.
Bummer.
Post by Romain Manni-Bucau
2. you have to override the property activator as you mentionned cause
otherwise your profile is added (through plexus) in the list of activator,
set the activation to true and then property one sets it to false
I tried adding the Priority annotation, and it works from Maven's
lib/ext, but it also works *without* it, so I'm hesitant to add it
unless I know it's really necessary. The readme file in Maven's
lib/ext says

Use this directory to contribute 3rd-party extensions to the Maven
core. These extensions can either extend or override Maven's default
implementation.

Do I really need the Priority annotation, or will my extension's
AdvancedProfileActivator (annotated with '@Component(role =
ProfileActivator.class, hint = "property")') always take precedence
over the default by virtue of being in Maven's lib/ext?

Thank you!

Lewis

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-***@maven.apache.org
For additional commands, e-mail: dev-***@maven.apache.org
Romain Manni-Bucau
2018-11-20 19:01:16 UTC
Permalink
Post by J. Lewis Muir
On Tue, Nov 20, 2018 at 2:30 AM Romain Manni-Bucau
Post by Romain Manni-Bucau
1. you have to use lib/ext folder and not extensions.xml cause it is
loaded
Post by Romain Manni-Bucau
too late
Unfortunately, that's a deal breaker. Using Maven's lib/ext is the
original situation I reported when I started this thread (i.e., it
worked from Maven's lib/ext, but not from the project's
.mvn/extensions.xml.) There's no way I can get the developers of the
software I'm planning to use this in to install the extension in
Maven's lib/ext; it has to be able to work from the project's
.mvn/extensions.xml. I guess this is the end of the road, then.
Bummer.
Even with mvnsh, maven opts or the -D?
Post by J. Lewis Muir
Post by Romain Manni-Bucau
2. you have to override the property activator as you mentionned cause
otherwise your profile is added (through plexus) in the list of
activator,
Post by Romain Manni-Bucau
set the activation to true and then property one sets it to false
I tried adding the Priority annotation, and it works from Maven's
lib/ext, but it also works *without* it, so I'm hesitant to add it
unless I know it's really necessary. The readme file in Maven's
lib/ext says
Without it you dont deactivate default one - you can check it debugging it.
Post by J. Lewis Muir
Use this directory to contribute 3rd-party extensions to the Maven
core. These extensions can either extend or override Maven's default
implementation.
Do I really need the Priority annotation, or will my extension's
ProfileActivator.class, hint = "property")') always take precedence
over the default by virtue of being in Maven's lib/ext?
This kind of order is fragile so better to be deterministic ans more robust
imho
Post by J. Lewis Muir
Thank you!
Lewis
---------------------------------------------------------------------
J. Lewis Muir
2018-11-20 21:24:06 UTC
Permalink
On Tue, Nov 20, 2018 at 1:01 PM Romain Manni-Bucau
Post by Romain Manni-Bucau
Post by J. Lewis Muir
There's no way I can get the developers of the
software I'm planning to use this in to install the extension in
Maven's lib/ext; it has to be able to work from the project's
.mvn/extensions.xml.
Even with mvnsh, maven opts or the -D?
Well, it's for a project where I'm not a core developer, so I don't
think there will be much support for anything that requires doing
something extra.

I doubt mvnsh would fly.

MAVEN_OPTS would work, but it's external and not with the project
source code, so it requires each developer to do some special setting
up. I doubt it would fly.

The closest I can get would be -D in the project's .mvn/maven.config.
This would require adding the two JARs
(profile-activation-advanced-0.2.0.jar and mvel2-2.4.2.Final.jar) to
the project's source code repo, though. That right there is already
undesirable. And then, say the JARs were added under the project's
root at lib-ext, the following would need to be added to the project's
.mvn/maven.config:

-Dmaven.ext.class.path=lib-ext/profile-activation-advanced-0.2.0.jar:lib-ext/mvel2-2.4.2.Final.jar

That's the closest I could get, and it requires the paths in the
maven.ext.class.path system property to be resolved relative to the
project root (so that the relative paths to the JAR files will be
correct), and I don't even know if that's guaranteed.

So, it's a pretty tough sell at this point.
Post by Romain Manni-Bucau
Post by J. Lewis Muir
I tried adding the Priority annotation, and it works from Maven's
lib/ext, but it also works *without* it, so I'm hesitant to add it
unless I know it's really necessary. The readme file in Maven's
lib/ext says
Without it you dont deactivate default one - you can check it debugging it.
Hmm, how can I check it by debugging? I tried without the Priority
annotation with a breakpoint in AdvancedProfileActivator.isActive, and
I looked at the caller DefaultProfileSelector.isActive frame, which is
one frame down in the stack, and I see the AdvancedProfileActivator in
the DefaultProfileSelector's activators list, and I don't see the
default PropertyProfileActivator. Attached is a screenshot. Maybe
I'm looking in the wrong place?

Thanks!

Lewis
Romain Manni-Bucau
2018-11-20 22:33:42 UTC
Permalink
Post by J. Lewis Muir
On Tue, Nov 20, 2018 at 1:01 PM Romain Manni-Bucau
Post by Romain Manni-Bucau
Post by J. Lewis Muir
There's no way I can get the developers of the
software I'm planning to use this in to install the extension in
Maven's lib/ext; it has to be able to work from the project's
.mvn/extensions.xml.
Even with mvnsh, maven opts or the -D?
Well, it's for a project where I'm not a core developer, so I don't
think there will be much support for anything that requires doing
something extra.
I doubt mvnsh would fly.
Hmm mvnwrapper works cause it downloads mvn and can use itself to use
dependency:copy to download lissing and add them in the -D if needed IMHO.
Post by J. Lewis Muir
MAVEN_OPTS would work, but it's external and not with the project
source code, so it requires each developer to do some special setting
up. I doubt it would fly.
The closest I can get would be -D in the project's .mvn/maven.config.
This would require adding the two JARs
(profile-activation-advanced-0.2.0.jar and mvel2-2.4.2.Final.jar) to
the project's source code repo, though. That right there is already
undesirable. And then, say the JARs were added under the project's
root at lib-ext, the following would need to be added to the project's
-Dmaven.ext.class.path=lib-ext/profile-activation-advanced-0.2.0.jar:lib-ext/mvel2-2.4.2.Final.jar
That's the closest I could get, and it requires the paths in the
maven.ext.class.path system property to be resolved relative to the
project root (so that the relative paths to the JAR files will be
correct), and I don't even know if that's guaranteed.
So, it's a pretty tough sell at this point.
Post by Romain Manni-Bucau
Post by J. Lewis Muir
I tried adding the Priority annotation, and it works from Maven's
lib/ext, but it also works *without* it, so I'm hesitant to add it
unless I know it's really necessary. The readme file in Maven's
lib/ext says
Without it you dont deactivate default one - you can check it debugging
it.
Hmm, how can I check it by debugging? I tried without the Priority
annotation with a breakpoint in AdvancedProfileActivator.isActive, and
I looked at the caller DefaultProfileSelector.isActive frame, which is
one frame down in the stack, and I see the AdvancedProfileActivator in
the DefaultProfileSelector's activators list, and I don't see the
default PropertyProfileActivator. Attached is a screenshot. Maybe
I'm looking in the wrong place?
Hmm i had both. I used mvn 3.6.0 during my debugging - shouldnt change
since a few version but we never know.
Post by J. Lewis Muir
Thanks!
Lewis
---------------------------------------------------------------------
Loading...