mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Mark Craig
31.19.2015 cb2be8d178f6540878f46bb8e816c5eeee0d9bcb
CR-6494 OPENDJ-1897 Generate locales ref doc with a template

This patch moves to using a FreeMarker template
instead of building XML with strings.
1 files added
2 files modified
287 ■■■■■ changed files
opendj-doc-plugin/pom.xml 5 ●●●●● patch | view | raw | blame | history
opendj-doc-plugin/src/main/java/org/forgerock/opendj/maven/doc/GenerateSchemaDocMojo.java 211 ●●●●● patch | view | raw | blame | history
opendj-doc-plugin/src/main/resources/templates/sec-locales-subtypes.ftl 71 ●●●●● patch | view | raw | blame | history
opendj-doc-plugin/pom.xml
@@ -55,6 +55,11 @@
      <version>${project.version}</version>
    </dependency>
    <dependency>
      <groupId>org.freemarker</groupId>
      <artifactId>freemarker</artifactId>
      <version>2.3.21</version>
    </dependency>
    <dependency>
      <groupId>org.twdata.maven</groupId>
      <artifactId>mojo-executor</artifactId>
      <version>2.2.0</version>
opendj-doc-plugin/src/main/java/org/forgerock/opendj/maven/doc/GenerateSchemaDocMojo.java
@@ -26,6 +26,9 @@
import static com.forgerock.opendj.ldap.CoreMessages.*;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
@@ -33,16 +36,22 @@
import org.apache.maven.plugins.annotations.Parameter;
import org.forgerock.opendj.ldap.schema.CoreSchemaSupportedLocales;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
/**
 * Generate schema-related reference documentation sources.
@@ -65,7 +74,6 @@
    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        final Locale currentLocale = getLocaleFromTag(locale);
        final String localeReference = getLocalesAndSubTypesDocumentation(currentLocale);
        final File localeReferenceFile = new File(outputDirectory, "sec-locales-subtypes.xml");
        try {
@@ -79,6 +87,22 @@
    }
    /**
     * Returns a DocBook XML Section element documenting supported locales and language subtypes.
     * @param currentLocale The locale for which to generate the documentation.
     * @return A DocBook XML Section element documenting supported locales and language subtypes.
     */
    private String getLocalesAndSubTypesDocumentation(final Locale currentLocale) {
        final Map<String, Object> map = new HashMap<String, Object>();
        map.put("year", new SimpleDateFormat("yyyy").format(new Date()));
        map.put("lang", getTagFromLocale(currentLocale));
        map.put("title", DOC_LOCALE_SECTION_TITLE.get());
        map.put("info", DOC_LOCALE_SECTION_INFO.get());
        map.put("locales", getLocalesDocMap(currentLocale));
        map.put("subtypes", getSubTypesDocMap(currentLocale));
        return applyTemplate("sec-locales-subtypes.ftl", map);
    }
    /**
     * Create the output directory if it does not exist.
     * @throws IOException  Failed to create the directory.
     */
