001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.tools.propertiesdoc;
016    
017    import com.liferay.portal.freemarker.FreeMarkerUtil;
018    import com.liferay.portal.kernel.util.CharPool;
019    import com.liferay.portal.kernel.util.GetterUtil;
020    import com.liferay.portal.kernel.util.StringBundler;
021    import com.liferay.portal.kernel.util.StringPool;
022    import com.liferay.portal.kernel.util.StringUtil;
023    import com.liferay.portal.kernel.util.Validator;
024    import com.liferay.portal.tools.ArgumentsUtil;
025    import com.liferay.portal.util.FileImpl;
026    
027    import java.io.File;
028    import java.io.FileWriter;
029    import java.io.IOException;
030    import java.io.Writer;
031    
032    import java.util.ArrayList;
033    import java.util.HashMap;
034    import java.util.List;
035    import java.util.Map;
036    
037    /**
038     * @author Jesse Rao
039     * @author James Hinkey
040     */
041    public class PropertiesDocBuilder {
042    
043            public static void main(String[] args) throws Exception {
044                    Map<String, String> arguments = ArgumentsUtil.parseArguments(args);
045    
046                    try {
047                            new PropertiesDocBuilder(arguments);
048                    }
049                    catch (Exception e) {
050                            ArgumentsUtil.processMainException(arguments, e);
051                    }
052            }
053    
054            public PropertiesDocBuilder(Map<String, String> arguments)
055                    throws IOException {
056    
057                    String propertiesDestDirName = GetterUtil.getString(
058                            arguments.get("properties.dest.dir"));
059                    String propertiesFileName = GetterUtil.getString(
060                            arguments.get("properties.file"));
061                    String title = GetterUtil.getString(arguments.get("properties.title"));
062                    boolean toc = GetterUtil.getBoolean(arguments.get("properties.toc"));
063    
064                    System.out.println("Converting " + propertiesFileName + " to HTML");
065    
066                    File propertiesFile = new File(propertiesFileName);
067    
068                    Map<String, Object> context = new HashMap<>();
069    
070                    context.put("pageTitle", title);
071    
072                    int pos = propertiesFileName.lastIndexOf(StringPool.SLASH);
073    
074                    if (pos != -1) {
075                            propertiesFileName = propertiesFileName.substring(pos + 1);
076                    }
077    
078                    context.put("propertiesFileName", propertiesFileName);
079    
080                    List<PropertiesSection> propertiesSections = getPropertiesSections(
081                            propertiesFile);
082    
083                    if (propertiesSections == null) {
084                            return;
085                    }
086    
087                    context.put("sections", propertiesSections);
088    
089                    context.put("toc", toc);
090    
091                    try {
092                            StringBundler sb = new StringBundler(4);
093    
094                            sb.append(propertiesDestDirName);
095                            sb.append(StringPool.SLASH);
096                            sb.append(propertiesFileName);
097                            sb.append(".html");
098    
099                            String propertiesHTMLFileName = sb.toString();
100    
101                            File propertiesHTMLFile = new File(propertiesHTMLFileName);
102    
103                            System.out.println("Writing " + propertiesHTMLFile);
104    
105                            Writer writer = new FileWriter(propertiesHTMLFile);
106    
107                            try {
108                                    FreeMarkerUtil.process(
109                                            "com/liferay/portal/tools/propertiesdoc/dependencies/" +
110                                                    "properties.ftl",
111                                            context, writer);
112                            }
113                            catch (Exception e) {
114                                    e.printStackTrace();
115                            }
116    
117                            writer.flush();
118                    }
119                    catch (IOException ioe) {
120                            ioe.printStackTrace();
121                    }
122            }
123    
124            protected void addPropertyComment(
125                    List<PropertyComment> propertyComments, String comment) {
126    
127                    if (Validator.isNotNull(comment)) {
128                            PropertyComment propertyComment = new PropertyComment(comment);
129    
130                            propertyComments.add(propertyComment);
131                    }
132            }
133    
134            protected List<String> extractComments(String[] lines) {
135                    List<String> comments = new ArrayList<>();
136    
137                    StringBundler sb = new StringBundler();
138    
139                    for (String line : lines) {
140                            String trimmedLine = line.trim();
141    
142                            if (trimmedLine.startsWith("## ")) {
143                                    trimmedLine = trimmedLine.substring(2);
144    
145                                    sb.append(trimmedLine.trim());
146                            }
147    
148                            if (trimmedLine.length() < 3) {
149                                    if (sb.index() == 0) {
150                                            continue;
151                                    }
152    
153                                    comments.add(sb.toString());
154    
155                                    sb = new StringBundler();
156                            }
157                    }
158    
159                    return comments;
160            }
161    
162            protected String extractDefaultProperties(String[] lines) {
163                    StringBundler sb = new StringBundler();
164    
165                    boolean previousLineIsDefaultProperty = false;
166    
167                    for (String line : lines) {
168                            if (!previousLineIsDefaultProperty) {
169                                    if (!line.startsWith("#") && !line.startsWith(INDENT + "#")) {
170                                            previousLineIsDefaultProperty = true;
171    
172                                            sb.append(line);
173                                            sb.append(StringPool.NEW_LINE);
174                                    }
175                            }
176                            else {
177                                    if (line.startsWith("#") || line.startsWith(INDENT + "#")) {
178                                            previousLineIsDefaultProperty = false;
179    
180                                            continue;
181                                    }
182    
183                                    sb.append(line);
184                                    sb.append(StringPool.NEW_LINE);
185                            }
186                    }
187    
188                    return sb.toString();
189            }
190    
191            protected String extractExampleProperties(String[] lines) {
192                    StringBundler sb = new StringBundler();
193    
194                    boolean previousLineIsExample = false;
195    
196                    for (String line : lines) {
197                            String trimmedLine = line.trim();
198    
199                            if (!previousLineIsExample) {
200                                    if (line.startsWith(INDENT + "# ") || trimmedLine.equals("#")) {
201                                            continue;
202                                    }
203    
204                                    if (line.startsWith(INDENT + "#")) {
205                                            previousLineIsExample = true;
206    
207                                            String exampleProperty =
208                                                    StringUtil.replaceFirst(line, "#", StringPool.BLANK) +
209                                                            StringPool.NEW_LINE;
210    
211                                            sb.append(exampleProperty);
212                                    }
213                            }
214                            else {
215                                    if (!trimmedLine.startsWith("#")) {
216                                            previousLineIsExample = false;
217    
218                                            continue;
219                                    }
220    
221                                    String exampleProperty =
222                                            line.replaceFirst("#", StringPool.BLANK) +
223                                                    StringPool.NEW_LINE;
224    
225                                    sb.append(exampleProperty);
226                            }
227                    }
228    
229                    return sb.toString();
230            }
231    
232            protected List<PropertyComment> extractPropertyComments(String[] lines) {
233                    List<PropertyComment> propertyComments = new ArrayList<>();
234    
235                    StringBundler sb = new StringBundler();
236    
237                    boolean previousLineIsPreformatted = false;
238    
239                    for (String line : lines) {
240                            line = StringUtil.trimTrailing(line);
241    
242                            if (line.startsWith(DOUBLE_INDENT + "#")) {
243                                    break;
244                            }
245    
246                            String trimmedLine = line.trim();
247    
248                            if (trimmedLine.startsWith("# " + INDENT)) {
249                                    if (previousLineIsPreformatted) {
250                                            sb.append(
251                                                    StringUtil.replaceFirst(
252                                                            trimmedLine, "#", StringPool.BLANK));
253                                    }
254                                    else {
255                                            addPropertyComment(propertyComments, sb.toString());
256    
257                                            sb = new StringBundler();
258    
259                                            sb.append(
260                                                    StringUtil.replaceFirst(
261                                                            trimmedLine, "#", StringPool.BLANK));
262                                    }
263    
264                                    sb.append(StringPool.NEW_LINE);
265    
266                                    previousLineIsPreformatted = true;
267                            }
268                            else if (trimmedLine.startsWith("# ")) {
269                                    if (previousLineIsPreformatted) {
270                                            addPropertyComment(propertyComments, sb.toString());
271    
272                                            sb = new StringBundler();
273    
274                                            trimmedLine = StringUtil.replaceFirst(
275                                                    trimmedLine, "#", StringPool.BLANK);
276    
277                                            sb.append(trimmedLine.trim());
278                                    }
279                                    else {
280                                            if (sb.length() > 0) {
281                                                    sb.append(StringPool.SPACE);
282                                            }
283    
284                                            line = StringUtil.replaceFirst(line, "#", StringPool.BLANK);
285    
286                                            sb.append(line.trim());
287                                    }
288    
289                                    sb.append(StringPool.NEW_LINE);
290    
291                                    previousLineIsPreformatted = false;
292                            }
293                            else if (trimmedLine.startsWith("#") &&
294                                             (trimmedLine.length() < 2)) {
295    
296                                    addPropertyComment(propertyComments, sb.toString());
297    
298                                    sb = new StringBundler();
299                            }
300                            else {
301                                    addPropertyComment(propertyComments, sb.toString());
302    
303                                    break;
304                            }
305                    }
306    
307                    return propertyComments;
308            }
309    
310            protected String extractTitle(String[] lines) {
311                    if ((lines == null) || (lines.length <= 1)) {
312                            return null;
313                    }
314    
315                    String title = lines[1];
316    
317                    title = StringUtil.replaceFirst(title, "##", StringPool.BLANK);
318    
319                    return title.trim();
320            }
321    
322            protected int getLineCount(String sectionString) {
323                    String[] lines = sectionString.split("\r\n|\r|\n");
324    
325                    return lines.length;
326            }
327    
328            protected List<PropertiesSection> getPropertiesSections(File propertiesFile)
329                    throws IOException {
330    
331                    String content = _fileUtil.read(propertiesFile);
332    
333                    String[] sections = content.split("\n\n");
334    
335                    List<PropertiesSection> propertiesSections = new ArrayList<>(
336                            sections.length);
337    
338                    for (String section : sections) {
339                            section = StringUtil.trimLeading(section, CharPool.SPACE);
340    
341                            PropertiesSection propertiesSection = new PropertiesSection(
342                                    section);
343    
344                            String[] lines = section.split(StringPool.NEW_LINE);
345    
346                            if (section.startsWith("##")) {
347                                    int lineCount = getLineCount(section);
348    
349                                    if (lineCount == 3) {
350                                            propertiesSection.setTitle(extractTitle(lines));
351    
352                                            propertiesSections.add(propertiesSection);
353                                    }
354                                    else if (lineCount > 3) {
355                                            propertiesSection.setComments(extractComments(lines));
356    
357                                            propertiesSections.add(propertiesSection);
358                                    }
359                                    else {
360                                            StringBundler sb = new StringBundler(8);
361    
362                                            sb.append("Properties section should consist of 3 ");
363                                            sb.append("or more lines:");
364                                            sb.append(StringPool.NEW_LINE);
365                                            sb.append("##");
366                                            sb.append(StringPool.NEW_LINE);
367                                            sb.append("## Comments");
368                                            sb.append(StringPool.NEW_LINE);
369                                            sb.append("##");
370    
371                                            System.out.println(sb.toString());
372    
373                                            return null;
374                                    }
375                            }
376                            else {
377                                    propertiesSection.setDefaultProperties(
378                                            extractDefaultProperties(lines));
379                                    propertiesSection.setExampleProperties(
380                                            extractExampleProperties(lines));
381                                    propertiesSection.setPropertyComments(
382                                            extractPropertyComments(lines));
383    
384                                    propertiesSections.add(propertiesSection);
385                            }
386                    }
387    
388                    return propertiesSections;
389            }
390    
391            protected static final String DOUBLE_INDENT =
392                    PropertiesDocBuilder.INDENT + PropertiesDocBuilder.INDENT;
393    
394            protected static final String INDENT = StringPool.FOUR_SPACES;
395    
396            private static final FileImpl _fileUtil = FileImpl.getInstance();
397    
398    }