001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2012-2015 ForgeRock AS.
015 * Partial Copyright 2022 Wren Security
016 */
017package org.forgerock.doc.maven;
018
019import static org.twdata.maven.mojoexecutor.MojoExecutor.element;
020import static org.twdata.maven.mojoexecutor.MojoExecutor.name;
021
022import org.apache.commons.io.FilenameUtils;
023import org.apache.maven.execution.MavenSession;
024import org.apache.maven.plugin.AbstractMojo;
025import org.apache.maven.plugin.BuildPluginManager;
026import org.apache.maven.plugin.MojoExecutionException;
027import org.apache.maven.plugins.annotations.Component;
028import org.apache.maven.plugins.annotations.Parameter;
029import org.apache.maven.project.MavenProject;
030import org.forgerock.doc.maven.backstage.ArtifactItem;
031import org.forgerock.doc.maven.utils.NameUtils;
032import org.twdata.maven.mojoexecutor.MojoExecutor;
033
034import java.io.File;
035import java.io.IOException;
036import java.io.InputStream;
037import java.text.SimpleDateFormat;
038import java.util.ArrayList;
039import java.util.Date;
040import java.util.HashMap;
041import java.util.LinkedList;
042import java.util.List;
043import java.util.Map;
044import java.util.Properties;
045import java.util.Set;
046
047/**
048 * AbstractMojo implementation for building core documentation from <a
049 * href="http://www.docbook.org/tdg51/en/html/docbook.html">DocBook XML</a>
050 * using <a href="http://code.google.com/p/docbkx-tools/">docbkx-tools</a>.
051 */
052abstract public class AbstractDocbkxMojo extends AbstractMojo {
053
054    /**
055     * Versions of plugins driven by this plugin.
056     */
057    private Properties versions;
058
059    /**
060     * Load versions of plugins driven by this plugin.
061     */
062    private void loadVersions() {
063        versions = new Properties();
064        InputStream inputStream = null;
065
066        try {
067            inputStream = getClass().getResourceAsStream("/versions.properties");
068            if (inputStream == null) {
069                throw new IOException("Could not read properties resource");
070            }
071            versions.load(inputStream);
072        } catch (IOException e) {
073            getLog().error("Failed to read plugin version properties", e);
074        } finally {
075            if (inputStream != null) {
076                try {
077                    inputStream.close();
078                } catch (IOException e) {
079                    // Ignore exception.
080                }
081            }
082        }
083    }
084
085    /**
086     * Get a version property based on the version properties file.
087     *
088     * <br>
089     *
090     * Prefer the current value if it is already set.
091     *
092     * @param currentValue  If not null or empty, then return this value.
093     * @param key           Otherwise return the value for this key.
094     * @return              The currentValue if set, otherwise the property.
095     */
096    private String getVersionProperty(String currentValue, String key) {
097        if (currentValue != null && !currentValue.isEmpty()) {
098            return currentValue;
099        }
100
101        if (versions == null) {
102            loadVersions();
103        }
104
105        return versions.getProperty(key);
106    }
107
108    /**
109     * Whether to use WinAnsi encoding for embedded fonts.
110     * If {@code true}, then some UTF-8 characters cannot be used.
111     */
112    private String ansi = "false";
113
114    /**
115     * Whether to use WinAnsi encoding for embedded fonts.
116     *
117     * <br>
118     *
119     * Value: {@code false}
120     *
121     * @return Whether WinAnsi encoded should be used for embedded fonts.
122     */
123    public final String useAnsi() {
124        return ansi;
125    }
126
127    /**
128     * Should sections have numeric labels?
129     *
130     * <br>
131     *
132     * docbkx-tools element: &lt;sectionAutolabel&gt;
133     */
134    private String areSectionsAutolabeled = "true";
135
136    /**
137     * Whether sections should have numeric labels.
138     *
139     * <br>
140     *
141     * Value: {@code true}
142     *
143     * <br>
144     *
145     * docbkx-tools element: &lt;sectionAutolabel&gt;
146     *
147     * @return Whether sections should have numeric labels.
148     */
149    public final String areSectionsAutolabeled() {
150        return areSectionsAutolabeled;
151    }
152
153    /**
154     * Base directory for Asciidoc source files.
155     */
156    @Parameter(defaultValue = "${basedir}/src/main/asciidoc")
157    private File asciidocSourceDirectory;
158
159    /**
160     * Get the base directory for Asciidoc source files.
161     * These files remain unchanged during processing.
162     *
163     * <br>
164     *
165     * Default: {@code ${basedir}/src/main/asciidoc}.
166     *
167     * @return The base directory for Asciidoc source files.
168     */
169    public File getAsciidocSourceDirectory() {
170        return asciidocSourceDirectory;
171    }
172
173    /**
174     * Version of the Asciidoctor Maven plugin to use.
175     */
176    @Parameter
177    private String asciidoctorPluginVersion;
178
179    /**
180     * Returns the version of the Asciidoctor Maven plugin to use.
181     *
182     * @return The version of the Asciidoctor Maven plugin to use.
183     */
184    public String getAsciidoctorPluginVersion() {
185        return getVersionProperty(asciidoctorPluginVersion, "asciidoctorPluginVersion");
186    }
187
188    /**
189     * File system directory for Backstage layout output
190     * relative to the build directory.
191     */
192    @Parameter(defaultValue = "backstage")
193    private String backstageDirectory;
194
195    /**
196     * Get the file system directory for Backstage layout output.
197     *
198     * <br>
199     *
200     * Default: {@code ${project.build.directory}/backstage}
201     *
202     * @return The file system directory for Backstage layout output.
203     */
204    public File getBackstageDirectory() {
205        return new File(getBuildDirectory(), backstageDirectory);
206    }
207
208    /**
209     * Product name as shown on Backstage.
210     */
211    @Parameter(property = "backstageProductName")
212    private String backstageProductName;
213
214    /**
215     * Get the product name as shown on Backstage.
216     *
217     * <br>
218     *
219     * Default: {@code projectName}
220     *
221     * @return The product name as shown on Backstage.
222     */
223    public String getBackstageProductName() {
224        return backstageProductName != null ? backstageProductName : projectName;
225    }
226
227    /**
228     * Get the base configuration applicable to all builds with the docbkx-tools plugin.
229     *
230     * @return The configuration applicable to all builds.
231     */
232    public ArrayList<MojoExecutor.Element> getBaseConfiguration() {
233        ArrayList<MojoExecutor.Element> cfg = new ArrayList<>();
234
235        cfg.add(element(name("draftMode"), isDraftMode()));
236        cfg.add(element(name("draftWatermarkImage"), getDraftWatermarkURL()));
237        cfg.add(element(name("highlightSource"), useSyntaxHighlighting()));
238        cfg.add(element(name("sectionAutolabel"), areSectionsAutolabeled()));
239        cfg.add(element(name("sectionLabelIncludesComponentLabel"),
240                doesSectionLabelIncludeComponentLabel()));
241        cfg.add(element(name("xincludeSupported"), isXincludeSupported()));
242        cfg.add(element(name("sourceDirectory"), path(getDocbkxModifiableSourcesDirectory())));
243
244        return cfg;
245    }
246
247    /**
248     * Project base directory, needed to workaround bugs with *target.db and webhelp.
249     */
250    @Parameter(defaultValue = "${basedir}")
251    private File baseDir;
252
253    /**
254     * Project base directory, needed to workaround bugs with *target.db and webhelp.
255     *
256     * <br>
257     *
258     * Default: {@code ${basedir}}
259     *
260     * @return The project base directory.
261     */
262    public File getBaseDir() {
263        return baseDir;
264    }
265
266    /**
267     * The artifactId of the branding to use.
268     */
269    @Parameter(defaultValue = "doc-default-branding")
270    private String brandingArtifactId;
271
272    /**
273     * Gets the branding artifactId to use.
274     *
275     * <br>
276     *
277     * Default: {@code doc-default-branding}.
278     *
279     * @return The branding artifactId.
280     */
281    public String getBrandingArtifactId() {
282        return brandingArtifactId;
283    }
284
285    /**
286     * The groupId of the branding to use.
287     */
288    @Parameter(defaultValue = "org.wrensecurity.commons")
289    private String brandingGroupId;
290
291    /**
292     * Gets the groupId of the branding artifact to use.
293     *
294     * <br>
295     *
296     * Default: {@code org.wrensecurity.common}
297     *
298     * @return The branding groupId.
299     */
300    public String getBrandingGroupId() {
301        return brandingGroupId;
302    }
303
304    /**
305     * Version of the branding artifact to use.
306     */
307    @Parameter
308    private String brandingVersion;
309
310    /**
311     * Gets the version of the branding artifact to use.
312     *
313     * @return The branding artifact version.
314     */
315    public String getBrandingVersion() {
316        return getVersionProperty(brandingVersion, "brandingVersion");
317    }
318
319    /**
320     * The project build directory.
321     *
322     * <br>
323     *
324     * Default: {@code ${project.build.directory}}.
325     */
326    @Parameter(defaultValue = "${project.build.directory}")
327    private File buildDirectory;
328
329    /**
330     * Get the project build directory for this plugin.
331     *
332     * <br>
333     *
334     * Default: {@code ${project.build.directory}}.
335     *
336     * @return The build directory.
337     */
338    public File getBuildDirectory() {
339        return buildDirectory;
340    }
341
342    /**
343     * Whether to build a .zip of the release content.
344     */
345    @Parameter(defaultValue = "false", property = "buildReleaseZip")
346    private boolean buildReleaseZip;
347
348    /**
349     * Whether to build a .zip containing the release content.
350     *
351     * <br>
352     *
353     * Default: {@code false}
354     *
355     * @return true if the .zip should be built.
356     */
357    public final boolean doBuildReleaseZip() {
358        return buildReleaseZip;
359    }
360
361    /**
362     * Location of the chunked HTML XSL stylesheet customization file,
363     * relative to the build directory.
364     *
365     * <br>
366     *
367     * docbkx-tools element: &lt;htmlCustomization&gt;
368     */
369    private String chunkedHTMLCustomization = "docbkx-stylesheets/html/chunked.xsl";
370
371    /**
372     * Get the location of the chunked HTML XSL stylesheet customization file.
373     *
374     * <br>
375     *
376     * Default: {@code ${project.build.directory}/docbkx-stylesheets/html/chunked.xsl}
377     *
378     * <br>
379     *
380     * docbkx-tools element: &lt;htmlCustomization&gt;
381     *
382     * @return The location of the chunked HTML XSL stylesheet.
383     */
384    public final File getChunkedHTMLCustomization() {
385        return new File(getBuildDirectory(), chunkedHTMLCustomization);
386    }
387
388    /**
389     * The {@code artifactId} of the common content artifact.
390     */
391    @Parameter(defaultValue = "doc-common-content")
392    private String commonContentArtifactId;
393
394    /**
395     * Get the {@code artifactId} of the common content artifact.
396     *
397     * <br>
398     *
399     * Default: {@code doc-common-content}.
400     *
401     * @return The {@code artifactId} of the common content artifact.
402     */
403    public String getCommonContentArtifactId() {
404        return commonContentArtifactId;
405    }
406
407    /**
408     * The {@code groupId} of the common content artifact.
409     */
410    @Parameter(defaultValue = "org.wrensecurity.commons")
411    private String commonContentGroupId;
412
413    /**
414     * Get the {@code groupId} of the common content artifact.
415     *
416     * <br>
417     *
418     * Default: {@code org.wrensecurity.common}.
419     *
420     * @return The {@code groupId} of the common content artifact.
421     */
422    public String getCommonContentGroupId() {
423        return commonContentGroupId;
424    }
425
426    /**
427     * Version of the common content artifact to use.
428     */
429    @Parameter
430    private String commonContentVersion;
431
432    /**
433     * Get the version of the common content artifact to use.
434     *
435     * @return the version of the common content artifact to use.
436     */
437    public String getCommonContentVersion() {
438        return getVersionProperty(commonContentVersion, "commonContentVersion");
439    }
440
441    /**
442     * Whether to copy resource files alongside docs for site, release.
443     */
444    @Parameter(defaultValue = "false")
445    private boolean copyResourceFiles;
446
447    /**
448     * Whether to copy resource files alongside docs for site, release.
449     *
450     * <br>
451     *
452     * Default: false
453     *
454     * @return true if resource files should be copied.
455     */
456    public boolean doCopyResourceFiles() {
457        return copyResourceFiles;
458    }
459
460    /**
461     * Whether to build artifacts from pre-processed sources.
462     */
463    @Parameter(defaultValue = "true")
464    private boolean createArtifacts;
465
466    /**
467     * Whether to build artifacts from pre-processed sources.
468     *
469     * <br>
470     *
471     * Default: true
472     *
473     * @return true if artifacts should be build from pre-processed sources.
474     */
475    public boolean doCreateArtifacts() {
476        return createArtifacts;
477    }
478
479    /**
480     * Doc artifacts to unpack when preparing Backstage layout.
481     */
482    @Parameter
483    private List<ArtifactItem> artifactItems;
484
485    /**
486     * Get the doc artifacts to unpack when preparing Backstage layout.
487     *
488     * @return The doc artifacts to unpack when preparing Backstage layout.
489     */
490    public List<ArtifactItem> getArtifactItems() {
491        return artifactItems != null ? artifactItems : new LinkedList<ArtifactItem>();
492    }
493
494    /**
495     * Base directory for the modifiable copy of DocBook XML source files,
496     * relative to the build directory.
497     */
498    private String docbkxModifiableSourcesDirectory = "docbkx-sources";
499
500    /**
501     * Get the base directory for the modifiable copy of DocBook XML source files.
502     * This copy is modified during preparation for processing.
503     *
504     * <br>
505     *
506     * Value: {@code ${project.build.directory}/docbkx-sources}
507     *
508     * @return The base directory for the modifiable copy of DocBook XML source files.
509     */
510    public File getDocbkxModifiableSourcesDirectory() {
511        return new File(getBuildDirectory(), docbkxModifiableSourcesDirectory);
512    }
513
514    /**
515     * Base directory for built documentation, relative to the build directory.
516     */
517    private String docbkxOutputDirectory = "docbkx";
518
519    /**
520     * Base directory for built documentation.
521     *
522     * <br>
523     *
524     * Value: {@code ${project.build.directory}/docbkx}
525     *
526     * @return The base directory for built documentation.
527     */
528    public File getDocbkxOutputDirectory() {
529        return new File(buildDirectory, docbkxOutputDirectory);
530    }
531
532    /**
533     * Base directory for DocBook XML source files.
534     */
535    @Parameter(defaultValue = "${basedir}/src/main/docbkx", property = "docbkxSourceDirectory")
536    private File docbkxSourceDirectory;
537
538    /**
539     * Get the base directory for DocBook XML source files.
540     * These files remain unchanged during processing.
541     *
542     * <br>
543     *
544     * Default: {@code ${basedir}/src/main/docbkx}.
545     *
546     * @return The base directory for DocBook XML source files.
547     */
548    public File getDocbkxSourceDirectory() {
549        return docbkxSourceDirectory;
550    }
551
552    /**
553     * Docbkx Tools plugin version to use.
554     */
555    @Parameter
556    private String docbkxVersion;
557
558    /**
559     * Get the docbkx-tools plugin version to use.
560     *
561     * @return The docbkx-tools plugin version to use
562     */
563    public String getDocbkxVersion() {
564        return getVersionProperty(docbkxVersion, "docbkxVersion");
565    }
566
567    /**
568     * Supported DocBook profile attributes.
569     */
570    public enum ProfileAttributes {
571        /** Computer or chip architecture, such as i386. */
572        arch,
573
574        /** Intended audience of the content, such as instructor. Added in DocBook version 5.0. */
575        audience,
576
577        /** General purpose conditional attribute, with no preassigned semantics. */
578        condition,
579
580        /** Standards conformance, such as lsb (Linux Standards Base). */
581        conformance,
582
583        /** Language code, such as de_DE. */
584        lang,
585
586        /** Operating system. */
587        os,
588
589        /** Editorial revision, such as v2.1. */
590        revision,
591
592        /** Revision status of the element, such as changed. This attribute has a fixed set of values to choose from. */
593        revisionflag,
594
595        /** General purpose attribute, with no preassigned semantics. Use with caution for profiling. */
596        role,
597
598        /** Security level, such as high. */
599        security,
600
601        /** Editorial or publication status, such as InDevelopment or draft. */
602        status,
603
604        /** Level of user experience, such as beginner. */
605        userlevel,
606
607        /** Product vendor, such as apache. */
608        vendor,
609
610        /** Word size (width in bits) of the computer architecture, such as 64bit. Added in DocBook version 4.4. */
611        wordsize
612    }
613
614    /**
615     * Returns true if the attribute is one of the expected ProfileAttributes.
616     * @param attribute     The attribute to check.
617     * @return true if the attribute is one of the expected ProfileAttributes.
618     */
619    private boolean isProfileAttribute(final String attribute) {
620        try {
621            ProfileAttributes.valueOf(attribute);
622            return true;
623        } catch (IllegalArgumentException e) {
624            return false;
625        }
626    }
627
628    /**
629     * Include elements with these
630     * <a href="http://www.sagehill.net/docbookxsl/Profiling.html">DocBook profile</a> settings.
631     * <br>
632     * See <a href="http://www.sagehill.net/docbookxsl/Profiling.html#ProfilingAttribs"
633     * >the list of profile attributes specified for DocBook</a>.
634     * <br>
635     * Separate multiple attribute values for the same attribute with spaces.
636     * <br>
637     * For example, to include all elements with {@code os="linux"} or {@code os="unix"}
638     * and all elements with no {@code os} attribute,
639     * use the following configuration:
640     * <pre>
641     * &lt;inclusions>
642     *  &lt;os>linux unix&lt;/os>
643     * &lt;/inclusions>
644     * </pre>
645     */
646    @Parameter
647    private Map<String, String> inclusions;
648
649    /**
650     * Returns a map of DocBook profile settings to include elements.
651     * <br>
652     * This implementation ignores unexpected profile settings.
653     *
654     * @return A map of DocBook profile settings to include elements,
655     *         or null if none are set.
656     */
657    public Map<String, String> getInclusions() {
658        if (inclusions == null) {
659            return null;
660        }
661
662        Map<String, String> result = new HashMap<>();
663        for (String attribute : inclusions.keySet()) {
664            if (isProfileAttribute(attribute)) {
665                result.put(attribute, inclusions.get(attribute));
666            }
667        }
668        return result;
669    }
670
671    /**
672     * Exclude elements with these
673     * <a href="http://www.sagehill.net/docbookxsl/Profiling.html">DocBook profile</a> settings.
674     * <br>
675     * See <a href="http://www.sagehill.net/docbookxsl/Profiling.html#ProfilingAttribs"
676     * >the list of profile attributes specified for DocBook</a>.
677     * <br>
678     * Separate multiple attribute values for the same attribute with spaces.
679     * <br>
680     * For example, to exclude all elements with {@code os="linux"} and {@code os="unix"},
681     * use the following configuration:
682     * <pre>
683     * &lt;exclusions>
684     *  &lt;os>linux unix&lt;/os>
685     * &lt;/exclusions>
686     * </pre>
687     */
688    @Parameter
689    private Map<String, String> exclusions;
690
691    /**
692     * Returns a map of DocBook profile settings to exclude elements.
693     * <br>
694     * This implementation ignores unexpected profile settings.
695     *
696     * @return A map of DocBook profile settings to exclude elements,
697     *         or null if none are set.
698     */
699    public Map<String, String> getExclusions() {
700        if (exclusions == null) {
701            return null;
702        }
703
704        Map<String, String> result = new HashMap<>();
705        for (String attribute : exclusions.keySet()) {
706            if (isProfileAttribute(attribute)) {
707                result.put(attribute, exclusions.get(attribute));
708            }
709        }
710        return result;
711    }
712
713    /**
714     * Get document names for the current project.
715     *
716     * @return The document names for the current project.
717     * @throws MojoExecutionException No document names found.
718     */
719    public Set<String> getDocNames() throws MojoExecutionException {
720
721        Set<String> docNames = NameUtils.getDocumentNames(
722                getDocbkxModifiableSourcesDirectory(), getDocumentSrcName());
723
724        if (docNames.isEmpty()) {
725            throw new MojoExecutionException("No document names found.");
726        }
727        return docNames;
728    }
729
730    /**
731     * URL to site for published documentation.
732     */
733    @Parameter(defaultValue = "https://docs.wrensecurity.org/")
734    private String docsSite;
735
736    /**
737     * Get the URL to the site for published documentation.
738     *
739     * <br>
740     *
741     * Default: {@code https://docs.wrensecurity.org/}
742     *
743     * @return The URL to the site for published documentation.
744     */
745    public String getDocsSite() {
746        return docsSite;
747    }
748
749    /**
750     * Top-level DocBook XML source document name.
751     */
752    @Parameter(defaultValue = "index.xml", property = "documentSrcName")
753    private String documentSrcName;
754
755    /**
756     * Get the top-level DocBook XML source document name.
757     *
758     * <br>
759     *
760     * Default: {@code index.xml}.
761     *
762     * <br>
763     *
764     * Documents included in the documentation set
765     * such as books, articles, and references share a common entry point,
766     * which is a file having the name specified by this element.
767     *
768     * <br>
769     *
770     * For example, if your documentation set has
771     * Release Notes, an Installation Guide, an Admin Guide, a Dev Guide, and a Reference,
772     * your source layout under the base DocBook XML source directory
773     * might look like the following:
774     *
775     * <pre>
776     * src/main/docbkx/
777     *  admin-guide/
778     *   index.xml
779     *   ...other files...
780     *  dev-guide/
781     *   index.xml
782     *   ...other files...
783     *  install-guide/
784     *   index.xml
785     *   ...other files...
786     *  reference/
787     *   index.xml
788     *   ...other files...
789     *  release-notes/
790     *   index.xml
791     *   ...other files...
792     *  shared/
793     *   ...other files...
794     * </pre>
795     *
796     * <br>
797     *
798     * The {@code ...other files...} can have whatever names you want,
799     * as long as the name does not match the file name you configure.
800     * For example, if you were to hand-code an index file
801     * you could name it {@code ix.xml}.
802     *
803     * @return File name of top-level DocBook XML source document.
804     */
805    public String getDocumentSrcName() {
806        return documentSrcName;
807    }
808
809    /**
810     * Whether section labels should include parent numbers,
811     * like 1.1, 1.2, 1.2.1, 1.2.2.
812     *
813     * <br>
814     *
815     * docbkx-tools element: &lt;sectionLabelIncludesComponentLabel&gt;
816     */
817    private String doesSectionLabelIncludeComponentLabel = "true";
818
819    /**
820     * Whether section labels should include parent numbers,
821     * like 1.1, 1.2, 1.2.1, 1.2.2.
822     *
823     * <br>
824     *
825     * Value: {@code true}
826     *
827     * <br>
828     *
829     * docbkx-tools element: &lt;sectionLabelIncludesComponentLabel&gt;
830     *
831     * @return Whether section labels should include parent numbers.
832     */
833    public final String doesSectionLabelIncludeComponentLabel() {
834        return doesSectionLabelIncludeComponentLabel;
835    }
836
837    /**
838     * For draft mode, URL to the background watermark image.
839     *
840     * <br>
841     *
842     * docbkx-tools element: &lt;draftWatermarkImage&gt;
843     */
844    @Parameter(defaultValue = "http://docbook.sourceforge.net/release/images/draft.png")
845    private String draftWatermarkURL;
846
847    /**
848     * For draft mode, URL to the background watermark image.
849     *
850     * <br>
851     *
852     * Default: {@code http://docbook.sourceforge.net/release/images/draft.png}
853     *
854     * <br>
855     *
856     * docbkx-tools element: &lt;draftWatermarkImage&gt;
857     *
858     * @return The URL to the background watermark image.
859     */
860    public final String getDraftWatermarkURL() {
861        return draftWatermarkURL;
862    }
863
864    /**
865     * URL to JSON object showing EOSL versions for each project.
866     */
867    @Parameter(defaultValue = "http://docs.wrensecurity.org/eosl.json")
868    private String eoslJson;
869
870    /**
871     * Get the URL to JSON object showing EOSL versions for each project.
872     *
873     * @return The URL to the JSON object.
874     */
875    public String getEoslJson() {
876        return eoslJson;
877    }
878
879    /**
880     * Location of the EPUB XSL stylesheet customization file,
881     * relative to the build directory.
882     *
883     * <br>
884     *
885     * docbkx-tools element: &lt;epubCustomization&gt;
886     */
887    private String epubCustomization = "docbkx-stylesheets/epub/coredoc.xsl";
888
889    /**
890     * Get the location of the EPUB XSL stylesheet customization file.
891     *
892     * <br>
893     *
894     * Default: {@code ${project.build.directory}/docbkx-stylesheets/epub/coredoc.xsl}
895     *
896     * <br>
897     *
898     * docbkx-tools element: &lt;epubCustomization&gt;
899     *
900     * @return The location of the EPUB XSL stylesheet customization file.
901     */
902    public final File getEpubCustomization() {
903        return new File(getBuildDirectory(), epubCustomization);
904    }
905
906    /**
907     * Favicon link element for the pre-site version of the HTML.
908     */
909    @Parameter(defaultValue = "<link rel=\"shortcut icon\" href=\"https://wrensecurity.org/favicon.ico\">")
910    private String faviconLink;
911
912    /**
913     * Get the favicon link element for the pre-site version of the HTML.
914     *
915     * @return The link element.
916     */
917    public final String getFaviconLink() {
918        return faviconLink;
919    }
920
921    /**
922     * Location of the FO XSL stylesheet customization file (for PDF, RTF),
923     * relative to the build directory.
924     *
925     * <br>
926     *
927     * docbkx-tools element: &lt;foCustomization&gt;
928     */
929    private String foCustomization = "docbkx-stylesheets/fo/coredoc.xsl";
930
931    /**
932     * Get the location of the FO XSL stylesheet customization file (for PDF, RTF).
933     *
934     * <br>
935     *
936     * Value: {@code ${project.build.directory}/docbkx-stylesheets/fo/coredoc.xsl}
937     *
938     * <br>
939     *
940     * docbkx-tools element: &lt;foCustomization&gt;
941     *
942     * @return The location of the FO XSL stylesheet.
943     */
944    public final File getFoCustomization() {
945        return new File(getBuildDirectory(), foCustomization);
946    }
947
948    /**
949     * Directory where fonts and font metrics are stored,
950     * relative to the build directory.
951     */
952    private String fontsDirectory  = "fonts";
953
954    /**
955     * Directory where fonts and font metrics are stored.
956     *
957     * <br>
958     *
959     * Value: {@code ${project.build.directory}/fonts}
960     *
961     * @return The directory where fonts and font metrics are stored.
962     */
963    public final File getFontsDirectory() {
964        return new File(getBuildDirectory(), fontsDirectory);
965    }
966
967    /**
968     * Version of the FOP hyphenation plugin to use.
969     */
970    @Parameter
971    private String fopHyphVersion;
972
973    /**
974     * Get the version of the FOP hyphenation plugin to use.
975     * @return The version of the FOP hyphenation plugin to use.
976     */
977    public String getFopHyphVersion() {
978        return getVersionProperty(fopHyphVersion, "fopHyphVersion");
979    }
980
981    /**
982     * Log level when building FO output (PDF, RTF).
983     *
984     * <br>
985     *
986     * docbkx-tools element: &lt;fopLogLevel&gt;
987     */
988    @Parameter(defaultValue = "ERROR")
989    private String fopLogLevel;
990
991    /**
992     * Log level when building FO output (PDF, RTF).
993     *
994     * <br>
995     *
996     * Default: {@code ERROR}
997     *
998     * <br>
999     *
1000     * docbkx-tools element: &lt;fopLogLevel&gt;
1001     *
1002     * @return The log level for Apache FOP.
1003     */
1004    public final String getFopLogLevel() {
1005        return fopLogLevel;
1006    }
1007
1008    /**
1009     * Supported output formats.
1010     */
1011    public enum Format {
1012        /**
1013         * EPUB v2 without styling; not ready for publication.
1014         */
1015        epub,
1016
1017        /**
1018         * Styled single-page and chunked HTML 4.
1019         */
1020        html,
1021
1022        /**
1023         * Styled with HtmlForBootstrap single-page HTML 4.
1024         */
1025        bootstrap,
1026
1027        /**
1028         * Reference manual pages for use with the {@code man} command.
1029         */
1030        man,
1031
1032        /**
1033         * PDF.
1034         */
1035        pdf,
1036
1037        /**
1038         * RTF without styling; not ready for publication.
1039         */
1040        rtf,
1041
1042        /**
1043         * Styled DocBook Webhelp format.
1044         */
1045        webhelp,
1046
1047        /**
1048         * Single-page XHTML5 without styling except syntax highlighting;
1049         * not ready for publication as is.
1050         */
1051        xhtml5
1052    }
1053
1054    /**
1055     * Comma-separated list of output formats to generate.
1056     */
1057    @Parameter(property = "formats", defaultValue = "bootstrap,pdf")
1058    private List<Format> formats;
1059
1060    /**
1061     * Return a list of output formats to generate.
1062     *
1063     * <br>
1064     *
1065     * Default: bootstrap,pdf
1066     *
1067     * @return List of output formats.
1068     */
1069    public List<Format> getFormats() {
1070        return this.formats;
1071    }
1072
1073    /**
1074     * Google Analytics identifier for the project.
1075     *
1076     * <br>
1077     *
1078     * The identifier for docs.forgerock.org is {@code UA-REMOVED-VALUE}.
1079     */
1080    @Parameter(defaultValue = "UA-REMOVED-VALUE")
1081    private String googleAnalyticsId;
1082
1083    /**
1084     * Google Analytics identifier for the project.
1085     *
1086     * <br>
1087     *
1088     * Default: {@code UA-REMOVED-VALUE}
1089     *
1090     * @return The Google Analytics identifier.
1091     */
1092    public String getGoogleAnalyticsId() {
1093        return googleAnalyticsId;
1094    }
1095
1096    /**
1097     * Whether these are draft documents, rather than final documents.
1098     *
1099     * <br>
1100     *
1101     * docbkx-tools element: &lt;draftMode&gt;
1102     */
1103    @Parameter(defaultValue = "yes", property = "isDraftMode")
1104    private String isDraftMode;
1105
1106    /**
1107     * Whether these are draft documents, rather than final documents.
1108     *
1109     * <br>
1110     *
1111     * Default: {@code yes}
1112     *
1113     * <br>
1114     *
1115     * docbkx-tools element: &lt;draftMode&gt;
1116     *
1117     * @return Whether these are draft documents.
1118     */
1119    public final String isDraftMode() {
1120        return isDraftMode;
1121    }
1122
1123    /**
1124     * Whether documents should be allowed to include other documents.
1125     *
1126     * <br>
1127     *
1128     * docbkx-tools element: &lt;xincludeSupported&gt;
1129     */
1130    private String isXincludeSupported = "true";
1131
1132    /**
1133     * Whether documents should be allowed to include other documents.
1134     *
1135     * <br>
1136     *
1137     * Value: {@code true}
1138     *
1139     * <br>
1140     *
1141     * docbkx-tools element: &lt;xincludeSupported&gt;
1142     *
1143     * @return Where documents should be allowed to include other documents.
1144     */
1145    public final String isXincludeSupported() {
1146        return isXincludeSupported;
1147    }
1148
1149    /**
1150     * JavaScript file name, found under {@code /js/} in plugin resources.
1151     */
1152    private String javaScriptFileName = "uses-jquery.js";
1153
1154    /**
1155     * Get the main JavaScript file name, found under {@code /js/} in plugin resources.
1156     *
1157     * <br>
1158     *
1159     * Value: {@code uses-jquery.js}
1160     *
1161     * @return The JavaScript file name.
1162     */
1163    public String getJavaScriptFileName() {
1164        return javaScriptFileName;
1165    }
1166
1167    /**
1168     * The set of source paths where cited Java files are found.
1169     */
1170    @Parameter
1171    private List<File> jCiteSourcePaths;
1172
1173    /**
1174     * Get the source paths where cited Java files are found.
1175     *
1176     * <br>
1177     *
1178     * If source paths are not set, {@code src/main/java} is used.
1179     *
1180     * @return the set of source paths where cited Java files are found.
1181     */
1182    public List<File> getJCiteSourcePaths() {
1183        return jCiteSourcePaths;
1184    }
1185
1186    /**
1187     * JCite version to use for code citations.
1188     */
1189    @Parameter
1190    private String jCiteVersion;
1191
1192    /**
1193     * Get the JCite artifact version to use for Java code citations.
1194     *
1195     * @return The JCite artifact version to use for Java code citations.
1196     */
1197    public String getJCiteVersion() {
1198        return getVersionProperty(jCiteVersion, "jCiteVersion");
1199    }
1200
1201    /**
1202     * Whether to keep a custom index.html file for the documentation set.
1203     */
1204    @Parameter(defaultValue = "false")
1205    private boolean keepCustomIndexHtml;
1206
1207    /**
1208     * Whether to keep a custom index.html file for the documentation set.
1209     *
1210     * <br>
1211     *
1212     * Default: {@code false}
1213     *
1214     * @return Whether to keep a custom index.html file.
1215     */
1216    public boolean keepCustomIndexHtml() {
1217        return keepCustomIndexHtml;
1218    }
1219
1220    /**
1221     * URL to JSON object showing latest versions for each project.
1222     */
1223    @Parameter(defaultValue = "http://docs.wrensecurity.org/latest.json")
1224    private String latestJson;
1225
1226    /**
1227     * Get the URL to JSON object showing latest versions for each project.
1228     *
1229     * @return The URL to the JSON object.
1230     */
1231    public String getLatestJson() {
1232        return latestJson;
1233    }
1234
1235    /**
1236     * ForgeRock link tester plugin version to use.
1237     */
1238    @Parameter
1239    private String linkTesterVersion;
1240
1241    /**
1242     * ForgeRock link tester plugin version to use.
1243     *
1244     * @return The link tester plugin version to use.
1245     */
1246    public String getLinkTesterVersion() {
1247        return getVersionProperty(linkTesterVersion, "linkTesterVersion");
1248    }
1249
1250    /**
1251     * Locale tag for the documentation set.
1252     */
1253    @Parameter(defaultValue = "en")
1254    private String localeTag;
1255
1256    /**
1257     * Get the Locale tag for the documentation set.
1258     *
1259     * <br>
1260     *
1261     * Default: {@code en}
1262     *
1263     * @return The Locale tag for the documentation set.
1264     */
1265    public String getLocaleTag() {
1266        return localeTag;
1267    }
1268
1269    /**
1270     * Location of the man page XSL stylesheet customization file,
1271     * relative to the build directory.
1272     *
1273     * <br>
1274     *
1275     * docbkx-tools element: &lt;manpagesCustomization&gt;
1276     */
1277    private String manpagesCustomization = "docbkx-stylesheets/man/coredoc.xsl";
1278
1279    /**
1280     * Get the location of the man page XSL stylesheet customization file.
1281     *
1282     * <br>
1283     *
1284     * Value: {@code ${project.build.directory}/docbkx-stylesheets/man/coredoc.xsl}
1285     *
1286     * <br>
1287     *
1288     * docbkx-tools element: &lt;manpagesCustomization&gt;
1289     *
1290     * @return The location of the man page XSL stylesheet.
1291     */
1292    public final File getManpagesCustomization() {
1293        return new File(getBuildDirectory(), manpagesCustomization);
1294    }
1295
1296    /**
1297     * Version of the Maven assembly plugin to use.
1298     */
1299    @Parameter
1300    private String mavenAssemblyVersion;
1301
1302    /**
1303     * Get the version of the Maven dependency plugin to use.
1304     * @return The version of the Maven dependency plugin to use.
1305     */
1306    public String getMavenAssemblyVersion() {
1307        return getVersionProperty(mavenAssemblyVersion, "mavenAssemblyVersion");
1308    }
1309
1310    /**
1311     * Version of the Maven dependency plugin to use.
1312     */
1313    @Parameter
1314    private String mavenDependencyVersion;
1315
1316    /**
1317     * Get the version of the Maven dependency plugin to use.
1318     * @return The version of the Maven dependency plugin to use.
1319     */
1320    public String getMavenDependencyVersion() {
1321        return getVersionProperty(mavenDependencyVersion, "mavenDependencyVersion");
1322    }
1323
1324    /**
1325     * Version of the Maven filtering library to use.
1326     */
1327    @Parameter
1328    private String mavenFilteringVersion;
1329
1330    /**
1331     * Get the version of the Maven filtering library to use.
1332     * <br>
1333     * This is used as a workaround for
1334     * <a href="https://jira.codehaus.org/browse/MSHARED-325">MSHARED-325</a>.
1335     *
1336     * @return The version of the Maven filtering library to use.
1337     */
1338    public String getMavenFilteringVersion() {
1339        return getVersionProperty(mavenFilteringVersion, "mavenFilteringVersion");
1340    }
1341
1342    /**
1343     * Maven resources plugin version.
1344     * Executions seem to hit an NPE when the version is not specified.
1345     */
1346    @Parameter
1347    private String mavenResourcesVersion;
1348
1349    /**
1350     * Get the Maven resources plugin version.
1351     * Executions seem to hit an NPE when the version is not specified.
1352     *
1353     * @return The Maven resources plugin version.
1354     */
1355    public String getMavenResourcesVersion() {
1356        return getVersionProperty(mavenResourcesVersion, "mavenResourcesVersion");
1357    }
1358
1359    /**
1360     * Maximum height for PNG images used in PDF, in inches.
1361     */
1362    @Parameter(defaultValue = "5")
1363    private int maxImageHeightInInches;
1364
1365    /**
1366     * Get maximum height for PNG images used in PDF, in inches.
1367     *
1368     * @return Maximum height for PNG images used in PDF, in inches.
1369     */
1370    public int getMaxImageHeightInInches() {
1371        return maxImageHeightInInches;
1372    }
1373
1374    /**
1375     * Overwrite the copy of DocBook sources if it exists.
1376     */
1377    @Parameter(defaultValue = "true")
1378    private boolean overwriteModifiableCopy;
1379
1380    /**
1381     * Whether to overwrite the copy of DocBook sources if it exists.
1382     *
1383     * <br>
1384     *
1385     * One of the first things the plugin does when preparing DocBook sources
1386     * is to make a working copy of the files that is separate from the sources.
1387     * This allows the plugin to make changes to the files as necessary.
1388     *
1389     * <br>
1390     *
1391     * If for some reason you must provide the copy yourself,
1392     * and your copy must be in the {@code docbkxModifiableSourcesDirectory},
1393     * then you can set this to {@code false}
1394     * to prevent the plugin from replacing the copy.
1395     * The plugin will then pre-process the copy, however,
1396     * so expect the files in the modifiable copy to be changed.
1397     *
1398     * <br>
1399     *
1400     * Default: true
1401     *
1402     * @return Whether to overwrite the copy of DocBook sources if it exists.
1403     */
1404    public boolean doOverwriteModifiableCopy() {
1405        return overwriteModifiableCopy;
1406    }
1407
1408    /**
1409     * Overwrite project files with shared content.
1410     */
1411    @Parameter(defaultValue = "true", property = "overwriteProjectFilesWithSharedContent")
1412    private boolean overwriteProjectFilesWithSharedContent;
1413
1414    /**
1415     * Whether to overwrite project files with shared content.
1416     *
1417     * <br>
1418     *
1419     * Default: true
1420     *
1421     * @return Whether to overwrite project files with shared content.
1422     */
1423    public boolean doOverwriteProjectFilesWithSharedContent() {
1424        return overwriteProjectFilesWithSharedContent;
1425    }
1426
1427    /**
1428     * Get path name in UNIX format.
1429     *
1430     * @param file Path to return in UNIX format.
1431     * @return The path in UNIX format.
1432     */
1433    public String path(final File file) {
1434        String result = "";
1435        if (file != null) {
1436            result = FilenameUtils.separatorsToUnix(file.getPath());
1437        }
1438        return result;
1439    }
1440
1441    /**
1442     * Version of the PlantUML artifact to use.
1443     */
1444    @Parameter
1445    private String plantUmlVersion;
1446
1447    /**
1448     * Get the version of the PlantUML artifact.
1449     *
1450     * @return The version of the PlantUML artifact.
1451     */
1452    public String getPlantUmlVersion() {
1453        return getVersionProperty(plantUmlVersion, "plantUmlVersion");
1454    }
1455
1456    /**
1457     * The version of Plexus Utils used by the XCite Maven plugin.
1458     */
1459    @Parameter
1460    private String plexusUtilsVersion;
1461
1462    /**
1463     * Return the version of Plexus Utils used by the XCite Maven plugin.
1464     *
1465     * @return The version of Plexus Utils used by the XCite Maven plugin.
1466     */
1467    public String getPlexusUtilsVersion() {
1468        return getVersionProperty(plexusUtilsVersion, "plexusUtilsVersion");
1469    }
1470
1471    /**
1472     * The Maven {@code BuildPluginManager} object.
1473     */
1474    @Component
1475    private BuildPluginManager pluginManager;
1476
1477    /**
1478     * Get the Maven {@code BuildPluginManager} object.
1479     *
1480     * @return The Maven {@code BuildPluginManager} object.
1481     */
1482    public BuildPluginManager getPluginManager() {
1483        return pluginManager;
1484    }
1485
1486    /**
1487     * CSS file for the pre-site version of the HTML,
1488     * relative to the build directory.
1489     */
1490    private String preSiteCssFileName = "coredoc.css";
1491
1492    /**
1493     * Get the CSS file for the pre-site version of the HTML.
1494     *
1495     * <br>
1496     *
1497     * Value: {@code ${project.build.directory}/coredoc.css}
1498     *
1499     * @return The CSS file.
1500     */
1501    public final File getPreSiteCss() {
1502        return new File(getBuildDirectory(), preSiteCssFileName);
1503    }
1504
1505    /**
1506     * The {@code MavenProject} object, which is read-only.
1507     */
1508    @Parameter(property = "project", required = true, readonly = true)
1509    private MavenProject project;
1510
1511    /**
1512     * Get the {@code MavenProject} object.
1513     *
1514     * @return The {@code MavenProject} object.
1515     */
1516    public MavenProject getProject() {
1517        return project;
1518    }
1519
1520    /**
1521     * Short name of the project, such as OpenAM, OpenDJ, OpenIDM.
1522     */
1523    @Parameter(property = "projectName", required = true)
1524    private String projectName;
1525
1526    /**
1527     * Short name of the project, such as OpenAM, OpenDJ, OpenIDM.
1528     *
1529     * @return The short name of the project.
1530     */
1531    public String getProjectName() {
1532        return projectName;
1533    }
1534
1535    /**
1536     * Project version.
1537     */
1538    @Parameter(property = "projectVersion", required = true)
1539    private String projectVersion;
1540
1541    /**
1542     * Get the project version.
1543     *
1544     * @return The project version.
1545     */
1546    public String getProjectVersion() {
1547        return projectVersion;
1548    }
1549
1550    /**
1551     * CSS file for the release version of the HTML,
1552     * relative to the build directory.
1553     */
1554    private String releaseCssFileName = "dfo.css";
1555
1556    /**
1557     * Get the CSS file for the release version of the HTML.
1558     *
1559     * <br>
1560     *
1561     * Value: {@code ${project.build.directory}/dfo.css}
1562     *
1563     * @return The CSS file.
1564     */
1565    public final File getReleaseCss() {
1566        return new File(getBuildDirectory(), releaseCssFileName);
1567    }
1568
1569    /**
1570     * Software release date.
1571     */
1572    @Parameter(property = "releaseDate")
1573    private String releaseDate;
1574
1575    /**
1576     * Get the software release date.
1577     *
1578     * <br>
1579     *
1580     * Default: now
1581     *
1582     * @return The software release date.
1583     */
1584    public String getReleaseDate() {
1585        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
1586        return releaseDate == null || releaseDate.isEmpty() ? format.format(new Date()) : releaseDate;
1587    }
1588
1589    /**
1590     * File system directory for release layout documentation,
1591     * relative to the build directory.
1592     */
1593    @Parameter(defaultValue = "release")
1594    private String releaseDirectory;
1595
1596    /**
1597     * Get the file system directory for release layout documentation.
1598     *
1599     * <br>
1600     *
1601     * Default: {@code ${project.build.directory}/release}
1602     *
1603     * @return {@link #releaseDirectory}
1604     */
1605    public final File getReleaseDirectory() {
1606        return new File(getBuildDirectory(), releaseDirectory);
1607    }
1608
1609    /**
1610     * Favicon link element for the release version of the HTML.
1611     */
1612    @Parameter(defaultValue = "<link rel=\"shortcut icon\" href=\"https://wrensecurity.org/favicon.ico\">")
1613    private String releaseFaviconLink;
1614
1615    /**
1616     * Get the favicon link element for the release version of the HTML.
1617     *
1618     * @return The link element.
1619     */
1620    public final String getReleaseFaviconLink() {
1621        return releaseFaviconLink;
1622    }
1623
1624    /**
1625     * Version for this release.
1626     */
1627    @Parameter(property = "releaseVersion", required = true)
1628    private String releaseVersion;
1629
1630    /**
1631     * Get the version for this release.
1632     *
1633     * @return The version for this release.
1634     */
1635    public final String getReleaseVersion() {
1636        return releaseVersion;
1637    }
1638
1639    /**
1640     * Get the path to the directory to hold the release version documents,
1641     * such as {@code ${project.build.directory}/release/1.0.0}.
1642     *
1643     * @return The path to the release version directory.
1644     */
1645    public final String getReleaseVersionPath() {
1646        return getReleaseDirectory().getPath() + File.separator + getReleaseVersion();
1647    }
1648
1649    /**
1650     * File system directory for arbitrary documentation set resources,
1651     * relative to the modifiable sources directory.
1652     */
1653    @Parameter(defaultValue = "resources")
1654    private String resourcesDirectory;
1655
1656    /**
1657     * Path to arbitrary documentation set resources,
1658     * relative to the modifiable sources directory.
1659     *
1660     * <br>
1661     *
1662     * Default: {@code resources}
1663     *
1664     * @return The resources directory path, relative to the modifiable sources directory.
1665     */
1666    public String getRelativeResourcesDirectoryPath() {
1667        return resourcesDirectory;
1668    }
1669
1670    /**
1671     * Directory for arbitrary documentation set resources.
1672     *
1673     * <br>
1674     *
1675     * Default: {@code ${basedir}/src/main/docbkx/resources}
1676     *
1677     * @return The resources directory.
1678     */
1679    public File getResourcesDirectory() {
1680        return new File(getDocbkxModifiableSourcesDirectory(), resourcesDirectory);
1681    }
1682
1683    /**
1684     * Whether to run the ForgeRock link tester plugin.
1685     */
1686    @Parameter(defaultValue = "true", property = "runLinkTester")
1687    private String runLinkTester;
1688
1689    /**
1690     * Whether to run the ForgeRock link tester plugin.
1691     *
1692     * <br>
1693     *
1694     * You only need to run the link test from the top level of a project.
1695     *
1696     * <br>
1697     *
1698     * Default: {@code "true"}
1699     *
1700     * @return Whether to run the ForgeRock link tester plugin.
1701     */
1702    public String runLinkTester() {
1703        return runLinkTester;
1704    }
1705
1706    /**
1707     * The {@code MavenSession} object, which is read-only.
1708     */
1709    @Parameter(property = "session", required = true, readonly = true)
1710    private MavenSession session;
1711
1712    /**
1713     * Get the {@code MavenSession} object.
1714     * @return The {@code MavenSession} object.
1715     */
1716    public MavenSession getSession() {
1717        return session;
1718    }
1719
1720    /**
1721     * Location of the single page HTML XSL stylesheet customization file,
1722     * relative to the build directory.
1723     *
1724     * <br>
1725     *
1726     * docbkx-tools element: &lt;htmlCustomization&gt;
1727     */
1728    private String singleHTMLCustomization = "/docbkx-stylesheets/html/coredoc.xsl";
1729
1730    /**
1731     * Get the location of the single page HTML XSL stylesheet customization file.
1732     *
1733     * <br>
1734     *
1735     * Value: {@code ${project.build.directory}/docbkx-stylesheets/html/coredoc.xsl}
1736     *
1737     * <br>
1738     *
1739     * docbkx-tools element: &lt;htmlCustomization&gt;
1740     *
1741     * @return The location of the single-page HTML XSL stylesheet.
1742     */
1743    public final File getSingleHTMLCustomization() {
1744        return new File(getBuildDirectory(), singleHTMLCustomization);
1745    }
1746
1747    /**
1748     * File system directory for site content, relative to the build directory.
1749     */
1750    @Parameter(defaultValue = "site")
1751    private String siteDirectory;
1752
1753    /**
1754     * Get the file system directory for site content.
1755     *
1756     * <br>
1757     *
1758     * Default: {@code ${project.build.directory}/site}
1759     *
1760     * @return The file system directory for site content.
1761     */
1762    public final File getSiteDirectory() {
1763        return new File(getBuildDirectory(), siteDirectory);
1764    }
1765
1766    /**
1767     * Whether the ForgeRock link tester plugin should skip checking
1768     * that external URLs are valid.
1769     *
1770     * <br>
1771     *
1772     * See the {@code skipUrls} parameter of the <a
1773     * href="https://github.com/aldaris/docbook-linktester/">linktester plugin</a>.
1774     */
1775    @Parameter(defaultValue = "false", property = "skipLinkCheck")
1776    private String skipLinkCheck;
1777
1778    /**
1779     * Whether the ForgeRock link tester plugin should skip checking
1780     * that external URLs are valid.
1781     *
1782     * <br>
1783     *
1784     * See the {@code skipUrls} parameter of the <a
1785     * href="https://github.com/aldaris/docbook-linktester/">linktester plugin</a>.
1786     *
1787     * <br>
1788     *
1789     * Default: {@code false}
1790     *
1791     * @return Whether to test that external URLs are valid.
1792     */
1793    public String skipLinkCheck() {
1794        return skipLinkCheck;
1795    }
1796
1797    /**
1798     * Regex patterns of URLs to skip when checking external links.
1799     *
1800     * <br>
1801     *
1802     * See the {@code skipUrlPatterns} parameter of the <a
1803     * href="https://github.com/aldaris/docbook-linktester/">linktester plugin</a>.
1804     */
1805    @Parameter
1806    private String[] skipUrlPatterns;
1807
1808    /**
1809     * Get regex patterns of URLs to skip when checking external links.
1810     *
1811     * <br>
1812     *
1813     * Default: {@code null}
1814     *
1815     * @return Regex patterns of URLs to skip when checking external links.
1816     */
1817    public String[] getSkipUrlPatterns() {
1818        return skipUrlPatterns;
1819    }
1820
1821    /**
1822     * Whether to build from pre-processed DocBook XML sources.
1823     */
1824    @Parameter(defaultValue = "false", property = "usePreProcessedSources")
1825    private boolean usePreProcessedSources;
1826
1827    /**
1828     * Whether to build from pre-processed DocBook XML sources.
1829     *
1830     * <p>
1831     *
1832     * Default: {@code false}
1833     *
1834     * @return True if {@code docbkxSourceDirectory} contains fully pre-processed sources.
1835     */
1836    public boolean doUsePreProcessedSources() {
1837        return usePreProcessedSources;
1838    }
1839
1840    /**
1841     * Whether &lt;programlisting&gt; content has syntax highlighting.
1842     *
1843     * <br>
1844     *
1845     * docbkx-tools element: &lt;highlightSource&gt;
1846     */
1847    private String useSyntaxHighlighting = "1";
1848
1849    /**
1850     * Whether &lt;programlisting&gt; content has syntax highlighting.
1851     *
1852     * <br>
1853     *
1854     * Value: {@code 1} (true)
1855     *
1856     * <br>
1857     *
1858     * docbkx-tools element: &lt;highlightSource&gt;
1859     *
1860     * @return Where program listings use syntax highlighting.
1861     */
1862    public final String useSyntaxHighlighting() {
1863        return useSyntaxHighlighting;
1864    }
1865
1866    /**
1867     * Location of the main CSS for webhelp documents,
1868     * relative to the build directory.
1869     */
1870    private String webhelpCss = "docbkx-stylesheets/webhelp/positioning.css";
1871
1872    /**
1873     * Get the location of the main CSS file for webhelp documents.
1874     *
1875     * <br>
1876     *
1877     * Value: {@code ${project.build.dir}/docbkx-stylesheets/webhelp/positioning.css}
1878     *
1879     * @return The main CSS file for webhelp documents.
1880     */
1881    public final File getWebHelpCss() {
1882        return new File(getBuildDirectory(), webhelpCss);
1883    }
1884
1885    /**
1886     * Location of the webhelp XSL stylesheet customization file, relative to
1887     * the build
1888     * directory.
1889     *
1890     * <br>
1891     *
1892     * docbkx-tools element: &lt;webhelpCustomization&gt;
1893     */
1894    private String webhelpCustomization = "docbkx-stylesheets/webhelp/coredoc.xsl";
1895
1896    /**
1897     * Get the location of the webhelp XSL stylesheet customization file.
1898     *
1899     * <br>
1900     *
1901     * Value: {@code ${project.build.dir}/docbkx-stylesheets/webhelp/coredoc.xsl}
1902     *
1903     * <br>
1904     *
1905     * docbkx-tools element: &lt;webhelpCustomization&gt;
1906     *
1907     * @return The location of the webhelp XSL stylesheet.
1908     */
1909    public final File getWebHelpCustomization() {
1910        return new File(getBuildDirectory(), webhelpCustomization);
1911    }
1912
1913    /**
1914     * Location of the logo image for webhelp documents,
1915     * relative to the build directory.
1916     */
1917    private String webhelpLogo = "docbkx-stylesheets/webhelp/logo.png";
1918
1919    /**
1920     * Get the location of the logo image for webhelp documents.
1921     *
1922     * <br>
1923     *
1924     * Value: {@code ${project.build.dir}/docbkx-stylesheets/webhelp/logo.png}
1925     *
1926     * @return The logo image for webhelp documents.
1927     */
1928    public final File getWebHelpLogo() {
1929        return new File(getBuildDirectory(), webhelpLogo);
1930    }
1931
1932    /**
1933     * Version of the XCite Maven plugin to use.
1934     */
1935    @Parameter
1936    private String xCiteVersion;
1937
1938    /**
1939     * Return the version of the XCite Maven plugin to use.
1940     *
1941     * @return The version of the XCite Maven plugin to use.
1942     */
1943    public String getXCiteVersion() {
1944        return getVersionProperty(xCiteVersion, "xCiteVersion");
1945    }
1946
1947    /**
1948     * Location of the XHTML5 XSL stylesheet customization file,
1949     * relative to the build directory.
1950     *
1951     * <br>
1952     *
1953     * docbkx-tools element: &lt;xhtml5Customization&gt;
1954     */
1955    private String xhtml5Customization = "docbkx-stylesheets/xhtml5/coredoc.xsl";
1956
1957    /**
1958     * Location of the XHTML5 XSL stylesheet customization file,
1959     * relative to the build directory.
1960     *
1961     * <br>
1962     *
1963     * Value: {@code ${project.build.directory}/docbkx-stylesheets/xhtml5/coredoc.xsl}
1964     *
1965     * <br>
1966     *
1967     * Default: {@code ${project.build.directory}/docbkx-stylesheets/xhtml5/coredoc.xsl}
1968     *
1969     * <br>
1970     *
1971     * docbkx-tools element: &lt;xhtml5Customization&gt;
1972     *
1973     * @return The location of the XHTML5 XSL stylesheet.
1974     */
1975    public final File getXhtml5Customization() {
1976        return new File(getBuildDirectory(), xhtml5Customization);
1977    }
1978
1979    /**
1980     * Location of the HtmlForBootstrap XSL stylesheet customization file,
1981     * relative to the build directory.
1982     *
1983     * <br>
1984     *
1985     * docbkx-tools element: &lt;bootstrapCustomization&gt;
1986     */
1987    private String bootstrapCustomization =
1988            "docbkx-stylesheets/bootstrap/coredoc.xsl";
1989    /**
1990     * Get the location of the HtmlForBootstrap XSL stylesheet customization file.
1991     *
1992     * <br>
1993     *
1994     * Default: {@code ${project.build.directory}/docbkx-stylesheets/bootstrap/coredoc.xsl}
1995     *
1996     * <br>
1997     *
1998     * docbkx-tools element: &lt;bootstrapCustomization&gt;
1999     *
2000     * @return The location of the HtmlForBootstrap XSL stylesheet.
2001     */
2002    public final File getBootstrapCustomization() {
2003        return new File(getBuildDirectory(), bootstrapCustomization);
2004    }
2005}