@@ -105,23 +129,61 @@
    private final Map<String, String> localeTagsToOids =
            CoreSchemaSupportedLocales.getJvmSupportedLocaleNamesToOids();
    /** FreeMarker template configuration. */
    private Configuration configuration;
    /**
     * Returns a DocBook XML VariableList element documenting supported locales.
     * @param currentLocale The locale for which to generate the documentation.
     * @return A DocBook XML VariableList element documenting supported locales.
     * Returns a FreeMarker configuration for applying templates.
     * @return A FreeMarker configuration for applying templates.
     */
    private String getLocalesDocumentation(final Locale currentLocale) {
        if (currentLocale == null) {
            return "";
    private Configuration getConfiguration() {
        if (configuration == null) {
            configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
            configuration.setClassForTemplateLoading(GenerateSchemaDocMojo.class, "/templates");
            configuration.setDefaultEncoding("UTF-8");
            configuration.setTemplateExceptionHandler(TemplateExceptionHandler.DEBUG_HANDLER);
        }
        return configuration;
    }
        class LocaleDoc {
            String tag;
            String language;
            String oid;
    /**
     * Returns the String result from applying a FreeMarker template.
     * @param template The name of a template file found in {@code resources/templates/}.
     * @param map      The map holding the data to use in the template.
     * @return The String result from applying a FreeMarker template.
     */
    private String applyTemplate(final String template, final Map<String, Object> map) {
        // FreeMarker requires a configuration to find the template.
        configuration = getConfiguration();
        // FreeMarker takes the data and a Writer to process the template.
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        Writer writer = new OutputStreamWriter(outputStream);
        try {
            Template configurationTemplate = configuration.getTemplate(template);
            configurationTemplate.process(map, writer);
            return outputStream.toString();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            org.forgerock.util.Utils.closeSilently(writer, outputStream);
        }
    }
        Map<String, LocaleDoc> locales = new HashMap<String, LocaleDoc>();
    /** Container for documentation regarding a locale. */
    private class LocaleDoc {
        String tag;
        String language;
        String oid;
    }
    /**
     * Returns a map of languages to Locale documentation containers.
     * @param currentLocale     The Locale of the resulting documentation.
     * @return A map of languages to Locale documentation containers.
     */
    private Map<String, LocaleDoc> getLanguagesToLocalesMap(final Locale currentLocale) {
        Map<String, LocaleDoc> locales = new TreeMap<String, LocaleDoc>();
        for (String tag : localeTagsToOids.keySet()) {
            final Locale locale = getLocaleFromTag(tag);
            if (locale == null) {
@@ -134,52 +196,50 @@
            if (!localeDoc.language.equals(localeDoc.tag)) {
                // No display language so must not be supported in current JVM
                locales.put(localeDoc.language, localeDoc);
            } else {
                if (localeDoc.tag.equals("sh")) {
                    localeDoc.language = DOC_LANGUAGE_SH.get().toString(currentLocale);
                    locales.put(localeDoc.language, localeDoc);
                }
            } else if (localeDoc.tag.equals("sh")) {
                localeDoc.language = DOC_LANGUAGE_SH.get().toString(currentLocale);
                locales.put(localeDoc.language, localeDoc);
            }
        }
        if (locales.isEmpty()) {
            return "";
        }
        final String eol = System.getProperty("line.separator");
        final StringBuilder stringBuilder = new StringBuilder();
        stringBuilder
                .append(" <variablelist xml:id=\"supported-locales\">").append(eol)
                .append("  <title>").append(DOC_SUPPORTED_LOCALES_TITLE.get()).append("</title>").append(eol)
                .append("  <indexterm><primary>").append(DOC_SUPPORTED_LOCALES_INDEXTERM.get())
                .append("</primary></indexterm>").append(eol);
        Set<String> sortedLanguages = new TreeSet<String>(locales.keySet());
        for (String language : sortedLanguages) {
            LocaleDoc locale = locales.get(language);
            stringBuilder
                    .append("  <varlistentry>").append(eol)
                    .append("   <term>").append(locale.language).append("</term>").append(eol)
                    .append("   <listitem>").append(eol)
                    .append("    <para>").append(DOC_LOCALE_TAG.get(locale.tag)).append("</para>").append(eol)
                    .append("    <para>").append(DOC_LOCALE_OID.get(locale.oid)).append("</para>").append(eol)
                    .append("   </listitem>").append(eol)
                    .append("  </varlistentry>").append(eol);
        }
        stringBuilder.append(" </variablelist>").append(eol);
        return stringBuilder.toString();
        return locales;
    }
    /**
     * Returns a DocBook XML ItemizedList element documenting supported language subtypes.
     * @param currentLocale The locale for which to generate the documentation.
     * @return A DocBook XML ItemizedList element documenting supported language subtypes.
     * Returns a map of information for documenting supported locales.
     * @param currentLocale The locale for which to generate the information.
     * @return A map of information for documenting supported locales.
     */
    private String getSubTypesDocumentation(final Locale currentLocale) {
        if (currentLocale == null) {
            return "";
    private Map<String, Object> getLocalesDocMap(final Locale currentLocale) {
        final Map<String, Object> result = new HashMap<String, Object>();
        result.put("title", DOC_SUPPORTED_LOCALES_TITLE.get());
        result.put("indexTerm", DOC_SUPPORTED_LOCALES_INDEXTERM.get());
        final Map<String, LocaleDoc> localesMap = getLanguagesToLocalesMap(currentLocale);
        final Set<String> sortedLanguages = localesMap.keySet();
        final List<Map<String, Object>> locales = new LinkedList<Map<String, Object>>();
        for (final String language : sortedLanguages) {
            final LocaleDoc locale = localesMap.get(language);
            final Map<String, Object> map = new HashMap<String, Object>();
            map.put("language", locale.language);
            map.put("tag", DOC_LOCALE_TAG.get(locale.tag));
            map.put("oid", DOC_LOCALE_OID.get(locale.oid));
            locales.add(map);
        }
        result.put("locales", locales);
        return result;
    }
        Map<String, String> map = new TreeMap<String, String>();
        for (String tag : localeTagsToOids.keySet()) {
    /**
     * Returns a map of information for documenting supported language subtypes.
     * @param currentLocale The locale for which to generate the information.
     * @return A map of information for documenting supported language subtypes.
     */
    private Map<String, Object> getSubTypesDocMap(final Locale currentLocale) {
        final Map<String, Object> result = new HashMap<String, Object>();
        result.put("title", DOC_SUPPORTED_SUBTYPES_TITLE.get());
        result.put("indexTerm", DOC_SUPPORTED_SUBTYPES_INDEXTERM.get());
        final List<Map<String, Object>> locales = new LinkedList<Map<String, Object>>();
        for (final String tag : localeTagsToOids.keySet()) {
            final Map<String, Object> map = new HashMap<String, Object>();
            int idx = tag.indexOf('-');
            if (idx == -1) {
                final Locale locale = getLocaleFromTag(tag);
@@ -188,48 +248,19 @@
                }
                final String language = locale.getDisplayName(currentLocale);
                if (!language.equals(tag)) {
                    map.put(language, tag);
                } else {
                    if (tag.equals("sh")) {
                        map.put(DOC_LANGUAGE_SH.get().toString(currentLocale), tag);
                    }
                    map.put("language", language);
                    map.put("tag", tag);
                } else if (tag.equals("sh")) {
                    map.put("language", DOC_LANGUAGE_SH.get().toString(currentLocale));
                    map.put("tag", tag);
                }
                if (!map.isEmpty()) {
                    locales.add(map);
                }
            }
        }
        final String eol = System.getProperty("line.separator");
        final StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(" <itemizedlist xml:id=\"supported-language-subtypes\">").append(eol)
                .append("  <title>").append(DOC_SUPPORTED_SUBTYPES_TITLE.get()).append("</title>").append(eol)
                .append("  <indexterm><primary>").append(DOC_SUPPORTED_SUBTYPES_INDEXTERM.get())
                .append("</primary></indexterm>").append(eol);
        for (String language: map.keySet()) {
            stringBuilder
                    .append("  <listitem><para>").append(language).append(", ")
                    .append(map.get(language)).append("</para></listitem>").append(eol);
        }
        stringBuilder.append(" </itemizedlist>").append(eol);
        return stringBuilder.toString();
    }
    /**
     * Returns a DocBook XML Section element documenting supported locales and language subtypes.
     * @param currentLocale The locale for which to generate the documentation.
     * @return A DocBook XML Section element documenting supported locales and language subtypes.
     */
    private String getLocalesAndSubTypesDocumentation(final Locale currentLocale) {
        final String eol = System.getProperty("line.separator");
        return "<section xml:id=\"sec-locales-subtypes\" "
                + "xmlns=\"http://docbook.org/ns/docbook\" version=\"5.0\" "
                + "xml:lang=\"" + getTagFromLocale(currentLocale) + "\" "
                + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
                + "xsi:schemaLocation=\"http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd\""
                + ">" + eol
                + " <title>" + DOC_LOCALE_SECTION_TITLE.get() + "</title>" + eol
                + " <para>" + DOC_LOCALE_SECTION_INFO.get() + "</para>" + eol
                + getLocalesDocumentation(currentLocale) + eol
                + getSubTypesDocumentation(currentLocale) + eol
                + "</section>";
        result.put("locales", locales);
        return result;
    }
    /**
opendj-doc-plugin/src/main/resources/templates/sec-locales-subtypes.ftl
New file
@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
  ! CCPL HEADER START
  !
  ! This work is licensed under the Creative Commons
  ! Attribution-NonCommercial-NoDerivs 3.0 Unported License.
  ! To view a copy of this license, visit
  ! http://creativecommons.org/licenses/by-nc-nd/3.0/
  ! or send a letter to Creative Commons, 444 Castro Street,
  ! Suite 900, Mountain View, California, 94041, USA.
  !
  ! You can also obtain a copy of the license at
  ! trunk/opendj/legal-notices/CC-BY-NC-ND.txt.
  ! See the License for the specific language governing permissions
  ! and limitations under the License.
  !
  ! If applicable, add the following below this CCPL HEADER, with the fields
  ! enclosed by brackets "[]" replaced with your own identifying information:
  !      Portions Copyright [yyyy] [name of copyright owner]
  !
  ! CCPL HEADER END
  !
  !      Copyright 2011-${year} ForgeRock AS.
  !
-->
<section xml:id="sec-locales-subtypes"
         xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="${lang}"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://docbook.org/ns/docbook
                             http://docbook.org/xml/5.0/xsd/docbook.xsd">
 <title>${title}</title>
 <para>
  ${info}
 </para>
 <variablelist xml:id="supported-locales">
  <title>${locales.title}</title>
  <indexterm><primary>${locales.indexTerm}</primary></indexterm>
  <#list locales.locales as locale>
  <varlistentry>
   <term>${locale.language}</term>
   <listitem>
    <para>
     ${locale.tag}
    </para>
    <para>
     ${locale.oid}
    </para>
   </listitem>
  </varlistentry>
  </#list>
 </variablelist>
 <itemizedlist xml:id="supported-language-subtypes">
  <title>${subtypes.title}</title>
  <indexterm><primary>${subtypes.indexTerm}</primary></indexterm>
  <#list subtypes.locales?sort_by("language") as subtype>
  <listitem>
   <para>${subtype.language}, ${subtype.tag}</para>
  </listitem>
  </#list>
 </itemizedlist>
</section>