001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2015 ForgeRock AS. 025 */ 026package org.forgerock.opendj.maven.doc; 027 028import static org.forgerock.opendj.maven.doc.Utils.*; 029 030import com.thoughtworks.qdox.JavaProjectBuilder; 031import com.thoughtworks.qdox.model.JavaClass; 032import com.thoughtworks.qdox.model.JavaField; 033import com.thoughtworks.qdox.model.JavaType; 034import org.apache.maven.plugin.AbstractMojo; 035import org.apache.maven.plugin.MojoExecutionException; 036import org.apache.maven.plugin.MojoFailureException; 037import org.apache.maven.plugins.annotations.LifecyclePhase; 038import org.apache.maven.plugins.annotations.Mojo; 039import org.apache.maven.plugins.annotations.Parameter; 040import org.forgerock.opendj.ldap.ResultCode; 041 042import java.io.File; 043import java.io.IOException; 044import java.text.SimpleDateFormat; 045import java.util.Date; 046import java.util.HashMap; 047import java.util.LinkedList; 048import java.util.List; 049import java.util.Map; 050 051/** 052 * Generates documentation source for LDAP result codes based on 053 * {@code org.forgerock.opendj.ldap.ResultCode}. 054 * <br> 055 * This implementation parses the source to match Javadoc comments with result codes. 056 * It is assumed that the class's ResultCode fields are named with result code enum values, 057 * and that those fields have Javadoc comments describing each result code. 058 */ 059@Mojo(name = "generate-result-code-doc", defaultPhase = LifecyclePhase.COMPILE) 060public class GenerateResultCodeDocMojo extends AbstractMojo { 061 /** 062 * The Java file containing the source of the ResultCode class, 063 * {@code org.forgerock.opendj.ldap.ResultCode}. 064 * <br> 065 * For example, {@code opendj-core/src/main/java/org/forgerock/opendj/ldap/ResultCode.java}. 066 */ 067 @Parameter(required = true) 068 private File resultCodeSource; 069 070 /** The XML file to generate. */ 071 @Parameter(required = true) 072 private File xmlFile; 073 074 /** 075 * Generates documentation source for LDAP result codes. 076 * 077 * @throws MojoExecutionException Generation failed 078 * @throws MojoFailureException Not used 079 */ 080 @Override 081 public void execute() throws MojoExecutionException, MojoFailureException { 082 final Map<String, Object> map = new HashMap<>(); 083 map.put("year", new SimpleDateFormat("yyyy").format(new Date())); 084 085 // The overall explanation in the generated doc is the class comment. 086 final JavaClass resultCodeClass; 087 try { 088 resultCodeClass = getJavaClass(); 089 } catch (IOException e) { 090 throw new MojoExecutionException("Could not read " + resultCodeSource.getPath(), e); 091 } 092 map.put("classComment", cleanComment(resultCodeClass.getComment())); 093 094 // Documentation for each result code comes from the Javadoc for the code, 095 // and from the value and friendly name of the code. 096 final Map<String, Object> comments = new HashMap<>(); 097 for (final JavaField field : resultCodeClass.getFields()) { 098 final JavaType type = field.getType(); 099 if (type.getValue().equals("ResultCode")) { 100 comments.put(field.getName(), cleanComment(field.getComment())); 101 } 102 } 103 map.put("resultCodes", getResultCodesDoc(comments)); 104 105 final String template = "appendix-ldap-result-codes.ftl"; 106 try { 107 writeStringToFile(applyTemplate(template, map), xmlFile); 108 } catch (IOException e) { 109 throw new MojoExecutionException("Could not write to " + xmlFile.getPath(), e); 110 } 111 getLog().info("Wrote " + xmlFile.getPath()); 112 } 113 114 /** 115 * Returns an object to access to the result code Java source. 116 * @return An object to access to the result code Java source. 117 * @throws IOException Could not read the source 118 */ 119 private JavaClass getJavaClass() throws IOException { 120 final JavaProjectBuilder builder = new JavaProjectBuilder(); 121 builder.addSource(resultCodeSource); 122 return builder.getClassByName("org.forgerock.opendj.ldap.ResultCode"); 123 } 124 125 /** 126 * Returns a clean string for use in generated documentation. 127 * @param comment The comment to clean. 128 * @return A clean string for use in generated documentation. 129 */ 130 private String cleanComment(String comment) { 131 return stripCodeValueSentences(stripTags(convertLineSeparators(comment))).trim(); 132 } 133 134 /** 135 * Returns a string with line separators converted to spaces. 136 * @param string The string to convert. 137 * @return A string with line separators converted to spaces. 138 */ 139 private String convertLineSeparators(String string) { 140 return string.replaceAll(System.lineSeparator(), " "); 141 } 142 143 /** 144 * Returns a string with the HTML tags removed. 145 * @param string The string to strip. 146 * @return A string with the HTML tags removed. 147 */ 148 private String stripTags(String string) { 149 return string.replaceAll("<[^>]*>", ""); 150 } 151 152 /** 153 * Returns a string with lines sentences of the following form removed: 154 * This result code corresponds to the LDAP result code value of {@code 0}. 155 * @param string The string to strip. 156 * @return A string with lines sentences of the matching form removed. 157 */ 158 private String stripCodeValueSentences(String string) { 159 return string 160 .replaceAll("This result code corresponds to the LDAP result code value of \\{@code \\d+\\}.", ""); 161 } 162 163 /** 164 * Returns a list of documentation objects for all result codes. 165 * @param comments A map of field names to the clean comments. 166 * @return A list of documentation objects for all result codes. 167 */ 168 private List<Map<String, Object>> getResultCodesDoc(Map<String, Object> comments) { 169 final List<Map<String, Object>> list = new LinkedList<>(); 170 if (comments == null || comments.isEmpty()) { 171 return list; 172 } 173 174 for (ResultCode resultCode : ResultCode.values()) { 175 final Map<String, Object> doc = new HashMap<>(); 176 doc.put("intValue", resultCode.intValue()); 177 doc.put("name", resultCode.getName()); 178 final Object comment = comments.get(resultCode.asEnum().toString()); 179 doc.put("comment", comment); 180 list.add(doc); 181 } 182 return list; 183 } 184}