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.File;
040import java.io.FileInputStream;
041import java.io.IOException;
042import java.text.SimpleDateFormat;
043import java.util.Date;
044import java.util.HashMap;
045import java.util.LinkedList;
046import java.util.List;
047import java.util.Map;
048import java.util.regex.Matcher;
049import java.util.regex.Pattern;
050
051/**
052 * Generates documentation source table listing global ACIs.
053 */
054@Mojo(name = "generate-global-acis-table")
055public class GenerateGlobalAcisTableMojo extends AbstractMojo {
056    /** The locale for which to generate the documentation. */
057    @Parameter(defaultValue = "en")
058    private String locale;
059
060    /** The config.ldif file containing default global ACIs. **/
061    @Parameter(defaultValue = "${basedir}/resource/config/config.ldif")
062    private File configDotLdif;
063
064    /** Output directory for source files. */
065    @Parameter(defaultValue = "${project.build.directory}/docbkx-sources/shared")
066    private File outputDirectory;
067
068    /** Holds documentation for an ACI. */
069    private class Aci {
070        String description;
071        String definition;
072    }
073
074    /** Holds the list of global ACIs. */
075    private static List<Aci> allGlobalAcis = new LinkedList<>();
076
077    /**
078     * Writes documentation source table listing global ACIs.
079     * @throws MojoExecutionException   Not used.
080     * @throws MojoFailureException     Failed to read ACIs or to write the table file.
081     */
082    @Override
083    public void execute() throws MojoExecutionException, MojoFailureException {
084        try {
085            readAcis();
086        } catch (IOException e) {
087            throw new MojoFailureException(e.getMessage(), e);
088        }
089
090        File table = new File(outputDirectory, "table-global-acis.xml");
091        try {
092            writeStringToFile(getGlobalAcisTable(), table);
093        } catch (IOException e) {
094            throw new MojoFailureException(e.getMessage(), e);
095        }
096    }
097
098    /**
099     * Reads {@code ds-cfg-global-aci} values from {@code config.ldif} into the list of Acis.
100     * @throws IOException  Failed to read the LDIF.
101     */
102    private void readAcis() throws IOException {
103        LDIFEntryReader reader = new LDIFEntryReader(new FileInputStream(configDotLdif));
104        reader.setIncludeBranch(DN.valueOf("cn=Access Control Handler,cn=config"));
105
106        while (reader.hasNext()) {
107            Entry entry = reader.readEntry();
108            for (String attribute : entry.parseAttribute("ds-cfg-global-aci").asSetOfString()) {
109                Aci aci = new Aci();
110                aci.description = getDescription(attribute);
111                aci.definition = attribute;
112                allGlobalAcis.add(aci);
113            }
114        }
115    }
116
117    /**
118     * Returns a DocBook XML table listing global ACIs.
119     * @return A DocBook XML table listing global ACIs.
120     */
121    private String getGlobalAcisTable() {
122        final Map<String, Object> map = new HashMap<>();
123        map.put("year", new SimpleDateFormat("yyyy").format(new Date()));
124        map.put("lang", locale);
125        map.put("title", DOC_GLOBAL_ACIS_TABLE_TITLE.get());
126        map.put("summary", DOC_GLOBAL_ACIS_TABLE_SUMMARY.get());
127        map.put("descTitle", DOC_GLOBAL_ACIS_DESCRIPTION_COLUMN_TITLE.get());
128        map.put("defTitle", DOC_GLOBAL_ACIS_DEFINITION_COLUMN_TITLE.get());
129        map.put("acis", getDefaultGlobalAciList());
130        return applyTemplate("table-global-acis.ftl", map);
131    }
132
133    /**
134     * Returns a list of information about default global ACIs.
135     * @return A list of information about default global ACIs.
136     */
137    private List<Map<String, Object>> getDefaultGlobalAciList() {
138        final List<Map<String, Object>> globalAciList = new LinkedList<>();
139        for (final Aci aci : allGlobalAcis) {
140            final Map<String, Object> map = new HashMap<>();
141            map.put("description", aci.description);
142            map.put("definition", aci.definition);
143            globalAciList.add(map);
144        }
145        return globalAciList;
146    }
147
148    /**
149     * Returns the user-friendly description embedded in the ACI.
150     * @param aci   The string representation of the ACI value.
151     * @return  The user-friendly description embedded in the ACI,
152     *          or an empty string if no description is found.
153     */
154    private String getDescription(String aci) {
155        // Extract the user-friendly string in
156        // {@code ...version 3.0; acl "user-friendly string"...}.
157        Pattern pattern = Pattern.compile(".+version 3.0; ?acl \"([^\"]+)\".+");
158        Matcher matcher = pattern.matcher(aci);
159        if (matcher.find()) {
160            return matcher.group(1);
161        }
162        return "";
163    }
164}