Skip to content

Commit

Permalink
Improve accessibility of Mojo configuration parameters
Browse files Browse the repository at this point in the history
Advantages:
- Enables access to nested elements
- Enables accessing multiple elements of same name
- In general enables to selectively walk the configuration element tree
  • Loading branch information
HannesWell committed Oct 18, 2022
1 parent 0a23551 commit 28c0022
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 33 deletions.
41 changes: 39 additions & 2 deletions org.eclipse.m2e.core/src/org/eclipse/m2e/core/embedder/IMaven.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.stream.Stream;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
Expand Down Expand Up @@ -148,11 +150,46 @@ MojoExecution setupMojoExecution(MavenProject project, MojoExecution execution,
throws CoreException;

/**
* @since 1.4
* Instances should not be cached
*
* @since 2.1
*/
<T> T getMojoParameterValue(MavenProject project, MojoExecution mojoExecution, String parameter, Class<T> asType,
public interface IConfigurationElement {
// TODO or firstChild() ? That's what it is actually but it does not look so nice when chained
IConfigurationParameter get(String name) throws NoSuchElementException;

// TODO: or all(String) or similar.
Stream<IConfigurationParameter> children(String name) throws NoSuchElementException;

// TODO: or all() or similar.
Stream<IConfigurationParameter> children() throws NoSuchElementException;
}

public interface IConfigurationParameter extends IConfigurationElement {

boolean exists();

<T> T as(Class<T> clazz) throws NoSuchElementException, IllegalStateException;
}

/**
* @since 2.1
*/
IConfigurationElement getMojoConfiguration(MavenProject project, MojoExecution mojoExecution,
IProgressMonitor monitor) throws CoreException;

/**
* @since 1.4
* @deprecated use {@link #getMojoConfiguration(MavenProject, MojoExecution, IProgressMonitor)} instead and query the
* returned {@link IConfigurationElement}.
*/
@Deprecated(forRemoval = true, since = "2.1")
default <T> T getMojoParameterValue(MavenProject project, MojoExecution mojoExecution, String parameter,
Class<T> asType, IProgressMonitor monitor) throws CoreException {
IConfigurationParameter configParameter = getMojoConfiguration(project, mojoExecution, monitor).get(parameter);
return configParameter.exists() ? configParameter.as(asType) : null;
}

/**
* @since 1.4
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*******************************************************************************
* Copyright (c) 2022-2022 Hannes Wellmann and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Hannes Wellmann - initial API and implementation
*******************************************************************************/

package org.eclipse.m2e.core.internal.embedder;

import java.util.Arrays;
import java.util.NoSuchElementException;
import java.util.stream.Stream;

import org.eclipse.osgi.util.NLS;

import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
import org.codehaus.plexus.component.configurator.converters.ConfigurationConverter;
import org.codehaus.plexus.component.configurator.converters.lookup.ConverterLookup;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
import org.codehaus.plexus.configuration.PlexusConfiguration;

import org.apache.maven.plugin.descriptor.MojoDescriptor;

import org.eclipse.m2e.core.embedder.IMaven.IConfigurationElement;
import org.eclipse.m2e.core.embedder.IMaven.IConfigurationParameter;


class ConfigurationElementImpl implements IConfigurationElement {
final PlexusConfiguration configuration;

final String path;

final ValueFactory valueFactory;

ConfigurationElementImpl(PlexusConfiguration configuration, String path, ValueFactory valueComputer) {
this.path = path;
this.configuration = configuration;
this.valueFactory = valueComputer;
}

@Override
public IConfigurationParameter get(String name) {
requireExists();
PlexusConfiguration child = configuration.getChild(name);
return new ConfigurationParameterImpl(child, this.path + "/" + name, valueFactory);
}

@Override
public Stream<IConfigurationParameter> children(String name) {
requireExists();
return Arrays.stream(configuration.getChildren(name))
.map(c -> new ConfigurationParameterImpl(c, this.path + "/" + name, valueFactory));
}

@Override
public Stream<IConfigurationParameter> children() throws NoSuchElementException {
requireExists();
return Arrays.stream(configuration.getChildren())
.map(c -> new ConfigurationParameterImpl(c, this.path + "/" + c.getName(), valueFactory));
}

void requireExists() {
if(configuration == null) {
throw new NoSuchElementException(
"Plugin execution " + valueFactory.mojo.getId() + "does not have a configuration parameter " + path);
}
}

record ValueFactory(ConverterLookup lookup, MojoDescriptor mojo, ClassLoader pluginRealm,
ExpressionEvaluator evaluator) {

private <T> T create(PlexusConfiguration configuration, Class<T> clazz) throws ComponentConfigurationException {
ConfigurationConverter typeConverter = lookup.lookupConverterForType(clazz);
Object value = typeConverter.fromConfiguration(lookup, configuration, clazz, mojo.getImplementationClass(),
pluginRealm, evaluator, null);
return clazz.cast(value);
}
}

static class ConfigurationParameterImpl extends ConfigurationElementImpl implements IConfigurationParameter {

private ConfigurationParameterImpl(PlexusConfiguration configuration, String name, ValueFactory valueComputer) {
super(configuration, name, valueComputer);
}

@Override
public boolean exists() {
return configuration != null;
}

@Override
public <T> T as(Class<T> clazz) throws NoSuchElementException {
requireExists();
try {
return valueFactory.create(configuration, clazz);
} catch(ComponentConfigurationException e) {
//TODO: or throw a IllegalArgument exception
// Probably the catched exception is thrown on the wrong type. TODO: test that.
throw new IllegalStateException(
NLS.bind("Failed to compute configuration for for plugin execution {0}", valueFactory.mojo.getId(), e));
}
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@
import org.eclipse.m2e.core.embedder.MavenConfigurationChangeEvent;
import org.eclipse.m2e.core.internal.IMavenConstants;
import org.eclipse.m2e.core.internal.Messages;
import org.eclipse.m2e.core.internal.embedder.ConfigurationElementImpl.ValueFactory;
import org.eclipse.m2e.core.internal.preferences.MavenPreferenceConstants;
import org.eclipse.m2e.core.project.IMavenProjectFacade;

Expand Down Expand Up @@ -716,38 +717,26 @@ private File getLastUpdatedFile(ArtifactRepository localRepository, Artifact art
"m2e-lastUpdated.properties").toFile();
}

private <T> T getMojoParameterValue(MavenSession session, MojoExecution mojoExecution, String parameter,
Class<T> asType) throws CoreException {
try {
MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();

ClassRealm pluginRealm = lookup(BuildPluginManager.class).getPluginRealm(session,
mojoDescriptor.getPluginDescriptor());

ExpressionEvaluator expressionEvaluator = new PluginParameterExpressionEvaluator(session, mojoExecution);
ConfigurationConverter typeConverter = converterLookup.lookupConverterForType(asType);
Xpp3Dom dom = mojoExecution.getConfiguration();
if(dom == null) {
return null;
}
PlexusConfiguration configuration = new XmlPlexusConfiguration(dom).getChild(parameter);
if(configuration == null) {
return null;
}
Object value = typeConverter.fromConfiguration(converterLookup, configuration, asType,
mojoDescriptor.getImplementationClass(), pluginRealm, expressionEvaluator, null);
return asType.cast(value);
} catch(Exception e) {
throw new CoreException(Status
.error(NLS.bind(Messages.MavenImpl_error_param_for_execution, parameter, mojoExecution.getExecutionId()), e));
}
}

@Override
public <T> T getMojoParameterValue(MavenProject project, MojoExecution mojoExecution, String parameter,
Class<T> asType, IProgressMonitor monitor) throws CoreException {
return getExecutionContext().execute(project,
(context, pm) -> getMojoParameterValue(context.getSession(), mojoExecution, parameter, asType), monitor);
public IConfigurationElement getMojoConfiguration(MavenProject project, MojoExecution execution,
IProgressMonitor monitor) throws CoreException {
return getExecutionContext().execute(project, (context, pm) -> {
try {
MavenSession session = context.getSession();
MojoDescriptor mojo = execution.getMojoDescriptor();
ClassRealm pluginRealm = lookup(BuildPluginManager.class).getPluginRealm(session, mojo.getPluginDescriptor());
PluginParameterExpressionEvaluator evaluator = new PluginParameterExpressionEvaluator(session, execution);
ValueFactory valueComputer = new ValueFactory(converterLookup, mojo, pluginRealm, evaluator);

Xpp3Dom dom = execution.getConfiguration();
PlexusConfiguration configuration = dom != null ? new XmlPlexusConfiguration(dom)
: new XmlPlexusConfiguration("");
return new ConfigurationElementImpl(configuration, "", valueComputer);
} catch(Exception e) {
throw new CoreException(Status.error(
NLS.bind("Could not get the configuration for for plugin execution {0}", execution.getExecutionId()), e));
}
}, monitor);
}

private <T> T getMojoParameterValue(String parameter, Class<T> type, MavenSession session, Plugin plugin,
Expand Down

0 comments on commit 28c0022

Please sign in to comment.