Skip to content

Commit

Permalink
[MSITE-1000] Introduce parser configuration parameter
Browse files Browse the repository at this point in the history
This leverages PlexusConfigurator under the hood
  • Loading branch information
kwin committed Mar 20, 2024
1 parent d78b8da commit 614a057
Show file tree
Hide file tree
Showing 6 changed files with 262 additions and 10 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ under the License.
<!-- for dependencies -->
<jettyVersion>9.4.53.v20231009</jettyVersion>
<doxiaVersion>2.0.0-M8</doxiaVersion>
<doxiaSitetoolsVersion>2.0.0-M16</doxiaSitetoolsVersion>
<doxiaSitetoolsVersion>2.0.0-M18-SNAPSHOT</doxiaSitetoolsVersion>
<wagonVersion>3.5.3</wagonVersion>
<slf4jVersion>1.7.36</slf4jVersion>
<!-- for ITs -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.apache.maven.doxia.site.SiteModel;
import org.apache.maven.doxia.siterenderer.DocumentRenderer;
import org.apache.maven.doxia.siterenderer.DocumentRenderingContext;
import org.apache.maven.doxia.siterenderer.ParserConfigurator;
import org.apache.maven.doxia.siterenderer.RendererException;
import org.apache.maven.doxia.siterenderer.SiteRenderer;
import org.apache.maven.doxia.siterenderer.SiteRenderingContext;
Expand All @@ -57,6 +58,8 @@
import org.apache.maven.reporting.exec.MavenReportExecutor;
import org.apache.maven.reporting.exec.MavenReportExecutorRequest;
import org.apache.maven.shared.utils.WriterFactory;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.configuration.PlexusConfiguration;
import org.codehaus.plexus.util.ReaderFactory;

import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
Expand Down Expand Up @@ -94,6 +97,37 @@ public abstract class AbstractSiteRenderingMojo extends AbstractSiteDescriptorMo
@Parameter
private Map<String, Object> attributes;

/**
* Parser configurations (per matching Doxia markup source file path patterns).
* Each configuration item has the following format:
* <p/>
* <pre><code>
* &lt;parserId&gt
* &lt;configurations&gt;
* &lt;configuration&gt;
* &lt;patterns&gt;
* &lt;pattern&gt;glob:**&#47;*.md&lt;/pattern&gt;&lt;!-- is either glob or regex syntax with the according prefix --&gt;
* &lt;/patterns&gt;
* &lt;!-- all configurations apart from pattern are directly applied to the underlying parser --&gt;
* &lt;emitComments&gt;true&lt;/emitComments&gt;&lt;!-- false by default --&gt;
* &lt;emitAnchorsForIndexableEntries&gt;false&lt;/emitAnchorsForIndexableEntries&gt;&lt;!-- true by default --&gt;
* &lt;/configuration&gt;
* &lt;/configurations&gt;
* &lt;/parserId&gt
* </code></pre>
* The configuration is only applied if both
* <ul>
* <li>the parser id matches the parser used for a specific markup source file and</li>
* <li>one of the given patterns matches the Doxia markup source file path (or no pattern is given at all).</li>
* </ul>
*
* The first matching configuration wins (i.e. is applied).
* @since 4.0.0
* @see java.nio.file.FileSystem#getPathMatcher(String) FileSystem.getPathMatcher(String) for the supported patterns
*/
@Parameter
private Map<String, List<PlexusConfiguration>> parserConfigurations;

/**
* Site renderer.
*/
Expand Down Expand Up @@ -269,7 +303,12 @@ private ReportPlugin[] getReportingPlugins() {
return reportingPlugins.toArray(new ReportPlugin[0]);
}

protected SiteRenderingContext createSiteRenderingContext(Locale locale)
protected ParserConfiguratorImpl createParserConfigurator() throws ComponentLookupException {
return new ParserConfiguratorImpl(
parserConfigurations, mavenSession.getContainer(), mojoExecution.getMojoDescriptor());
}

protected SiteRenderingContext createSiteRenderingContext(Locale locale, ParserConfigurator parserConfigurator)
throws MojoExecutionException, IOException, MojoFailureException {
SiteModel siteModel = prepareSiteModel(locale);
Map<String, Object> templateProperties = new HashMap<>();
Expand Down Expand Up @@ -329,7 +368,7 @@ protected SiteRenderingContext createSiteRenderingContext(Locale locale)
context.setProcessedContentOutput(processedDir);
}
}

