com.ly.doc.plugin.mojo.BaseDocsGeneratorMojo Maven / Gradle / Ivy
/*
* smart-doc
*
* Copyright (C) 2018-2023 smart-doc
*
* 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 com.ly.doc.plugin.mojo;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
import com.ly.doc.plugin.util.ArtifactFilterUtil;
import com.ly.doc.plugin.util.ClassLoaderUtil;
import com.ly.doc.plugin.util.FileUtil;
import com.ly.doc.plugin.util.MojoUtils;
import com.power.common.constants.Charset;
import com.power.common.util.CollectionUtil;
import com.power.common.util.DateTimeUtil;
import com.power.common.util.RegexUtil;
import com.power.common.util.StringUtil;
import com.ly.doc.helper.JavaProjectBuilderHelper;
import com.ly.doc.model.ApiConfig;
import com.ly.doc.plugin.constant.GlobalConstants;
import com.ly.doc.plugin.constant.MojoConstants;
import com.thoughtworks.qdox.JavaProjectBuilder;
import com.thoughtworks.qdox.library.SortedClassLibraryBuilder;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.DefaultProjectBuildingRequest;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuilder;
import org.apache.maven.project.ProjectBuildingRequest;
import org.apache.maven.repository.RepositorySystem;
import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
import org.apache.maven.shared.dependency.graph.DependencyNode;
/**
* reference https://github.com/jboz/living-documentation
* @author yu 2020/1/8.
*/
public abstract class BaseDocsGeneratorMojo extends AbstractMojo {
@Parameter(defaultValue = "${project}", readonly = true, required = true)
protected MavenProject project;
@Component
protected RepositorySystem repositorySystem;
protected JavaProjectBuilder javaProjectBuilder;
@Component(role = org.apache.maven.project.ProjectBuilder.class)
protected ProjectBuilder projectBuilder;
@Parameter(defaultValue = "${localRepository}", required = true, readonly = true)
private ArtifactRepository localRepository;
@Parameter(defaultValue = "${session}", readonly = true, required = true)
private MavenSession session;
@Parameter(defaultValue = "${reactorProjects}", readonly = true, required = true)
private List reactorProjects;
@Component(hint = "default")
private DependencyGraphBuilder dependencyGraphBuilder;
@Parameter(property = "scope")
private String scope;
@Parameter(property = "configFile", defaultValue = GlobalConstants.DEFAULT_CONFIG)
private File configFile;
@Parameter(property = "projectName")
private String projectName;
@Parameter(required = false)
private Set excludes;
@Parameter(required = false)
private Set includes;
@Parameter(property = "skip")
private String skip;
@Parameter(property = "increment")
private Boolean increment;
@Parameter(defaultValue = "${mojoExecution}")
private MojoExecution mojoEx;
private DependencyNode rootNode;
private List projectArtifacts;
@Parameter(defaultValue = "${tornaToken}")
private String tornaToken;
public abstract void executeMojo(ApiConfig apiConfig, JavaProjectBuilder javaProjectBuilder)
throws MojoExecutionException, MojoFailureException;
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
//skip
if ("true".equals(skip)) {
return;
}
if (Objects.nonNull(configFile) && !configFile.exists()) {
// Throwing an exception will cause an error in the multi-module maven project build.
this.getLog().warn("Can't find config file: " + configFile.getName() + " from [" + project.getName()
+ "],If it is a non-web module, please ignore the error.");
return;
}
this.getLog().info("------------------------------------------------------------------------");
this.getLog().info("Smart-doc Start preparing sources at: " + DateTimeUtil.nowStrTime());
projectArtifacts = project.getArtifacts().stream().map(moduleName -> moduleName.getGroupId() + ":" + moduleName.getArtifactId())
.collect(Collectors.toList());
ApiConfig apiConfig = MojoUtils.buildConfig(configFile, projectName, project, projectBuilder, session, projectArtifacts, increment, getLog());
if (Objects.isNull(apiConfig)) {
this.getLog().info(GlobalConstants.ERROR_MSG);
return;
}
if (StringUtil.isNotEmpty(tornaToken)) {
apiConfig.setAppToken(tornaToken);
}
javaProjectBuilder = buildJavaProjectBuilder(apiConfig.getCodePath());
javaProjectBuilder.setEncoding(Charset.DEFAULT_CHARSET);
String rpcConsumerConfig = apiConfig.getRpcConsumerConfig();
if (!FileUtil.isAbsPath(rpcConsumerConfig) && StringUtil.isNotEmpty(rpcConsumerConfig)) {
apiConfig.setRpcConsumerConfig(project.getBasedir().getPath() + "/" + rpcConsumerConfig);
}
String goal = mojoEx.getGoal();
String outPath = apiConfig.getOutPath();
if (StringUtil.isEmpty(outPath)) {
if (!MojoConstants.TORNA_REST_MOJO.equals(goal) && !MojoConstants.TORNA_RPC_MOJO.equals(goal)) {
this.getLog().error("Smart-doc out path can't be null or empty.");
throw new RuntimeException("Smart-doc out path can't be null or empty.");
}
}
if (!FileUtil.isAbsPath(outPath) && StringUtil.isNotEmpty(outPath)) {
apiConfig.setOutPath(project.getBasedir().getPath() + "/" + outPath);
}
getLog().info("Smart-doc Starting Create API Documentation at: " + DateTimeUtil.nowStrTime());
if (!MojoConstants.TORNA_RPC_MOJO.equals(goal) && !MojoConstants.TORNA_REST_MOJO.equals(goal)) {
getLog().info("API documentation is output to => " + apiConfig.getOutPath().replace("\\", "/"));
}
this.executeMojo(apiConfig, javaProjectBuilder);
}
/**
* Classloading
*/
private JavaProjectBuilder buildJavaProjectBuilder(String codePath) throws MojoExecutionException {
SortedClassLibraryBuilder classLibraryBuilder = new SortedClassLibraryBuilder();
classLibraryBuilder.setErrorHander(e -> getLog().error("Parse error", e));
JavaProjectBuilder javaDocBuilder = JavaProjectBuilderHelper.create(classLibraryBuilder);
javaDocBuilder.setEncoding(Charset.DEFAULT_CHARSET);
javaDocBuilder.setErrorHandler(e -> getLog().warn(e.getMessage()));
//addSourceTree
javaDocBuilder.addSourceTree(new File(codePath));
javaDocBuilder.addClassLoader(ClassLoaderUtil.getRuntimeClassLoader(project));
loadSourcesDependencies(javaDocBuilder);
return javaDocBuilder;
}
/**
* load sources
*/
private void loadSourcesDependencies(JavaProjectBuilder javaDocBuilder) throws MojoExecutionException {
try {
List currentProjectModules = getCurrentProjectArtifacts(this.project);
ArtifactFilter artifactFilter = this.createResolvingArtifactFilter();
ProjectBuildingRequest buildingRequest = new DefaultProjectBuildingRequest(this.session.getProjectBuildingRequest());
buildingRequest.setProject(this.project);
this.rootNode = this.dependencyGraphBuilder.buildDependencyGraph(buildingRequest, artifactFilter);
List dependencyNodes = this.rootNode.getChildren();
List artifactList = this.getArtifacts(dependencyNodes);
artifactList.forEach(artifact -> {
if (ArtifactFilterUtil.ignoreSpringBootArtifactById(artifact)) {
return;
}
String artifactName = artifact.getGroupId() + ":" + artifact.getArtifactId();
if (currentProjectModules.contains(artifactName)) {
this.projectArtifacts.add(artifactName);
return;
}
if (RegexUtil.isMatches(excludes, artifactName)) {
return;
}
Artifact sourcesArtifact = repositorySystem.createArtifactWithClassifier(artifact.getGroupId(),
artifact.getArtifactId(), artifact.getVersion(), artifact.getType(), "sources");
if (RegexUtil.isMatches(includes, artifactName)) {
this.projectArtifacts.add(artifactName);
this.loadSourcesDependency(javaDocBuilder, sourcesArtifact);
return;
}
if (CollectionUtil.isEmpty(includes)) {
this.projectArtifacts.add(artifactName);
this.loadSourcesDependency(javaDocBuilder, sourcesArtifact);
}
});
} catch (DependencyGraphBuilderException e) {
throw new MojoExecutionException("Can't build project dependency graph", e);
}
}
/**
* reference https://github.com/jboz/living-documentation
*
* @param javaDocBuilder JavaProjectBuilder
* @param sourcesArtifact Artifact
*/
private void loadSourcesDependency(JavaProjectBuilder javaDocBuilder, Artifact sourcesArtifact) {
String artifactName = sourcesArtifact.getGroupId() + ":" + sourcesArtifact.getArtifactId();
getLog().debug("smart-doc loaded artifact:" + artifactName);
// create request
ArtifactResolutionRequest request = new ArtifactResolutionRequest();
request.setArtifact(sourcesArtifact);
//request.setResolveTransitively(true);
request.setRemoteRepositories(project.getRemoteArtifactRepositories());
// resolve dependencies
ArtifactResolutionResult result = repositorySystem.resolve(request);
// load java source file into javadoc builder
result.getArtifacts().forEach(artifact -> {
JarFile jarFile;
String sourceURL;
try {
sourceURL = artifact.getFile().toURI().toURL().toString();
if (getLog().isDebugEnabled()) {
getLog().debug("smart-doc loaded jar source:" + sourceURL);
}
jarFile = new JarFile(artifact.getFile());
} catch (IOException e) {
getLog().warn("Unable to load jar source " + artifact + " : " + e.getMessage());
return;
}
for (Enumeration> entries = jarFile.entries(); entries.hasMoreElements(); ) {
JarEntry entry = (JarEntry) entries.nextElement();
String name = entry.getName();
try {
if (name.endsWith(".java") && !name.endsWith("/package-info.java")) {
String uri = "jar:" + sourceURL + "!/" + name;
if (getLog().isDebugEnabled()) {
getLog().debug(uri);
}
javaDocBuilder.addSource(new URL(uri));
}
} catch (Throwable e) {
getLog().warn("syntax error in jar :" + sourceURL);
getLog().warn(e.getMessage());
}
}
});
}
/**
* copy from maven-dependency-plugin tree TreeMojo.java
*
* @return ArtifactFilter
*/
private ArtifactFilter createResolvingArtifactFilter() {
ScopeArtifactFilter filter;
if (this.scope != null) {
this.getLog().debug("+ Resolving dependency tree for scope '" + this.scope + "'");
filter = new ScopeArtifactFilter(this.scope);
} else {
filter = null;
}
return filter;
}
private List getArtifacts(List dependencyNodes) {
List artifacts = new ArrayList<>();
if (CollectionUtil.isEmpty(dependencyNodes)) {
return artifacts;
}
for (DependencyNode dependencyNode : dependencyNodes) {
if (ArtifactFilterUtil.ignoreArtifact(dependencyNode.getArtifact())) {
continue;
}
artifacts.add(dependencyNode.getArtifact());
if (dependencyNode.getChildren().size() > 0) {
artifacts.addAll(getArtifacts(dependencyNode.getChildren()));
}
}
return artifacts;
}
private List getCurrentProjectArtifacts(MavenProject project) {
if (!project.hasParent()) {
return new ArrayList<>(0);
}
List finalArtifactsName = new ArrayList<>();
MavenProject mavenProject = project.getParent();
if (Objects.nonNull(mavenProject)) {
File file = mavenProject.getBasedir();
if (!Objects.isNull(file)) {
String groupId = mavenProject.getGroupId();
List moduleList = mavenProject.getModules();
moduleList.forEach(str -> finalArtifactsName.add(groupId + ":" + str));
}
}
return finalArtifactsName;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy