[MNG-7891] Support configuration for extensions (#1252)

This commit is contained in:
Guillaume Nodet 2023-09-22 09:14:56 +02:00 committed by GitHub
parent aefa9599fb
commit dd2f1214d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 203 additions and 20 deletions

View File

@ -3281,6 +3281,12 @@
<description>The version of the extension.</description>
<type>String</type>
</field>
<field>
<name>configuration</name>
<version>4.1.0+</version>
<description>The configuration of the extension.</description>
<type>DOM</type>
</field>
</fields>
<codeSegments>
<codeSegment>

View File

@ -29,6 +29,7 @@ import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import org.apache.maven.api.xml.XmlNode;
import org.apache.maven.project.ExtensionDescriptor;
import org.apache.maven.project.ExtensionDescriptorBuilder;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
@ -46,10 +47,21 @@ public class CoreExtensionEntry {
private final Set<String> packages;
public CoreExtensionEntry(ClassRealm realm, Collection<String> artifacts, Collection<String> packages) {
private final String key;
private final XmlNode configuration;
public CoreExtensionEntry(
ClassRealm realm,
Collection<String> artifacts,
Collection<String> packages,
String key,
XmlNode configuration) {
this.realm = realm;
this.artifacts = Collections.unmodifiableSet(new HashSet<>(artifacts));
this.packages = Collections.unmodifiableSet(new HashSet<>(packages));
this.key = key;
this.configuration = configuration;
}
/**
@ -73,6 +85,21 @@ public class CoreExtensionEntry {
return packages;
}
/**
* The key that can must used to identify the configuration using the
* {@link javax.inject.Named} annotation.
*/
public String getKey() {
return key;
}
/**
* Returns the configuration for this extension.
*/
public XmlNode getConfiguration() {
return configuration;
}
private static final ExtensionDescriptorBuilder BUILDER = new ExtensionDescriptorBuilder();
public static CoreExtensionEntry discoverFrom(ClassRealm loader) {
@ -93,10 +120,11 @@ public class CoreExtensionEntry {
// exports descriptors are entirely optional
}
return new CoreExtensionEntry(loader, artifacts, packages);
return new CoreExtensionEntry(loader, artifacts, packages, null, null);
}
public static CoreExtensionEntry discoverFrom(ClassRealm loader, Collection<File> classpath) {
public static CoreExtensionEntry discoverFrom(
ClassRealm loader, Collection<File> classpath, String key, XmlNode configuration) {
Set<String> artifacts = new LinkedHashSet<>();
Set<String> packages = new LinkedHashSet<>();
@ -112,6 +140,6 @@ public class CoreExtensionEntry {
// exports descriptors are entirely optional
}
return new CoreExtensionEntry(loader, artifacts, packages);
return new CoreExtensionEntry(loader, artifacts, packages, key, configuration);
}
}

View File

@ -427,7 +427,10 @@ public class DefaultMavenPluginManager implements MavenPluginManager {
((DefaultPlexusContainer) container)
.discoverComponents(
pluginRealm, new SessionScopeModule(container), new MojoExecutionScopeModule(container));
pluginRealm,
new SessionScopeModule(container),
new MojoExecutionScopeModule(container),
new PluginConfigurationModule(plugin.getDelegate()));
} catch (ComponentLookupException | CycleDetectedInComponentGraphException e) {
throw new PluginContainerException(
plugin,

View File

@ -0,0 +1,53 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.plugin.internal;
import com.google.inject.Binder;
import com.google.inject.Module;
import com.google.inject.name.Names;
import org.apache.maven.api.model.Plugin;
import org.apache.maven.api.xml.XmlNode;
import org.apache.maven.internal.xml.XmlNodeImpl;
import org.apache.maven.internal.xml.XmlPlexusConfiguration;
import org.codehaus.plexus.configuration.PlexusConfiguration;
class PluginConfigurationModule implements Module {
private final Plugin plugin;
PluginConfigurationModule(Plugin plugin) {
this.plugin = plugin;
}
@Override
public void configure(Binder binder) {
if (plugin.getKey() != null) {
XmlNode configuration = plugin.getConfiguration();
if (configuration == null) {
configuration = new XmlNodeImpl("configuration");
}
binder.bind(XmlNode.class)
.annotatedWith(Names.named(plugin.getKey()))
.toInstance(configuration);
binder.bind(PlexusConfiguration.class)
.annotatedWith(Names.named(plugin.getKey()))
.toInstance(XmlPlexusConfiguration.toPlexusConfiguration(configuration));
}
}
}

View File

@ -151,6 +151,7 @@ public class DefaultProjectBuildingHelper implements ProjectBuildingHelper {
plugin.setGroupId(extension.getGroupId());
plugin.setArtifactId(extension.getArtifactId());
plugin.setVersion(extension.getVersion());
plugin.setConfiguration(extension.getConfiguration());
extensionPlugins.add(plugin);
}

View File

@ -175,7 +175,7 @@ under the License.
<groupId>org.codehaus.modello</groupId>
<artifactId>modello-maven-plugin</artifactId>
<configuration>
<version>1.1.0</version>
<version>1.2.0</version>
<models>
<model>src/main/mdo/core-extensions.mdo</model>
</models>

View File

@ -0,0 +1,85 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cli;
import com.google.inject.Binder;
import com.google.inject.Module;
import com.google.inject.name.Names;
import org.apache.maven.api.xml.XmlNode;
import org.apache.maven.extension.internal.CoreExtensionEntry;
import org.apache.maven.internal.xml.XmlNodeImpl;
import org.apache.maven.internal.xml.XmlPlexusConfiguration;
import org.apache.maven.model.v4.MavenTransformer;
import org.codehaus.plexus.configuration.PlexusConfiguration;
import org.codehaus.plexus.interpolation.InterpolationException;
import org.codehaus.plexus.interpolation.PropertiesBasedValueSource;
import org.codehaus.plexus.interpolation.StringSearchInterpolator;
class ExtensionConfigurationModule implements Module {
private final CoreExtensionEntry extension;
private final CliRequest cliRequest;
ExtensionConfigurationModule(CoreExtensionEntry extension, CliRequest cliRequest) {
this.extension = extension;
this.cliRequest = cliRequest;
}
@Override
public void configure(Binder binder) {
if (extension.getKey() != null) {
XmlNode configuration = extension.getConfiguration();
if (configuration == null) {
configuration = new XmlNodeImpl("configuration");
}
configuration = new Interpolator().transform(configuration);
binder.bind(XmlNode.class)
.annotatedWith(Names.named(extension.getKey()))
.toInstance(configuration);
binder.bind(PlexusConfiguration.class)
.annotatedWith(Names.named(extension.getKey()))
.toInstance(XmlPlexusConfiguration.toPlexusConfiguration(configuration));
}
}
class Interpolator extends MavenTransformer {
final StringSearchInterpolator interpolator;
Interpolator() {
super(null);
interpolator = new StringSearchInterpolator();
interpolator.setCacheAnswers(true);
interpolator.addValueSource(new PropertiesBasedValueSource(cliRequest.userProperties));
interpolator.addValueSource(new PropertiesBasedValueSource(cliRequest.systemProperties));
}
public XmlNode transform(XmlNode node) {
return super.transform(node);
}
protected String transform(String str) {
try {
return interpolator.interpolate(str);
} catch (InterpolationException e) {
throw new RuntimeException(e);
}
}
}
}

View File

@ -694,7 +694,8 @@ public class MavenCli {
container.discoverComponents(
extension.getClassRealm(),
new SessionScopeModule(container),
new MojoExecutionScopeModule(container));
new MojoExecutionScopeModule(container),
new ExtensionConfigurationModule(extension, cliRequest));
}
customizeContainer(container);

View File

@ -150,7 +150,10 @@ public class BootstrapCoreExtensionManager {
}
}
return CoreExtensionEntry.discoverFrom(
realm, Collections.singleton(artifacts.get(0).getFile()));
realm,
Collections.singleton(artifacts.get(0).getFile()),
extension.getGroupId() + ":" + extension.getArtifactId(),
extension.getConfiguration());
}
private List<Artifact> resolveExtension(

View File

@ -90,6 +90,12 @@
<required>false</required>
<type>String</type>
</field>
<field>
<name>configuration</name>
<version>1.2.0+</version>
<required>false</required>
<type>DOM</type>
</field>
</fields>
<codeSegments>
<codeSegment>
@ -101,17 +107,10 @@
*
* @return The extension id in the form {@code <groupId>:<artifactId>:<version>}, never {@code null}.
*/
public String getId()
{
StringBuilder id = new StringBuilder( 128 );
id.append( ( getGroupId() == null ) ? "[unknown-group-id]" : getGroupId() );
id.append( ":" );
id.append( ( getArtifactId() == null ) ? "[unknown-artifact-id]" : getArtifactId() );
id.append( ":" );
id.append( ( getVersion() == null ) ? "[unknown-version]" : getVersion() );
return id.toString();
public String getId() {
return (getGroupId() == null ? "[unknown-group-id]" : getGroupId())
+ ":" + (getArtifactId() == null ? "[unknown-artifact-id]" : getArtifactId())
+ ":" + (getVersion() == null ? "[unknown-version]" : getVersion());
}
]]>
</code>

View File

@ -138,7 +138,7 @@ public class ${className} {
#end
#foreach ( $field in $classToFields.get( $class ) )
#if ( $field.isManyMultiplicity() )
#if ( $classToFields.containsKey( $model.getClass( $field.type ) ) )
#if ( $classToFields.containsKey( $field.toClass ) )
$pfx ${var}.get${Helper.capitalise($field.name)}().stream().anyMatch(this::is_${v}) // ${class.name} : ${field.name}
#else
$pfx !${var}.get${Helper.capitalise($field.name)}().isEmpty() // ${class.name} : ${field.name}
@ -177,4 +177,8 @@ public class ${className} {
return !list.isEmpty();
}
private boolean has(XmlNode node) {
return node != null;
}
}