1   /**
2    * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.tools;
24  
25  import com.liferay.portal.kernel.util.ClassUtil;
26  import com.liferay.portal.kernel.util.ListUtil;
27  import com.liferay.portal.kernel.util.StringPool;
28  import com.liferay.portal.kernel.util.StringUtil;
29  import com.liferay.portal.util.ContentUtil;
30  import com.liferay.portal.util.FileImpl;
31  
32  import java.io.BufferedReader;
33  import java.io.File;
34  import java.io.InputStream;
35  import java.io.IOException;
36  import java.io.StringReader;
37  import java.net.URL;
38  import java.util.ArrayList;
39  import java.util.Collections;
40  import java.util.HashSet;
41  import java.util.List;
42  import java.util.Properties;
43  import java.util.Set;
44  import java.util.regex.Matcher;
45  import java.util.regex.Pattern;
46  
47  import org.apache.tools.ant.DirectoryScanner;
48  
49  /**
50   * <a href="SourceFormatter.java.html"><b><i>View Source</i></b></a>
51   *
52   * @author Brian Wing Shun Chan
53   *
54   */
55  public class SourceFormatter {
56  
57      public static void main(String[] args) {
58          try {
59              _readExclusions();
60  
61              _checkPersistenceTestSuite();
62              _checkWebXML();
63              _formatJava();
64              _formatJSP();
65          }
66          catch (Exception e) {
67              e.printStackTrace();
68          }
69      }
70  
71      public static String stripImports(
72              String content, String packageDir, String className)
73          throws IOException {
74  
75          int x = content.indexOf("import ");
76  
77          if (x == -1) {
78              return content;
79          }
80  
81          int y = content.indexOf("{", x);
82  
83          y = content.substring(0, y).lastIndexOf(";") + 1;
84  
85          String imports = _formatImports(content.substring(x, y));
86  
87          content =
88              content.substring(0, x) + imports +
89                  content.substring(y + 1, content.length());
90  
91          Set<String> classes = ClassUtil.getClasses(
92              new StringReader(content), className);
93  
94          classes.add("_getMarkup");
95          classes.add("_performBlockingInteraction");
96  
97          x = content.indexOf("import ");
98  
99          y = content.indexOf("{", x);
100 
101         y = content.substring(0, y).lastIndexOf(";") + 1;
102 
103         imports = content.substring(x, y);
104 
105         StringBuilder sb = new StringBuilder();
106 
107         BufferedReader br = new BufferedReader(new StringReader(imports));
108 
109         String line = null;
110 
111         while ((line = br.readLine()) != null) {
112             if (line.indexOf("import ") != -1) {
113                 int importX = line.indexOf(" ");
114                 int importY = line.lastIndexOf(".");
115 
116                 String importPackage = line.substring(importX + 1, importY);
117                 String importClass = line.substring(
118                     importY + 1, line.length() - 1);
119 
120                 if (!packageDir.equals(importPackage)) {
121                     if (!importClass.equals("*")) {
122                         if (classes.contains(importClass)) {
123                             sb.append(line);
124                             sb.append("\n");
125                         }
126                     }
127                     else {
128                         sb.append(line);
129                         sb.append("\n");
130                     }
131                 }
132             }
133         }
134 
135         imports = _formatImports(sb.toString());
136 
137         content =
138             content.substring(0, x) + imports +
139                 content.substring(y + 1, content.length());
140 
141         return content;
142     }
143 
144     public static void _checkPersistenceTestSuite() throws IOException {
145         String basedir = "./portal-impl/test";
146 
147         if (!_fileUtil.exists(basedir)) {
148             return;
149         }
150 
151         DirectoryScanner ds = new DirectoryScanner();
152 
153         ds.setBasedir(basedir);
154         ds.setIncludes(new String[] {"**\\*PersistenceTest.java"});
155 
156         ds.scan();
157 
158         String[] files = ds.getIncludedFiles();
159 
160         Set<String> persistenceTests = new HashSet<String>();
161 
162         for (String file : files) {
163             String persistenceTest = file.substring(0, file.length() - 5);
164 
165             persistenceTest = persistenceTest.substring(
166                 persistenceTest.lastIndexOf(File.separator) + 1,
167                 persistenceTest.length());
168 
169             persistenceTests.add(persistenceTest);
170         }
171 
172         String persistenceTestSuite = _fileUtil.read(
173             basedir + "/com/liferay/portal/service/persistence/" +
174                 "PersistenceTestSuite.java");
175 
176         for (String persistenceTest : persistenceTests) {
177             if (persistenceTestSuite.indexOf(persistenceTest) == -1) {
178                 System.out.println("PersistenceTestSuite: " + persistenceTest);
179             }
180         }
181     }
182 
183     private static void _checkWebXML() throws IOException {
184         String basedir = "./";
185 
186         if (_fileUtil.exists(basedir + "portal-impl")) {
187             return;
188         }
189 
190         String webXML = ContentUtil.get(
191             "com/liferay/portal/deploy/dependencies/web.xml");
192 
193         DirectoryScanner ds = new DirectoryScanner();
194 
195         ds.setBasedir(basedir);
196         ds.setIncludes(new String[] {"**\\web.xml"});
197 
198         ds.scan();
199 
200         String[] files = ds.getIncludedFiles();
201 
202         for (String file : files) {
203             String content = _fileUtil.read(basedir + file);
204 
205             if (content.equals(webXML)) {
206                 System.out.println(file);
207             }
208         }
209     }
210 
211     private static void _checkXSS(String fileName, String jspContent) {
212         Matcher matcher = _xssPattern.matcher(jspContent);
213 
214         while (matcher.find()) {
215             boolean xssVulnerable = false;
216 
217             String jspVariable = matcher.group(1);
218 
219             String inputVulnerability =
220                 " type=\"hidden\" value=\"<%= " + jspVariable + " %>";
221 
222             if (jspContent.indexOf(inputVulnerability) != -1) {
223                 xssVulnerable = true;
224             }
225 
226             String anchorVulnerability = " href=\"<%= " + jspVariable + " %>";
227 
228             if (jspContent.indexOf(anchorVulnerability) != -1) {
229                 xssVulnerable = true;
230             }
231 
232             String inlineStringVulnerability1 = "'<%= " + jspVariable + " %>";
233 
234             if (jspContent.indexOf(inlineStringVulnerability1) != -1) {
235                 xssVulnerable = true;
236             }
237 
238             String inlineStringVulnerability2 = "(\"<%= " + jspVariable + " %>";
239 
240             if (jspContent.indexOf(inlineStringVulnerability2) != -1) {
241                 xssVulnerable = true;
242             }
243 
244             String inlineStringVulnerability3 = " \"<%= " + jspVariable + " %>";
245 
246             if (jspContent.indexOf(inlineStringVulnerability3) != -1) {
247                 xssVulnerable = true;
248             }
249 
250             String documentIdVulnerability = ".<%= " + jspVariable + " %>";
251 
252             if (jspContent.indexOf(documentIdVulnerability) != -1) {
253                 xssVulnerable = true;
254             }
255 
256             if (xssVulnerable) {
257                 System.out.println(
258                     "(xss): " + fileName + " (" + jspVariable + ")");
259             }
260         }
261     }
262 
263     public static String _formatImports(String imports) throws IOException {
264         if ((imports.indexOf("/*") != -1) ||
265             (imports.indexOf("*/") != -1) ||
266             (imports.indexOf("//") != -1)) {
267 
268             return imports + "\n";
269         }
270 
271         List<String> importsList = new ArrayList<String>();
272 
273         BufferedReader br = new BufferedReader(new StringReader(imports));
274 
275         String line = null;
276 
277         while ((line = br.readLine()) != null) {
278             if (line.indexOf("import ") != -1) {
279                 if (!importsList.contains(line)) {
280                     importsList.add(line);
281                 }
282             }
283         }
284 
285         Collections.sort(importsList);
286 
287         StringBuilder sb = new StringBuilder();
288 
289         String temp = null;
290 
291         for (int i = 0; i < importsList.size(); i++) {
292             String s = importsList.get(i);
293 
294             int pos = s.indexOf(".");
295 
296             pos = s.indexOf(".", pos + 1);
297 
298             if (pos == -1) {
299                 pos = s.indexOf(".");
300             }
301 
302             String packageLevel = s.substring(7, pos);
303 
304             if ((i != 0) && (!packageLevel.equals(temp))) {
305                 sb.append("\n");
306             }
307 
308             temp = packageLevel;
309 
310             sb.append(s);
311             sb.append("\n");
312         }
313 
314         return sb.toString();
315     }
316 
317     private static void _formatJava() throws IOException {
318         String basedir = "./";
319 
320         String copyright = _getCopyright();
321 
322         String[] files = null;
323 
324         if (_fileUtil.exists(basedir + "portal-impl")) {
325             files = _getPortalJavaFiles();
326         }
327         else {
328             files = _getPluginJavaFiles();
329         }
330 
331         for (int i = 0; i < files.length; i++) {
332             File file = new File(basedir + files[i]);
333 
334             String content = _fileUtil.read(file);
335 
336             String className = file.getName();
337 
338             className = className.substring(0, className.length() - 5);
339 
340             String packagePath = files[i];
341 
342             int packagePathX = packagePath.indexOf(
343                 File.separator + "src" + File.separator);
344             int packagePathY = packagePath.lastIndexOf(File.separator);
345 
346             packagePath = packagePath.substring(packagePathX + 5, packagePathY);
347             packagePath = StringUtil.replace(
348                 packagePath, File.separator, StringPool.PERIOD);
349 
350             if (packagePath.endsWith(".model")) {
351                 if (content.indexOf(
352                         "extends " + className + "Model {") != -1) {
353 
354                     continue;
355                 }
356             }
357 
358             String newContent = _formatJavaContent(files[i], content);
359 
360             if (newContent.indexOf("$\n */") != -1) {
361                 System.out.println("*: " + files[i]);
362 
363                 newContent = StringUtil.replace(
364                     newContent, "$\n */", "$\n *\n */");
365             }
366 
367             if (newContent.indexOf(copyright) == -1) {
368                 System.out.println("(c): " + files[i]);
369             }
370 
371             if (newContent.indexOf(className + ".java.html") == -1) {
372                 System.out.println("Java2HTML: " + files[i]);
373             }
374 
375             newContent = stripImports(newContent, packagePath, className);
376 
377             newContent = StringUtil.replace(
378                 newContent, "@author Raymond Aug?", "@author Raymond Augé");
379 
380             if (newContent.indexOf(";\n/**") != -1) {
381                 newContent = StringUtil.replace(
382                     newContent,
383                     ";\n/**",
384                     ";\n\n/**");
385             }
386 
387             if (newContent.indexOf("\t/*\n\t *") != -1) {
388                 newContent = StringUtil.replace(
389                     newContent,
390                     "\t/*\n\t *",
391                     "\t/**\n\t *");
392             }
393 
394             if (newContent.indexOf("if(") != -1) {
395                 newContent = StringUtil.replace(
396                     newContent,
397                     "if(",
398                     "if (");
399             }
400 
401             if (newContent.indexOf("while(") != -1) {
402                 newContent = StringUtil.replace(
403                     newContent,
404                     "while(",
405                     "while (");
406             }
407 
408             if (newContent.indexOf("\n\n\n") != -1) {
409                 newContent = StringUtil.replace(
410                     newContent,
411                     "\n\n\n",
412                     "\n\n");
413             }
414 
415             if (newContent.indexOf("*/\npackage ") != -1) {
416                 System.out.println("package: " + files[i]);
417             }
418 
419             if (newContent.indexOf("    ") != -1) {
420                 if (!files[i].endsWith("StringPool.java")) {
421                     System.out.println("tab: " + files[i]);
422                 }
423             }
424 
425             if (newContent.indexOf("  {") != -1) {
426                 System.out.println("{:" + files[i]);
427             }
428 
429             if (!newContent.endsWith("\n\n}") &&
430                 !newContent.endsWith("{\n}")) {
431 
432                 System.out.println("}: " + files[i]);
433             }
434 
435             if ((newContent != null) && !content.equals(newContent)) {
436                 _fileUtil.write(file, newContent);
437 
438                 System.out.println(file);
439             }
440         }
441     }
442 
443     private static String _formatJavaContent(String fileName, String content)
444         throws IOException {
445 
446         StringBuilder sb = new StringBuilder();
447 
448         BufferedReader br = new BufferedReader(new StringReader(content));
449 
450         int lineCount = 0;
451 
452         String line = null;
453 
454         while ((line = br.readLine()) != null) {
455             lineCount++;
456 
457             if (line.trim().length() == 0) {
458                 line = StringPool.BLANK;
459             }
460 
461             line = StringUtil.trimTrailing(line);
462 
463             sb.append(line);
464             sb.append("\n");
465 
466             line = StringUtil.replace(line, "\t", "    ");
467 
468             String excluded = _exclusions.getProperty(
469                 StringUtil.replace(fileName, "\\", "/") + StringPool.AT +
470                     lineCount);
471 
472             if ((excluded == null) && ((line.length() - 1) > 79) &&
473                 (!line.startsWith("import "))) {
474 
475                 System.out.println("> 80: " + fileName + " " + lineCount);
476             }
477         }
478 
479         br.close();
480 
481         String newContent = sb.toString();
482 
483         if (newContent.endsWith("\n")) {
484             newContent = newContent.substring(0, newContent.length() -1);
485         }
486 
487         return newContent;
488     }
489 
490     private static void _formatJSP() throws IOException {
491         String basedir = "./";
492 
493         List<File> list = new ArrayList<File>();
494 
495         DirectoryScanner ds = new DirectoryScanner();
496 
497         ds.setBasedir(basedir);
498         ds.setExcludes(new String[] {"**\\null.jsp", "**\\tmp\\**"});
499         ds.setIncludes(new String[] {"**\\*.jsp", "**\\*.jspf", "**\\*.vm"});
500 
501         ds.scan();
502 
503         list.addAll(ListUtil.fromArray(ds.getIncludedFiles()));
504 
505         String copyright = _getCopyright();
506 
507         String[] files = list.toArray(new String[list.size()]);
508 
509         for (int i = 0; i < files.length; i++) {
510             File file = new File(basedir + files[i]);
511 
512             String content = _fileUtil.read(file, true);
513             String newContent = _formatJSPContent(files[i], content);
514 
515             newContent = StringUtil.replace(
516                 newContent,
517                 new String[] {"<br/>", "\"/>"},
518                 new String[] {"<br />", "\" />"});
519 
520             if (files[i].endsWith(".jsp")) {
521                 if (newContent.indexOf(copyright) == -1) {
522                     System.out.println("(c): " + files[i]);
523                 }
524             }
525 
526             if (newContent.indexOf("alert('<%= LanguageUtil.") != -1) {
527                 newContent = StringUtil.replace(newContent,
528                     "alert('<%= LanguageUtil.",
529                     "alert('<%= UnicodeLanguageUtil.");
530             }
531 
532             if (newContent.indexOf("alert(\"<%= LanguageUtil.") != -1) {
533                 newContent = StringUtil.replace(newContent,
534                     "alert(\"<%= LanguageUtil.",
535                     "alert(\"<%= UnicodeLanguageUtil.");
536             }
537 
538             if (newContent.indexOf("confirm('<%= LanguageUtil.") != -1) {
539                 newContent = StringUtil.replace(newContent,
540                     "confirm('<%= LanguageUtil.",
541                     "confirm('<%= UnicodeLanguageUtil.");
542             }
543 
544             if (newContent.indexOf("confirm(\"<%= LanguageUtil.") != -1) {
545                 newContent = StringUtil.replace(newContent,
546                     "confirm(\"<%= LanguageUtil.",
547                     "confirm(\"<%= UnicodeLanguageUtil.");
548             }
549 
550             if (newContent.indexOf("    ") != -1) {
551                 if (!files[i].endsWith("template.vm")) {
552                     System.out.println("tab: " + files[i]);
553                 }
554             }
555 
556             _checkXSS(files[i], content);
557 
558             if ((newContent != null) && !content.equals(newContent)) {
559                 _fileUtil.write(file, newContent);
560 
561                 System.out.println(file);
562             }
563         }
564     }
565 
566     private static String _formatJSPContent(String fileName, String content)
567         throws IOException {
568 
569         StringBuilder sb = new StringBuilder();
570 
571         BufferedReader br =
572             new BufferedReader(new StringReader(content));
573 
574         int lineCount = 0;
575 
576         String line = null;
577 
578         while ((line = br.readLine()) != null) {
579             lineCount++;
580 
581             int x = line.indexOf("\"<%=");
582             int y = line.indexOf("%>\"", x);
583 
584             boolean hasTagLibrary = false;
585 
586             for (int i = 0; i < _TAG_LIBRARIES.length; i++) {
587                 if (line.indexOf("<" + _TAG_LIBRARIES[i] + ":") != -1) {
588                     hasTagLibrary = true;
589 
590                     break;
591                 }
592             }
593 
594             if ((x != -1) && (y != -1) && hasTagLibrary) {
595                 String regexp = line.substring(x, y + 3);
596 
597                 if (regexp.indexOf("\\\"") == -1) {
598                     regexp = regexp.substring(1, regexp.length() - 1);
599 
600                     if (regexp.indexOf("\"") != -1) {
601                         line =
602                             line.substring(0, x) + "'" + regexp + "'" +
603                                 line.substring(y + 3, line.length());
604                     }
605                 }
606             }
607 
608             if (line.trim().length() == 0) {
609                 line = StringPool.BLANK;
610             }
611 
612             line = StringUtil.trimTrailing(line);
613 
614             sb.append(line);
615             sb.append("\n");
616         }
617 
618         br.close();
619 
620         String newContent = sb.toString();
621 
622         if (newContent.endsWith("\n")) {
623             newContent = newContent.substring(0, newContent.length() -1);
624         }
625 
626         return newContent;
627     }
628 
629     private static String _getCopyright() throws IOException {
630         try {
631             return _fileUtil.read("copyright.txt");
632         }
633         catch (Exception e1) {
634             try {
635                 return _fileUtil.read("../copyright.txt");
636             }
637             catch (Exception e2) {
638                 return _fileUtil.read("../../copyright.txt");
639             }
640         }
641     }
642 
643     private static String[] _getPluginJavaFiles() {
644         String basedir = "./";
645 
646         List<File> list = new ArrayList<File>();
647 
648         DirectoryScanner ds = new DirectoryScanner();
649 
650         ds.setBasedir(basedir);
651         ds.setExcludes(
652             new String[] {
653                 "**\\com\\liferay\\portlet\\service\\*.java",
654                 "**\\model\\*Model.java", "**\\model\\*Soap.java",
655                 "**\\model\\impl\\*ModelImpl.java",
656                 "**\\service\\*Service.java",
657                 "**\\service\\*ServiceFactory.java",
658                 "**\\service\\*ServiceUtil.java",
659                 "**\\service\\base\\*ServiceBaseImpl.java",
660                 "**\\service\\http\\*JSONSerializer.java",
661                 "**\\service\\http\\*ServiceHttp.java",
662                 "**\\service\\http\\*ServiceJSON.java",
663                 "**\\service\\http\\*ServiceSoap.java",
664                 "**\\service\\persistence\\*Finder.java",
665                 "**\\service\\persistence\\*Persistence.java",
666                 "**\\service\\persistence\\*PersistenceImpl.java",
667                 "**\\service\\persistence\\*Util.java"
668             });
669         ds.setIncludes(new String[] {"**\\*.java"});
670 
671         ds.scan();
672 
673         list.addAll(ListUtil.fromArray(ds.getIncludedFiles()));
674 
675         return list.toArray(new String[list.size()]);
676     }
677 
678     private static String[] _getPortalJavaFiles() {
679         String basedir = "./";
680 
681         List<File> list = new ArrayList<File>();
682 
683         DirectoryScanner ds = new DirectoryScanner();
684 
685         ds.setBasedir(basedir);
686         ds.setExcludes(
687             new String[] {
688                 "**\\classes\\*", "**\\jsp\\*", "**\\tmp\\**",
689                 "**\\EARXMLBuilder.java", "**\\EJBXMLBuilder.java",
690                 "**\\JSMin.java", "**\\PropsKeys.java",
691                 "**\\InstanceWrapperBuilder.java",
692                 "**\\ServiceBuilder.java", "**\\SourceFormatter.java",
693                 "**\\UserAttributes.java", "**\\WebKeys.java",
694                 "**\\*_IW.java", "**\\XHTMLComplianceFormatter.java",
695                 "**\\portal-service\\**\\model\\*Model.java",
696                 "**\\portal-service\\**\\model\\*Soap.java",
697                 "**\\model\\impl\\*ModelImpl.java",
698                 "**\\portal\\service\\**", "**\\portal-client\\**",
699                 "**\\portal-web\\test\\**\\*Test.java",
700                 "**\\portlet\\**\\service\\**", "**\\tools\\ext_tmpl\\**",
701                 "**\\util-wsrp\\**"
702             });
703         ds.setIncludes(new String[] {"**\\*.java"});
704 
705         ds.scan();
706 
707         list.addAll(ListUtil.fromArray(ds.getIncludedFiles()));
708 
709         ds = new DirectoryScanner();
710 
711         ds.setBasedir(basedir);
712         ds.setExcludes(
713             new String[] {
714                 "**\\tools\\ext_tmpl\\**", "**\\*_IW.java",
715                 "**\\test\\**\\*PersistenceTest.java"
716             });
717         ds.setIncludes(
718             new String[] {
719                 "**\\service\\http\\*HttpTest.java",
720                 "**\\service\\http\\*SoapTest.java",
721                 "**\\service\\impl\\*.java", "**\\service\\jms\\*.java",
722                 "**\\service\\permission\\*.java",
723                 "**\\service\\persistence\\BasePersistence.java",
724                 "**\\service\\persistence\\*FinderImpl.java",
725                 "**\\portal-impl\\test\\**\\*.java",
726                 "**\\portal-service\\**\\liferay\\counter\\**.java",
727                 "**\\portal-service\\**\\liferay\\documentlibrary\\**.java",
728                 "**\\portal-service\\**\\liferay\\lock\\**.java",
729                 "**\\portal-service\\**\\liferay\\mail\\**.java",
730                 "**\\util-bridges\\**\\*.java"
731             });
732 
733         ds.scan();
734 
735         list.addAll(ListUtil.fromArray(ds.getIncludedFiles()));
736 
737         return list.toArray(new String[list.size()]);
738     }
739 
740     private static void _readExclusions() throws IOException {
741         _exclusions = new Properties();
742 
743         ClassLoader classLoader = SourceFormatter.class.getClassLoader();
744 
745         URL url = classLoader.getResource(
746             "com/liferay/portal/tools/dependencies/" +
747                 "source_formatter_exclusions.properties");
748 
749         if (url == null) {
750             return;
751         }
752 
753         InputStream is = url.openStream();
754 
755         _exclusions.load(is);
756 
757         is.close();
758     }
759 
760     private static final String[] _TAG_LIBRARIES = new String[] {
761         "c", "html", "jsp", "liferay-portlet", "liferay-security",
762         "liferay-theme", "liferay-ui", "liferay-util", "portlet", "struts",
763         "tiles"
764     };
765 
766     private static FileImpl _fileUtil = FileImpl.getInstance();
767     private static Properties _exclusions;
768     private static Pattern _xssPattern = Pattern.compile(
769         "String\\s+([^\\s]+)\\s*=\\s*ParamUtil\\.getString\\(");
770 
771 }