/* * The contents of this file are subject to the terms of the Common Development and * Distribution License (the License). You may not use this file except in compliance with the * License. * * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the * specific language governing permission and limitations under the License. * * When distributing Covered Software, include this CDDL Header Notice in each file and include * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL * Header, with the fields enclosed by brackets [] replaced by your own identifying * information: "Portions Copyright [year] [name of copyright owner]". * * Copyright 2015 ForgeRock AS. * Portions Copyright 2026 3A Systems, LLC. */ package com.forgerock.opendj.cli; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateExceptionHandler; import java.io.ByteArrayOutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.Map; import java.util.regex.Pattern; /** * This class provides utility functions to help generate reference documentation. */ public final class DocGenerationHelper { /** Prevent instantiation. */ private DocGenerationHelper() { // Do nothing. } /** FreeMarker template configuration. */ private static Configuration configuration; /** * An AsciiDoc attribute reference, such as {@code {name}}, that no backslash escapes. * Word characters are Unicode ones, as in Asciidoctor. */ private static final Pattern ATTRIBUTE_REFERENCE = Pattern.compile("(? map) { // FixMe: This method is public so it can be used by the SubCommandUsageHandler // in org.forgerock.opendj.config.dsconfig.DSConfig. // FreeMarker requires a configuration to find the template. configuration = getConfiguration(); // FreeMarker takes the data and a Writer to process the template. try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); Writer writer = new OutputStreamWriter(outputStream)) { Template configurationTemplate = configuration.getTemplate(template); configurationTemplate.process(map, writer); builder.append(escapeAttributeReferences(outputStream.toString())); } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } } /** * Escapes the AsciiDoc attribute references in generated reference text. * *
* * The generated reference refers to no AsciiDoc attribute: a {@code {name}} in it is the placeholder * of an option value, written as is in the messages, which AsciiDoc would read as a reference * to a missing attribute. A reference that is already escaped is left as is, * so the result of a template can go through another template that includes it. * * @param text The generated AsciiDoc text. * @return The text with each attribute reference escaped by a backslash. */ static String escapeAttributeReferences(final String text) { return ATTRIBUTE_REFERENCE.matcher(text).replaceAll("\\\\$1"); } /** * Returns an option synopsis. * *
* * Note: The synopsis might contain characters that must be escaped in XML. * * @param argument The argument option. * @return A synopsis. */ static String getOptionSynopsis(final Argument argument) { StringBuilder builder = new StringBuilder(); final Character shortID = argument.getShortIdentifier(); if (shortID != null) { builder.append("-").append(shortID.charValue()); } final String longID = argument.getLongIdentifier(); if (shortID != null && longID != null) { builder.append(" | "); } if (longID != null) { builder.append("--").append(longID); } if (argument.needsValue()) { builder.append(" ").append(argument.getValuePlaceholder()); } return builder.toString(); } /** * Returns true when the argument handles properties. * * @param argument The argument. * @return True if the argument handles properties. */ public static boolean doesHandleProperties(final Argument argument) { // FixMe: This method is public so it can be used by the SubCommandUsageHandler // in org.forgerock.opendj.config.dsconfig.DSConfig. final String id = argument.getLongIdentifier(); return ("add".equals(id) || "remove".equals(id) || "reset".equals(id) || "set".equals(id)); } }