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 * Copyright 2015 ForgeRock AS. 024 */ 025package org.forgerock.opendj.maven.doc; 026 027import static org.forgerock.opendj.maven.doc.DocsMessages.*; 028import static org.forgerock.opendj.maven.doc.Utils.applyTemplate; 029import static org.forgerock.opendj.maven.doc.Utils.writeStringToFile; 030import org.apache.maven.plugin.AbstractMojo; 031import org.apache.maven.plugin.MojoExecutionException; 032import org.apache.maven.plugin.MojoFailureException; 033import org.apache.maven.plugins.annotations.Mojo; 034import org.apache.maven.plugins.annotations.Parameter; 035import org.forgerock.opendj.ldap.DN; 036import org.forgerock.opendj.ldap.Entry; 037import org.forgerock.opendj.ldif.LDIFEntryReader; 038 039import java.io.BufferedReader; 040import java.io.File; 041import java.io.FileInputStream; 042import java.io.FileReader; 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; 050import java.util.regex.Matcher; 051import java.util.regex.Pattern; 052 053/** 054 * Generates documentation source table listing global ACIs. 055 */ 056@Mojo(name = "generate-global-acis-table") 057public class GenerateGlobalAcisTableMojo extends AbstractMojo { 058 /** The locale for which to generate the documentation. */ 059 @Parameter(defaultValue = "en") 060 private String locale; 061 062 /** The config.ldif file containing default global ACIs. **/ 063 @Parameter(defaultValue = "${basedir}/resource/config/config.ldif") 064 private File configDotLdif; 065 066 /** Output directory for source files. */ 067 @Parameter(defaultValue = "${project.build.directory}/docbkx-sources/shared") 068 private File outputDirectory; 069 070 /** Holds descriptions for ACIs. */ 071 private Map<String, String> descriptions; 072 073 /** Holds documentation for an ACI. */ 074 private class Aci { 075 String name; 076 String description; 077 String definition; 078 } 079 080 /** Holds the list of global ACIs. */ 081 private static List<Aci> allGlobalAcis = new LinkedList<>(); 082 083 /** 084 * Writes documentation source table listing global ACIs. 085 * @throws MojoExecutionException Not used. 086 * @throws MojoFailureException Failed to read ACIs or to write the table file. 087 */ 088 @Override 089 public void execute() throws MojoExecutionException, MojoFailureException { 090 try { 091 readAcis(getAciDescriptions()); 092 } catch (IOException e) { 093 throw new MojoFailureException(e.getMessage(), e); 094 } 095 096 File table = new File(outputDirectory, "table-global-acis.xml"); 097 try { 098 writeStringToFile(getGlobalAcisTable(), table); 099 } catch (IOException e) { 100 throw new MojoFailureException(e.getMessage(), e); 101 } 102 } 103 104 /** 105 * Populates map of {@code ds-cfg-global-aci} descriptions from comments in {@code config.ldif}. 106 * Keys are ACI names. Values are descriptions. 107 * <br> 108 * The format expected for ACI description comments is the following: 109 * {@code # @aci name: description}, 110 * where {@code name} matches the name embedded in the ACI, 111 * and {@code description} is a longer description. 112 * @throws IOException Failed to read the LDIF. 113 */ 114 private Map<String, String> getAciDescriptions() throws IOException { 115 final Map<String, String> descriptions = new HashMap<>(); 116 BufferedReader reader = new BufferedReader(new FileReader(configDotLdif)); 117 String line; 118 while ((line = reader.readLine()) != null) { 119 if (line.startsWith("# @aci ")) { 120 String[] split = line.replace("# @aci ", "").split(":", 2); 121 descriptions.put(split[0], split[1]); 122 } 123 } 124 return descriptions; 125 } 126 127 /** 128 * Reads {@code ds-cfg-global-aci} values from {@code config.ldif} into the list of Acis. 129 * @param descriptions Long descriptions from comments in {@code config.ldif}. 130 * Keys are ACI names. Values are descriptions. 131 * @throws IOException Failed to read the LDIF. 132 */ 133 private void readAcis(Map<String, String> descriptions) throws IOException { 134 LDIFEntryReader reader = new LDIFEntryReader(new FileInputStream(configDotLdif)); 135 reader.setIncludeBranch(DN.valueOf("cn=Access Control Handler,cn=config")); 136 137 while (reader.hasNext()) { 138 Entry entry = reader.readEntry(); 139 for (String attribute : entry.parseAttribute("ds-cfg-global-aci").asSetOfString()) { 140 Aci aci = new Aci(); 141 aci.name = getName(attribute); 142 if (descriptions != null) { 143 aci.description = descriptions.get(aci.name); 144 } 145 aci.definition = attribute; 146 allGlobalAcis.add(aci); 147 } 148 } 149 } 150 151 /** 152 * Returns the user-friendly name embedded in the ACI. 153 * @param aci The string representation of the ACI value. 154 * @return The user-friendly name embedded in the ACI, 155 * or an empty string if no name is found. 156 */ 157 private String getName(String aci) { 158 // Extract the user-friendly string in 159 // {@code ...version 3.0; acl "user-friendly name"...}. 160 Pattern pattern = Pattern.compile(".+version 3.0; ?acl \"([^\"]+)\".+"); 161 Matcher matcher = pattern.matcher(aci); 162 if (matcher.find()) { 163 return matcher.group(1); 164 } 165 return ""; 166 } 167 168 /** 169 * Returns a DocBook XML table listing global ACIs. 170 * @return A DocBook XML table listing global ACIs. 171 */ 172 private String getGlobalAcisTable() { 173 final Map<String, Object> map = new HashMap<>(); 174 map.put("year", new SimpleDateFormat("yyyy").format(new Date())); 175 map.put("lang", locale); 176 map.put("title", DOC_GLOBAL_ACIS_TABLE_TITLE.get()); 177 map.put("summary", DOC_GLOBAL_ACIS_TABLE_SUMMARY.get()); 178 map.put("nameTitle", DOC_GLOBAL_ACIS_NAME_COLUMN_TITLE.get()); 179 map.put("descTitle", DOC_GLOBAL_ACIS_DESCRIPTION_COLUMN_TITLE.get()); 180 map.put("defTitle", DOC_GLOBAL_ACIS_DEFINITION_COLUMN_TITLE.get()); 181 map.put("acis", getDefaultGlobalAciList()); 182 return applyTemplate("table-global-acis.ftl", map); 183 } 184 185 /** 186 * Returns a list of information about default global ACIs. 187 * @return A list of information about default global ACIs. 188 */ 189 private List<Map<String, Object>> getDefaultGlobalAciList() { 190 final List<Map<String, Object>> globalAciList = new LinkedList<>(); 191 for (final Aci aci : allGlobalAcis) { 192 final Map<String, Object> map = new HashMap<>(); 193 map.put("name", aci.name); 194 map.put("description", aci.description); 195 map.put("definition", aci.definition); 196 globalAciList.add(map); 197 } 198 return globalAciList; 199 } 200}