001package ball.maven.plugins.javadoc; 002/*- 003 * ########################################################################## 004 * Javadoc Maven Plugin 005 * %% 006 * Copyright (C) 2021, 2022 Allen D. Ball 007 * %% 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 * ########################################################################## 020 */ 021import java.io.File; 022import java.io.IOException; 023import java.io.InputStream; 024import java.io.PrintWriter; 025import java.net.URL; 026import java.nio.file.Files; 027import java.nio.file.Path; 028import java.util.List; 029import java.util.Map; 030import java.util.Set; 031import java.util.jar.JarEntry; 032import java.util.jar.JarFile; 033import java.util.regex.Pattern; 034import javax.inject.Inject; 035import lombok.NoArgsConstructor; 036import lombok.ToString; 037import lombok.extern.slf4j.Slf4j; 038import org.apache.maven.artifact.Artifact; 039import org.apache.maven.artifact.ArtifactUtils; 040import org.apache.maven.plugin.MojoExecutionException; 041import org.apache.maven.plugin.MojoFailureException; 042import org.apache.maven.plugins.annotations.Mojo; 043import org.apache.maven.plugins.annotations.Parameter; 044import org.apache.maven.project.MavenProject; 045 046import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; 047import static java.nio.file.StandardOpenOption.CREATE; 048import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; 049import static java.nio.file.StandardOpenOption.WRITE; 050import static java.util.stream.Collectors.groupingBy; 051import static java.util.stream.Collectors.mapping; 052import static java.util.stream.Collectors.toList; 053import static org.apache.maven.plugins.annotations.LifecyclePhase.GENERATE_SOURCES; 054import static org.apache.maven.plugins.annotations.ResolutionScope.RUNTIME; 055 056/** 057 * {@link org.apache.maven.plugin.Mojo} to generate javadoc options file for 058 * {@code maven-javadoc-plugin}. 059 * 060 * {@injected.fields} 061 * 062 * {@maven.plugin.fields} 063 * 064 * {@bean.info} 065 * 066 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball} 067 */ 068@Mojo(name = "generate-options-file", requiresDependencyResolution = RUNTIME, 069 defaultPhase = GENERATE_SOURCES, requiresProject = true) 070@NoArgsConstructor @ToString @Slf4j 071public class GenerateOptionsFileMojo extends AbstractJavadocMojo { 072 private static final Pattern JAR_ENTRY_PATTERN = Pattern.compile("^(package|element)[^-]*-list$"); 073 074 @Parameter(property = "outputDirectory", defaultValue = "${project.build.directory}/javadoc-options") 075 private File outputDirectory = null; 076 077 @Parameter(defaultValue = "false", property = "includeDependencyManagement") 078 private boolean includeDependencyManagement = false; 079 080 @Parameter(property = "doclet") 081 private String doclet = null; 082 083 @Inject private MavenProject project = null; 084 085 @Override 086 public void execute() throws MojoExecutionException, MojoFailureException { 087 super.execute(); 088 089 try { 090 if (! isSkip()) { 091 Set<URL> set = getLinkSet(project, includeDependencyManagement); 092 Map<URL,List<Artifact>> map = 093 getResolvedOfflinelinkMap(project, includeDependencyManagement).entrySet().stream() 094 .collect(groupingBy(Map.Entry::getValue, mapping(Map.Entry::getKey, toList()))); 095 096 set.removeAll(map.keySet()); 097 098 generateOutput(set, map); 099 } else { 100 log.info("Skipping javadoc options file generation."); 101 } 102 } catch (Throwable throwable) { 103 log.error("{}", throwable.getMessage(), throwable); 104 105 if (throwable instanceof MojoExecutionException) { 106 throw (MojoExecutionException) throwable; 107 } else if (throwable instanceof MojoFailureException) { 108 throw (MojoFailureException) throwable; 109 } else { 110 throw new MojoExecutionException(throwable.getMessage(), throwable); 111 } 112 } 113 } 114 115 private void generateOutput(Set<URL> set, Map<URL,List<Artifact>> map) throws IOException { 116 Path parent = outputDirectory.toPath(); 117 118 Files.createDirectories(parent); 119 120 Path options = parent.resolve("options"); 121 122 try (PrintWriter out = new PrintWriter(Files.newBufferedWriter(options, CREATE, WRITE, TRUNCATE_EXISTING))) { 123 if (doclet != null) { 124 out.println("-doclet"); 125 out.println(doclet); 126 } 127 128 for (URL url : set) { 129 out.println("-link"); 130 out.println(url); 131 } 132 133 for (Map.Entry<URL,List<Artifact>> entry : map.entrySet()) { 134 List<Artifact> artifacts = entry.getValue(); 135 136 for (Artifact artifact : artifacts) { 137 Path location = parent.resolve(ArtifactUtils.versionlessKey(artifact)); 138 139 Files.createDirectories(location); 140 141 try (JarFile jar = new JarFile(artifact.getFile())) { 142 List<JarEntry> entries = 143 jar.stream() 144 .filter(t -> JAR_ENTRY_PATTERN.matcher(t.getName()).matches()) 145 .collect(toList()); 146 147 if (! entries.isEmpty()) { 148 for (JarEntry jarEntry : entries) { 149 try (InputStream in = jar.getInputStream(jarEntry)) { 150 Files.copy(in, location.resolve(jarEntry.getName()), REPLACE_EXISTING); 151 } 152 } 153 154 Path packageList = location.resolve("package-list"); 155 Path elementList = location.resolve("element-list"); 156 157 if (! Files.exists(packageList)) { 158 Files.copy(elementList, packageList); 159 } else if (! Files.exists(elementList)) { 160 Files.copy(packageList, elementList); 161 } 162 163 out.println("-linkoffline"); 164 out.println(entry.getKey()); 165 out.println(location); 166 } else { 167 log.warn("{}: Location directory is empty; skipping...", location); 168 } 169 } 170 } 171 } 172 } 173 } 174}