ValidateMojo.java
package com.github.jonasrutishauser.cdi.maven.plugin;
/*
* Copyright (C) 2017 Jonas Rutishauser
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/lgpl-3.0.txt>.
*/
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.inject.Inject;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResult;
import org.apache.maven.shared.transfer.dependencies.resolve.DependencyResolver;
import org.apache.maven.shared.transfer.dependencies.resolve.DependencyResolverException;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
import org.jboss.weld.bootstrap.WeldBootstrap;
import org.jboss.weld.bootstrap.api.CDI11Bootstrap;
import org.jboss.weld.bootstrap.api.Environments;
import com.github.jonasrutishauser.cdi.maven.plugin.ear.EarUtil;
import com.github.jonasrutishauser.cdi.maven.plugin.war.WarUtil;
/**
* Validates the CDI configuration of a war or ear.
*
* @author Jonas Rutishauser
*/
@Mojo(name = "validate", defaultPhase = LifecyclePhase.VERIFY, requiresProject = true, threadSafe = true)
public class ValidateMojo extends AbstractMojo {
private static final String SMALLRYE_GROUP_ID = "io.smallrye";
private final MavenSession session;
private final MavenProject project;
private final ArchiverManager archiverManager;
private final DependencyResolver dependencyResolver;
private final Map<String, String> oldSystemProperties = new HashMap<>();
@Parameter(defaultValue = "${project.build.directory}/cdi", readonly = true)
private File workDirectory;
@Parameter
private Map<String, String> systemProperties = new HashMap<>();
@Parameter
private boolean microprofile = false;
@Inject
public ValidateMojo(MavenSession session, MavenProject project, ArchiverManager archiverManager,
DependencyResolver dependencyResolver) {
this.session = session;
this.project = project;
this.archiverManager = archiverManager;
this.dependencyResolver = dependencyResolver;
}
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
fixCdiApiInClassloader();
ArchiveUtil util;
if ("ear".equals(project.getPackaging())) {
util = new EarUtil(archiverManager);
} else if ("war".equals(project.getPackaging())) {
util = new WarUtil(archiverManager);
} else {
return;
}
try {
util.init(workDirectory, project.getArtifact().getFile(), getParentClassLoader());
} catch (MalformedURLException e) {
throw new MojoExecutionException("failed to load ear", e);
}
systemProperties.forEach((key, value) -> oldSystemProperties.put(key, System.setProperty(key, value)));
oldSystemProperties.put("org.jboss.logging.provider",
System.setProperty("org.jboss.logging.provider", "slf4j"));
CDI11Bootstrap bootstrap = new WeldBootstrap();
ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(util.getClassLoader());
bootstrap.startContainer(UUID.randomUUID().toString(), Environments.EE, util.createDeployment(bootstrap));
bootstrap.startInitialization();
bootstrap.deployBeans();
bootstrap.validateBeans();
bootstrap.endInitialization();
} catch (Exception e) {
throw new MojoFailureException("CDI error found: " + e.getMessage(), e);
} finally {
Thread.currentThread().setContextClassLoader(oldContextClassLoader);
bootstrap.shutdown();
oldSystemProperties.forEach((key, value) -> {
if (value == null) {
System.clearProperty(key);
} else {
System.setProperty(key, value);
}
});
}
}
private void fixCdiApiInClassloader() {
if (getClass().getClassLoader() instanceof ClassRealm) {
ClassRealm ownRealm = (ClassRealm) getClass().getClassLoader();
if (ownRealm.getImportClassLoader("javax.enterprise.inject") instanceof ClassRealm) {
ownRealm.importFrom(new EmptyClassLoader(), "javax.enterprise.inject");
}
}
}
private ClassLoader getParentClassLoader() throws MojoExecutionException {
if (microprofile) {
List<URL> urls = new ArrayList<>();
try {
List<Dependency> managedDependencies = project.getDependencyManagement() == null ? new ArrayList<>() : project.getDependencyManagement().getDependencies();
for (ArtifactResult resolved : dependencyResolver.resolveDependencies(
session.getProjectBuildingRequest(), getMicroprofileImplementations(),
managedDependencies, null)) {
urls.add(resolved.getArtifact().getFile().toURI().toURL());
}
} catch (DependencyResolverException | MalformedURLException e) {
throw new MojoExecutionException("Failed to retrieve microprofile dependencies", e);
}
return new URLClassLoader(urls.toArray(new URL[urls.size()]), getClass().getClassLoader());
}
return getClass().getClassLoader();
}
private Collection<Dependency> getMicroprofileImplementations() {
Collection<Dependency> implementations = new ArrayList<>();
Dependency configImpl = new Dependency();
configImpl.setGroupId(SMALLRYE_GROUP_ID);
configImpl.setArtifactId("smallrye-config");
configImpl.setVersion("1.5.0");
implementations.add(configImpl);
Dependency faultToleranceApi = new Dependency();
faultToleranceApi.setGroupId("org.eclipse.microprofile.fault-tolerance");
faultToleranceApi.setArtifactId("microprofile-fault-tolerance-api");
faultToleranceApi.setVersion("2.1.1");
implementations.add(faultToleranceApi);
Dependency healthApi = new Dependency();
healthApi.setGroupId("org.eclipse.microprofile.health");
healthApi.setArtifactId("microprofile-health-api");
healthApi.setVersion("2.2");
implementations.add(healthApi);
Dependency metricsApi = new Dependency();
metricsApi.setGroupId("org.eclipse.microprofile.metrics");
metricsApi.setArtifactId("microprofile-metrics-api");
metricsApi.setVersion("2.3");
implementations.add(metricsApi);
Dependency metricsImpl = new Dependency();
metricsImpl.setGroupId(SMALLRYE_GROUP_ID);
metricsImpl.setArtifactId("smallrye-metrics");
metricsImpl.setVersion("2.4.2");
implementations.add(metricsImpl);
Dependency jwtImpl = new Dependency();
jwtImpl.setGroupId(SMALLRYE_GROUP_ID);
jwtImpl.setArtifactId("smallrye-jwt");
jwtImpl.setVersion("2.2.0");
implementations.add(jwtImpl);
Dependency restClientImpl = new Dependency();
restClientImpl.setGroupId(SMALLRYE_GROUP_ID);
restClientImpl.setArtifactId("smallrye-rest-client");
restClientImpl.setVersion("1.2.2");
implementations.add(restClientImpl);
return implementations;
}
}