Extension does not work from .mvn/extensions.xml

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Extension does not work from .mvn/extensions.xml

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
...
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: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Extension does not work from .mvn/extensions.xml

J. Lewis Muir
On Wed, Nov 14, 2018 at 3:31 PM Romain Manni-Bucau
<[hidden email]> wrote:
> 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: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Extension does not work from .mvn/extensions.xml

J. Lewis Muir
On Fri, Nov 16, 2018 at 3:35 PM Romain Manni-Bucau
<[hidden email]> wrote:
> 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?

> 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.

> > 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.

> > 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.
> >
>
> 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: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Extension does not work from .mvn/extensions.xml

J. Lewis Muir
On Sat, Nov 17, 2018 at 1:53 AM Romain Manni-Bucau
<[hidden email]> wrote:

> > > 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."

> > 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: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Extension does not work from .mvn/extensions.xml

Romain Manni-Bucau
Time to push your code and an example on github to encourage help/people to
run it ;)

Le lun. 19 nov. 2018 22:28, J. Lewis Muir <[hidden email]> a écrit :

> On Sat, Nov 17, 2018 at 11:32 AM Romain Manni-Bucau
> <[hidden email]> wrote:
> > Le sam. 17 nov. 2018 17:06, J. Lewis Muir <[hidden email]> a écrit
> :
> > > > 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: [hidden email]
> For additional commands, e-mail: [hidden email]
>
>
Reply | Threaded
Open this post in threaded view
|

Re: Extension does not work from .mvn/extensions.xml

Romain Manni-Bucau
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>


Le mar. 20 nov. 2018 à 05:56, J. Lewis Muir <[hidden email]> a écrit :

> On Mon, Nov 19, 2018 at 4:16 PM Romain Manni-Bucau
> <[hidden email]> wrote:
> > 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: [hidden email]
> For additional commands, e-mail: [hidden email]
>
>
Reply | Threaded
Open this post in threaded view
|

Re: Extension does not work from .mvn/extensions.xml

Romain Manni-Bucau
Le mar. 20 nov. 2018 22:24, J. Lewis Muir <[hidden email]> a écrit :

> On Tue, Nov 20, 2018 at 1:01 PM Romain Manni-Bucau
> <[hidden email]> wrote:
> > Le mar. 20 nov. 2018 19:23, J. Lewis Muir <[hidden email]> a écrit
> :
> > > 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.


> 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.
>
> > > 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.


> Thanks!
>
> Lewis
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]