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