View Javadoc
1   /*
2    * The contents of this file are subject to the terms of the Common Development and
3    * Distribution License (the License). You may not use this file except in compliance with the
4    * License.
5    *
6    * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
7    * specific language governing permission and limitations under the License.
8    *
9    * When distributing Covered Software, include this CDDL Header Notice in each file and include
10   * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
11   * Header, with the fields enclosed by brackets [] replaced by your own identifying
12   * information: "Portions copyright [year] [name of copyright owner]".
13   *
14   * Copyright 2012-2015 ForgeRock AS.
15   */
16  
17  package org.forgerock.doc.maven.utils;
18  
19  import java.io.File;
20  import java.io.FileFilter;
21  import java.io.FilenameFilter;
22  import java.io.IOException;
23  import java.util.Set;
24  import java.util.TreeSet;
25  import java.util.regex.Pattern;
26  
27  import org.apache.commons.io.FileUtils;
28  import org.apache.commons.io.FilenameUtils;
29  import org.codehaus.plexus.util.StringUtils;
30  
31  /**
32   * Utility methods to work with documents.
33   */
34  public final class NameUtils {
35      /**
36       * Pattern to validate the document names.
37       *
38       * <br>
39       *
40       * project-doc-version names are not expected in published docs,
41       * @see #renameDoc(String, String, String, String)
42       *
43       * <br>
44       *
45       * When published, documentation file names
46       * should include the version before the document name:
47       * Project-Version-Doc-Name.ext
48       *
49       * @deprecated since 3.0.0
50       *
51       * <p>Valid names:</p>
52       * <ul>
53       *     <li>guide</li>
54       *     <li>admin-quide</li>
55       *     <li>OpenTEST-guide</li>
56       *     <li>OpenTEST-admin-guide</li>
57       *     <li>OpenTEST-admin-guide-1.1.1.0</li>
58       *     <li>OpenTEST-admin-guide-1.1.1.0-SNAPSHOT</li>
59       *     <li>OpenTEST-admin-guide-1.1.1.0-express</li>
60       *     <li>OpenTEST-admin-guide-1.1.1.0-Xpress</li>
61       *     <li>OpenTEST-admin-guide-1.1.1.0-Xpress1</li>
62       *     <li>OpenTEST-10.1.0-admin-guide</li>
63       *     <li>OpenTEST-10.1.0-SNAPSHOT-admin-guide</li>
64       *     <li>OpenTEST-10.1.0-Xpress2-admin-guide</li>
65       *     <li>db2-connector-1.1.0.0-SNAPSHOT</li>
66       * </ul>
67       *
68       * <p>Invalid names:</p>
69       * <ul>
70       *     <li>guide.</li>
71       *     <li>guide-1</li>
72       *     <li>guide-.</li>
73       * </ul>
74       */
75      @Deprecated
76      public static final Pattern DOCUMENT_FILE_PATTERN = Pattern
77              .compile("^([a-zA-Z0-9]+)(-?[0-9].[0-9\\.]*[0-9])?(-SNAPSHOT|(-Ex|-ex|-X)press[0-9])"
78                      + "?([a-zA-Z-]*)((-?[0-9].[0-9\\.]*[0-9])?-?(SNAPSHOT|(Ex|ex|X)press[0-9]?)?)$");
79  
80      /**
81       * Rename document to reflect project and document name. For example,
82       * index.pdf could be renamed OpenAM-Admin-Guide.pdf.
83       *
84       * @param projectName
85       *            Short name of the project, such as OpenAM, OpenDJ, OpenIDM
86       * @param docName
87       *            Short name for the document, such as admin-guide,
88       *            release-notes, reference
89       * @param extension
90       *            File name extension not including dot, e.g. pdf
91       * @return New name for document. Can be "" if rename failed.
92       */
93      public static String renameDoc(final String projectName,
94                                     final String docName,
95                                     final String extension) {
96          return renameDoc(projectName, docName, "", extension);
97      }
98  
99      /**
100      * Rename document to reflect project and document name. For example,
101      * index.pdf could be renamed OpenAM-10.0.0-Admin-Guide.pdf.
102      *
103      * @param projectName
104      *            Short name of the project, such as OpenAM, OpenDJ, OpenIDM
105      * @param docName
106      *            Short name for the document, such as admin-guide,
107      *            release-notes, reference
108      * @param version
109      *            Document version such as 10.0.0, 2.5.0, 2.0.2
110      * @param extension
111      *            File name extension not including dot, e.g. pdf
112      * @return New name for document. Can be "" if rename failed.
113      */
114     public static String renameDoc(final String projectName,
115                                    final String docName,
116                                    final String version,
117                                    final String extension) {
118 
119         // Doc name must be non-empty.
120         if (!StringUtils.isNotBlank(docName)) {
121             return "";
122         }
123 
124         StringBuilder sb = new StringBuilder();
125 
126         // If project name exists, capitalize it, replace spaces with hyphens,
127         // and follow the result with a hyphen.
128         if (StringUtils.isNotBlank(projectName)) {
129             sb.append(spacesToHyphens(capitalize(projectName))).append('-');
130 
131             // Version precedes the document name.
132             // It only makes sense to use a version if a project name is defined.
133             // If version exists, follow it with a hyphen.
134             if (StringUtils.isNotBlank(version)) {
135                 sb.append(version).append('-');
136             }
137         }
138 
139         // Capitalize the doc name.
140         sb.append(capitalize(docName));
141 
142         // If extension exists, precede it with a .
143         if (StringUtils.isNotBlank(extension)) {
144             sb.append('.').append(extension);
145         }
146 
147         return sb.toString();
148     }
149 
150     /**
151      * Capitalize initial letters in a document name.
152      *
153      * @param docName
154      *            Name of the document such as reference or admin-guide
155      * @return Capitalized name such as Reference or Admin-Guide
156      */
157     protected static String capitalize(final String docName) {
158         char[] chars = docName.toCharArray();
159 
160         boolean isInitial = true;
161         for (int i = 0; i < chars.length; i++) {
162             if (isInitial && Character.isLetter(chars[i])) {
163                 chars[i] = Character.toUpperCase(chars[i]);
164                 isInitial = false;
165             } else {
166                 isInitial = !Character.isLetter(chars[i]);
167             }
168         }
169 
170         return String.valueOf(chars);
171     }
172 
173     /**
174      * Replace spaces with hyphens.
175      *
176      * @param   string  String in which to replace spaces with hyphens
177      * @return  String with spaces replaced by hyphens.
178      */
179     protected static String spacesToHyphens(final String string) {
180         return string.replaceAll(" ", "-");
181     }
182 
183     /**
184      * Returns names of directories that mirror the document names and contain
185      * DocBook XML documents to build.
186      *
187      * @param srcDir
188      *            Directory containing DocBook XML sources. Document directories
189      *            like admin-guide or reference are one level below this
190      *            directory.
191      * @param docFile
192      *            Name of a file common to all documents to build, such as
193      *            index.xml.
194      * @return Document names, as in admin-guide or reference
195      */
196     public static Set<String> getDocumentNames(final File srcDir,
197                                                final String docFile) {
198         Set<String> documentDirectories = new TreeSet<String>();
199 
200         // Match directories containing DocBook document entry point files,
201         // and ignore everything else.
202         FileFilter filter = new FileFilter() {
203             @Override
204             public boolean accept(final File file) {
205                 return file.isDirectory();
206             }
207         };
208 
209         File[] directories = srcDir.listFiles(filter);
210         if (directories != null && directories.length > 0) {
211 
212             FilenameFilter nameFilter = new FilenameFilter() {
213                 @Override
214                 public boolean accept(final File file, final String name) {
215                     return name.equalsIgnoreCase(docFile);
216                 }
217             };
218 
219             for (File dir : directories) {
220                 String[] found = dir.list(nameFilter);
221                 if (found.length > 0) {
222                     documentDirectories.add(dir.getName());
223                 }
224             }
225         }
226 
227         return documentDirectories;
228     }
229 
230     /**
231      * Rename a single built document.
232      * For example, rename {@code index.pdf} to {@code OpenAM-Admin-Guide.pdf}.
233      *
234      * @param builtDocument File to rename, such as {@code index.pdf}.
235      * @param docName       Simple document name such as {@code admin-guide}.
236      * @param projectName   Project name, such as {@code OpenAM}.
237      * @throws IOException  Something went wrong renaming the file.
238      */
239     public static void renameDocument(final File builtDocument,
240                                       final String docName,
241                                       final String projectName)
242             throws IOException {
243         String ext = FilenameUtils.getExtension(builtDocument.getName());
244         File newFile = new File(builtDocument.getParent(), renameDoc(projectName, docName, ext));
245         if (!newFile.exists()) {
246             FileUtils.moveFile(builtDocument, newFile);
247         }
248     }
249 
250     /**
251      * Not used.
252      */
253     private NameUtils() {
254     }
255 }