context.setParserConfigurator(parserConfigurator);
return context;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/*
* 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.plugins.site.render;

import java.io.Closeable;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import org.apache.maven.doxia.parser.Parser;
import org.apache.maven.doxia.siterenderer.ParserConfigurator;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
import org.codehaus.plexus.component.configurator.ComponentConfigurator;
import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.configuration.PlexusConfiguration;

/**
* Configures a parser based on a {@link PlexusConfiguration} for a particular parser id and optionally matching one of multiple patterns.
* It internally leverages the {@link ComponentConfigurator} for calling the right methods inside the parser implementation.
*/
public class ParserConfiguratorImpl implements ParserConfigurator, Closeable {

private static final class ParserConfigurationKey {

ParserConfigurationKey(String parserId, PlexusConfiguration patternsConfiguration) {
this(parserId, PlexusConfigurationUtils.getStringArrayValues(patternsConfiguration));
}

ParserConfigurationKey(String parserId, Collection<String> patterns) {
this.parserId = parserId;
// lazily populate all matchers
matchers = patterns.stream()
.map(p -> FileSystems.getDefault().getPathMatcher(p))
.collect(Collectors.toList());
}

private final String parserId;

/**
* List of {@link PathMatcher}s for all of the patterns passed to the constructor
*/
private List<PathMatcher> matchers;

/**
* Returns {@code true} the given file path matches one of the {@link #patterns} given via {@link #addPattern(String)}
* @param filePath the file path to check
* @return {@code true} if the given file path matches at least one of the patterns, {@code false} otherwise.
* @throws IllegalArgumentException
* If one of the patterns does not comply with the form: {@code syntax:pattern}
* @throws java.util.regex.PatternSyntaxException
* If one of the regex patterns is invalid
* @throws UnsupportedOperationException
* If one of the patterns syntax prefix is not known to the implementation
* @see FileSystem#getPathMatcher(String)
*/
public boolean matches(String parserId, Path filePath) {
if (this.parserId.equals(parserId)) {
return false;
}
if (matchers.isEmpty()) {
return true; // no patterns mean always match
}
return matchers.stream().anyMatch(m -> m.matches(filePath));
}
}

private final org.codehaus.plexus.classworlds.realm.ClassRealm pluginClassRealm;
private final PlexusContainer plexusContainer;
private final ComponentConfigurator componentConfigurator;

private final Map<ParserConfigurationKey, PlexusConfiguration> parserConfigurations;

public ParserConfiguratorImpl(
Map<String, List<PlexusConfiguration>> parserConfigurations,
PlexusContainer plexusContainer,
MojoDescriptor mojoDescriptor)
throws ComponentLookupException {
this.parserConfigurations = new LinkedHashMap<>();
for (Map.Entry<String, List<PlexusConfiguration>> parserConfigurationPerId : parserConfigurations.entrySet()) {
String parserId = parserConfigurationPerId.getKey();
for (PlexusConfiguration configuration : parserConfigurationPerId.getValue()) {
ParserConfigurationKey key = new ParserConfigurationKey(parserId, configuration.getChild("patterns"));
this.parserConfigurations.put(key, configuration);
}
}
pluginClassRealm = mojoDescriptor.getRealm();
this.plexusContainer = plexusContainer;
componentConfigurator = getComponentConfigurator(mojoDescriptor.getComponentConfigurator());
}

ComponentConfigurator getComponentConfigurator(String configuratorId) throws ComponentLookupException {
// logic copied from
// https://github.com/apache/maven/blob/267de063eec17111688fd1a27d4e3aae6c8d0c51/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java#L696C9-L700C10
if (configuratorId == null || configuratorId.isEmpty()) {
configuratorId = "basic"; // TODO: support v4
}
return plexusContainer.lookup(ComponentConfigurator.class, configuratorId);
}

public void configureParser(PlexusConfiguration configuration, Parser parser)
throws ComponentConfigurationException {
componentConfigurator.configureComponent(parser, configuration, pluginClassRealm);
}

@Override
public void close() throws IOException {
try {
plexusContainer.release(componentConfigurator);
} catch (ComponentLifecycleException e) {
throw new IOException(e);
}
}

@Override
public boolean configure(String parserId, Path filePath, Parser parser) {
Optional<PlexusConfiguration> config = parserConfigurations.entrySet().stream()
.filter(c -> c.getKey().matches(parserId, filePath))
.findFirst()
.map(Map.Entry::getValue);
config.ifPresent(c -> {
try {
configureParser(c, parser);
} catch (ComponentConfigurationException e) {
throw new IllegalStateException("Could not configure parser " + parser + " due to ", e);
}
});
return config.isPresent();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* 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.plugins.site.render;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.codehaus.plexus.configuration.PlexusConfiguration;

public class PlexusConfigurationUtils {

private PlexusConfigurationUtils() {
// not supposed to be instantiated
}

/**
* Retrieves all string values from the children of the given {@link PlexusConfiguration}
* @param arrayContainer the configuration containing the array container (may be {@code null})
* @return the list of string values
*/
static List<String> getStringArrayValues(PlexusConfiguration arrayContainer) {
if (arrayContainer == null) {
return Collections.emptyList();
}
List<String> stringValues = new ArrayList<>();
for (PlexusConfiguration item : arrayContainer.getChildren()) {
stringValues.add(item.getValue());
}
return stringValues;
}
}
16 changes: 12 additions & 4 deletions src/main/java/org/apache/maven/plugins/site/render/SiteMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

import org.apache.maven.doxia.siterenderer.DocumentRenderer;
import org.apache.maven.doxia.siterenderer.DoxiaDocumentRenderer;
import org.apache.maven.doxia.siterenderer.ParserConfigurator;
import org.apache.maven.doxia.siterenderer.RendererException;
import org.apache.maven.doxia.siterenderer.SiteRenderingContext;
import org.apache.maven.doxia.tools.SiteTool;
Expand All @@ -42,6 +43,7 @@
import org.apache.maven.reporting.MavenReportException;
import org.apache.maven.reporting.exec.MavenReportExecution;
import org.apache.maven.shared.utils.logging.MessageBuilder;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;

import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;

Expand Down Expand Up @@ -94,7 +96,7 @@ public void execute() throws MojoExecutionException, MojoFailureException {

checkInputEncoding();

try {
try (ParserConfiguratorImpl parserConfigurator = createParserConfigurator()) {
List<Locale> localesList = getLocales();

for (Locale locale : localesList) {
Expand All @@ -107,7 +109,7 @@ public void execute() throws MojoExecutionException, MojoFailureException {
File outputDirectory = getOutputDirectory(locale);
List<MavenReportExecution> reports =
generateReports ? getReports(outputDirectory) : Collections.emptyList();
renderLocale(locale, reports, localesList, outputDirectory);
renderLocale(locale, reports, localesList, outputDirectory, parserConfigurator);
}
} catch (RendererException e) {
if (e.getCause() instanceof MavenReportException) {
Expand All @@ -117,13 +119,19 @@ public void execute() throws MojoExecutionException, MojoFailureException {
throw new MojoExecutionException("Failed to render reports", e);
} catch (IOException e) {
throw new MojoExecutionException("Error during site generation", e);
} catch (ComponentLookupException e) {
throw new MojoExecutionException("Cannot lookup ComponentConfigurator for configuration of parsers", e);
}
}

private void renderLocale(
Locale locale, List<MavenReportExecution> reports, List<Locale> supportedLocales, File outputDirectory)
Locale locale,
List<MavenReportExecution> reports,
List<Locale> supportedLocales,
File outputDirectory,
ParserConfigurator parserConfigurator)
throws IOException, RendererException, MojoFailureException, MojoExecutionException {
SiteRenderingContext context = createSiteRenderingContext(locale);
SiteRenderingContext context = createSiteRenderingContext(locale, parserConfigurator);
context.addSiteLocales(supportedLocales);
if (!locale.equals(SiteTool.DEFAULT_LOCALE)) {
context.addSiteDirectory(new File(generatedSiteDirectory, locale.toString()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.plugins.site.render.AbstractSiteRenderingMojo;
import org.apache.maven.plugins.site.render.ParserConfiguratorImpl;
import org.apache.maven.reporting.exec.MavenReportExecution;
import org.codehaus.plexus.util.IOUtil;
import org.eclipse.jetty.server.Server;
Expand Down Expand Up @@ -125,15 +126,15 @@ private WebAppContext createWebApplication() throws MojoExecutionException {
List<Locale> localesList = getLocales();
webapp.setAttribute(DoxiaFilter.LOCALES_LIST_KEY, localesList);

try {
try (ParserConfiguratorImpl parserConfigurator = createParserConfigurator()) {
Map<String, DoxiaBean> i18nDoxiaContexts = new HashMap<>();

for (Locale locale : localesList) {
SiteRenderingContext i18nContext = createSiteRenderingContext(locale);
SiteRenderingContext i18nContext = createSiteRenderingContext(locale, parserConfigurator);
i18nContext.setInputEncoding(getInputEncoding());
i18nContext.setOutputEncoding(getOutputEncoding());

SiteRenderingContext i18nGeneratedSiteContext = createSiteRenderingContext(locale);
SiteRenderingContext i18nGeneratedSiteContext = createSiteRenderingContext(locale, parserConfigurator);
i18nGeneratedSiteContext.setInputEncoding(getInputEncoding());
i18nGeneratedSiteContext.setOutputEncoding(getOutputEncoding());
i18nGeneratedSiteContext.getSiteDirectories().clear();
Expand Down

0 comments on commit 614a057

Please sign in to comment.