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