Java tutorial
/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.tools.sourceformatter; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader; import com.liferay.portal.kernel.io.unsync.UnsyncStringReader; import com.liferay.portal.kernel.util.CharPool; import com.liferay.portal.kernel.util.GetterUtil; import com.liferay.portal.kernel.util.StringBundler; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.kernel.util.Validator; /** * @author Hugo Huijser */ public class JSPSourceProcessor extends BaseSourceProcessor { protected void addImportCounts(String content) { Matcher matcher = _importsPattern.matcher(content); while (matcher.find()) { String importName = matcher.group(1); int count = 0; if (_importCountMap.containsKey(importName)) { count = _importCountMap.get(importName); } else { int pos = importName.lastIndexOf(StringPool.PERIOD); String importClassName = importName.substring(pos + 1); if (_importClassNames.contains(importClassName)) { _duplicateImportClassNames.add(importClassName); } else { _importClassNames.add(importClassName); } } _importCountMap.put(importName, count + 1); } } protected void addJSPIncludeFileNames(String fileName) { String content = _jspContents.get(fileName); if (Validator.isNull(content)) { return; } for (int x = 0;;) { x = content.indexOf("<%@ include file=", x); if (x == -1) { break; } x = content.indexOf(StringPool.QUOTE, x); if (x == -1) { break; } int y = content.indexOf(StringPool.QUOTE, x + 1); if (y == -1) { break; } String includeFileName = content.substring(x + 1, y); Matcher matcher = _jspIncludeFilePattern.matcher(includeFileName); if (!matcher.find()) { throw new RuntimeException("Invalid include " + includeFileName); } includeFileName = buildFullPathIncludeFileName(fileName, includeFileName); if ((includeFileName.endsWith("jsp") || includeFileName.endsWith("jspf")) && !includeFileName.endsWith("html/common/init.jsp") && !includeFileName.endsWith("html/portlet/init.jsp") && !includeFileName.endsWith("html/taglib/init.jsp") && !_includeFileNames.contains(includeFileName)) { _includeFileNames.add(includeFileName); } x = y; } } protected void addJSPReferenceFileNames(String fileName) { for (Map.Entry<String, String> entry : _jspContents.entrySet()) { String referenceFileName = entry.getKey(); if (_includeFileNames.contains(referenceFileName)) { continue; } String sharedPath = fileName.substring(0, StringUtil.startsWithWeight(referenceFileName, fileName)); if (Validator.isNull(sharedPath) || !sharedPath.contains(StringPool.SLASH)) { continue; } if (!sharedPath.endsWith(StringPool.SLASH)) { sharedPath = sharedPath.substring(0, sharedPath.lastIndexOf(CharPool.SLASH) + 1); } String content = null; for (int x = -1;;) { x = sharedPath.indexOf(CharPool.SLASH, x + 1); if (x == -1) { break; } if (content == null) { content = entry.getValue(); } if (content.contains("<%@ include file=\"" + fileName.substring(x))) { _includeFileNames.add(referenceFileName); break; } } } } protected void addJSPUnusedImports(String fileName, List<String> importLines, List<String> unneededImports) { for (String importLine : importLines) { int x = importLine.indexOf(StringPool.QUOTE); int y = importLine.indexOf(StringPool.QUOTE, x + 1); if ((x == -1) || (y == -1)) { continue; } String className = importLine.substring(x + 1, y); className = className.substring(className.lastIndexOf(StringPool.PERIOD) + 1); String regex = "[^A-Za-z0-9_\"]" + className + "[^A-Za-z0-9_\"]"; if (hasUnusedJSPTerm(fileName, regex, "class")) { unneededImports.add(importLine); } } } protected String buildFullPathIncludeFileName(String fileName, String includeFileName) { String topLevelDirName = null; int x = includeFileName.indexOf(CharPool.SLASH, 1); if (x != -1) { topLevelDirName = includeFileName.substring(1, x); } String path = fileName; while (true) { int y = path.lastIndexOf(CharPool.SLASH); if (y == -1) { return StringPool.BLANK; } if (Validator.isNull(topLevelDirName) || path.equals(topLevelDirName) || path.endsWith(StringPool.SLASH + topLevelDirName)) { String fullPathIncludeFileName = path.substring(0, y) + includeFileName; if (_jspContents.containsKey(fullPathIncludeFileName) && !fullPathIncludeFileName.equals(fileName)) { return fullPathIncludeFileName; } } path = path.substring(0, y); } } protected boolean checkTaglibVulnerability(String jspContent, String vulnerability) { int pos1 = -1; do { pos1 = jspContent.indexOf(vulnerability, pos1 + 1); if (pos1 != -1) { int pos2 = jspContent.lastIndexOf(CharPool.LESS_THAN, pos1); while ((pos2 > 0) && (jspContent.charAt(pos2 + 1) == CharPool.PERCENT)) { pos2 = jspContent.lastIndexOf(CharPool.LESS_THAN, pos2 - 1); } String tagContent = jspContent.substring(pos2, pos1); if (!tagContent.startsWith("<aui:") && !tagContent.startsWith("<liferay-portlet:") && !tagContent.startsWith("<liferay-util:") && !tagContent.startsWith("<portlet:")) { return true; } } } while (pos1 != -1); return false; } protected void checkXSS(String fileName, String jspContent) { Matcher matcher = _xssPattern.matcher(jspContent); while (matcher.find()) { boolean xssVulnerable = false; String jspVariable = matcher.group(1); String anchorVulnerability = " href=\"<%= " + jspVariable + " %>"; if (checkTaglibVulnerability(jspContent, anchorVulnerability)) { xssVulnerable = true; } String inputVulnerability = " value=\"<%= " + jspVariable + " %>"; if (checkTaglibVulnerability(jspContent, inputVulnerability)) { xssVulnerable = true; } String inlineStringVulnerability1 = "'<%= " + jspVariable + " %>"; if (jspContent.contains(inlineStringVulnerability1)) { xssVulnerable = true; } String inlineStringVulnerability2 = "(\"<%= " + jspVariable + " %>"; if (jspContent.contains(inlineStringVulnerability2)) { xssVulnerable = true; } String inlineStringVulnerability3 = " \"<%= " + jspVariable + " %>"; if (jspContent.contains(inlineStringVulnerability3)) { xssVulnerable = true; } String documentIdVulnerability = ".<%= " + jspVariable + " %>"; if (jspContent.contains(documentIdVulnerability)) { xssVulnerable = true; } if (xssVulnerable) { processErrorMessage(fileName, "(xss): " + fileName + " (" + jspVariable + ")"); } } } @Override protected String doFormat(File file, String fileName, String absolutePath, String content) throws Exception { String newContent = formatJSP(fileName, absolutePath, content); newContent = StringUtil.replace(newContent, new String[] { "<br/>", "\"/>", "\" >", "@page import", "\"%>", ")%>", "else{", "for(", "function (", "if(", "javascript: ", "while(", "){\n", ";;\n", "\n\n\n" }, new String[] { "<br />", "\" />", "\">", "@ page import", "\" %>", ") %>", "else {", "for (", "function(", "if (", "javascript:", "while (", ") {\n", ";\n", "\n\n" }); newContent = fixCompatClassImports(absolutePath, newContent); if (_stripJSPImports && !_jspContents.isEmpty()) { try { newContent = stripJSPImports(fileName, newContent); } catch (RuntimeException re) { _stripJSPImports = false; } } if (portalSource && content.contains("page import=") && !fileName.contains("init.jsp") && !fileName.contains("init-ext.jsp") && !fileName.contains("/taglib/aui/") && !fileName.endsWith("touch.jsp") && (fileName.endsWith(".jspf") || content.contains("include file="))) { processErrorMessage(fileName, "move imports to init.jsp: " + fileName); } newContent = fixCopyright(newContent, absolutePath, fileName); newContent = StringUtil.replace(newContent, new String[] { "alert('<%= LanguageUtil.", "alert(\"<%= LanguageUtil.", "confirm('<%= LanguageUtil.", "confirm(\"<%= LanguageUtil." }, new String[] { "alert('<%= UnicodeLanguageUtil.", "alert(\"<%= UnicodeLanguageUtil.", "confirm('<%= UnicodeLanguageUtil.", "confirm(\"<%= UnicodeLanguageUtil." }); if (newContent.contains(" ")) { if (!fileName.matches(".*template.*\\.vm$")) { processErrorMessage(fileName, "tab: " + fileName); } } if (fileName.endsWith("init.jsp") || fileName.endsWith("init.jspf")) { int x = newContent.indexOf("<%@ page import="); int y = newContent.lastIndexOf("<%@ page import="); y = newContent.indexOf("%>", y); if ((x != -1) && (y != -1) && (y > x)) { // Set compressImports to false to decompress imports boolean compressImports = true; if (compressImports) { String imports = newContent.substring(x, y); imports = StringUtil.replace(imports, new String[] { "%>\r\n<%@ ", "%>\n<%@ " }, new String[] { "%><%@\r\n", "%><%@\n" }); newContent = newContent.substring(0, x) + imports + newContent.substring(y); } } } newContent = fixSessionKey(fileName, newContent, sessionKeyPattern); newContent = fixSessionKey(fileName, newContent, taglibSessionKeyPattern); checkLanguageKeys(fileName, newContent, languageKeyPattern); checkLanguageKeys(fileName, newContent, _taglibLanguageKeyPattern1); checkLanguageKeys(fileName, newContent, _taglibLanguageKeyPattern2); checkLanguageKeys(fileName, newContent, _taglibLanguageKeyPattern3); checkXSS(fileName, newContent); // LPS-47682 newContent = fixIncorrectParameterTypeForLanguageUtil(newContent, true, fileName); Matcher matcher = _javaClassPattern.matcher(newContent); if (matcher.find()) { String javaClassContent = matcher.group(); javaClassContent = javaClassContent.substring(1); String javaClassName = matcher.group(2); String beforeJavaClass = newContent.substring(0, matcher.start() + 1); int javaClassLineCount = StringUtil.count(beforeJavaClass, "\n") + 1; newContent = formatJavaTerms(javaClassName, fileName, absolutePath, newContent, javaClassContent, javaClassLineCount, null, null, null, null); } if (!content.equals(newContent)) { _jspContents.put(fileName, newContent); } return newContent; } @Override protected void format() throws Exception { _moveFrequentlyUsedImportsToCommonInit = GetterUtil .getBoolean(getProperty("move.frequently.used.imports.to.common.init")); _unusedVariablesExclusions = getPropertyList("jsp.unused.variables.excludes.files"); String[] excludes = new String[] { "**\\null.jsp", "**\\tools\\**" }; String[] includes = new String[] { "**\\*.jsp", "**\\*.jspf", "**\\*.vm" }; List<String> fileNames = getFileNames(excludes, includes); Pattern pattern = Pattern.compile("\\s*@\\s*include\\s*file=['\"](.*)['\"]"); for (String fileName : fileNames) { File file = new File(BASEDIR + fileName); fileName = StringUtil.replace(fileName, StringPool.BACK_SLASH, StringPool.SLASH); String absolutePath = getAbsolutePath(file); String content = fileUtil.read(file); Matcher matcher = pattern.matcher(content); String newContent = content; while (matcher.find()) { newContent = StringUtil.replaceFirst(newContent, matcher.group(), "@ include file=\"" + matcher.group(1) + "\"", matcher.start()); } processFormattedFile(file, fileName, content, newContent); if (portalSource && _moveFrequentlyUsedImportsToCommonInit && fileName.endsWith("/init.jsp") && !absolutePath.contains("/modules/") && !fileName.endsWith("/common/init.jsp")) { addImportCounts(content); } _jspContents.put(fileName, newContent); } if (portalSource && _moveFrequentlyUsedImportsToCommonInit) { moveFrequentlyUsedImportsToCommonInit(4); } for (String fileName : fileNames) { format(fileName); } } protected String formatJSP(String fileName, String absolutePath, String content) throws IOException { StringBundler sb = new StringBundler(); String currentAttributeAndValue = null; String previousAttribute = null; String previousAttributeAndValue = null; String currentException = null; String previousException = null; boolean hasUnsortedExceptions = false; try (UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader( new UnsyncStringReader(content))) { _checkedForIncludesFileNames = new HashSet<String>(); _includeFileNames = new HashSet<String>(); int lineCount = 0; String line = null; String previousLine = StringPool.BLANK; boolean readAttributes = false; boolean javaSource = false; while ((line = unsyncBufferedReader.readLine()) != null) { lineCount++; if (portalSource && hasUnusedTaglib(fileName, line)) { continue; } if (!fileName.contains("jsonw") || !fileName.endsWith("action.jsp")) { line = trimLine(line, false); } if (line.contains("<aui:button ") && line.contains("type=\"button\"")) { processErrorMessage(fileName, "aui:button " + fileName + " " + lineCount); } if (line.contains("debugger.")) { processErrorMessage(fileName, "debugger " + fileName + " " + lineCount); } String trimmedLine = StringUtil.trimLeading(line); String trimmedPreviousLine = StringUtil.trimLeading(previousLine); checkStringBundler(trimmedLine, fileName, lineCount); checkEmptyCollection(trimmedLine, fileName, lineCount); if (trimmedLine.equals("<%") || trimmedLine.equals("<%!")) { javaSource = true; } else if (trimmedLine.equals("%>")) { javaSource = false; } if (javaSource || trimmedLine.contains("<%= ")) { checkInefficientStringMethods(line, fileName, absolutePath, lineCount); } if (javaSource && portalSource && !isExcluded(_unusedVariablesExclusions, absolutePath, lineCount) && !_jspContents.isEmpty() && hasUnusedVariable(fileName, trimmedLine)) { continue; } // LPS-47179 if (line.contains(".sendRedirect(") && !fileName.endsWith("_jsp.jsp")) { processErrorMessage(fileName, "Do not use sendRedirect in jsp: " + fileName + " " + lineCount); } if (!trimmedLine.equals("%>") && line.contains("%>") && !line.contains("--%>") && !line.contains(" %>")) { line = StringUtil.replace(line, "%>", " %>"); } if (line.contains("<%=") && !line.contains("<%= ")) { line = StringUtil.replace(line, "<%=", "<%= "); } if (trimmedPreviousLine.equals("%>") && Validator.isNotNull(line) && !trimmedLine.equals("-->")) { sb.append("\n"); } else if (Validator.isNotNull(previousLine) && !trimmedPreviousLine.equals("<!--") && trimmedLine.equals("<%")) { sb.append("\n"); } else if (trimmedPreviousLine.equals("<%") && Validator.isNull(line)) { continue; } else if (trimmedPreviousLine.equals("<%") && trimmedLine.startsWith("//")) { sb.append("\n"); } else if (Validator.isNull(previousLine) && trimmedLine.equals("%>") && (sb.index() > 2)) { String lineBeforePreviousLine = sb.stringAt(sb.index() - 3); if (!lineBeforePreviousLine.startsWith("//")) { sb.setIndex(sb.index() - 1); } } if ((trimmedLine.startsWith("if (") || trimmedLine.startsWith("else if (") || trimmedLine.startsWith("while (")) && trimmedLine.endsWith(") {")) { checkIfClauseParentheses(trimmedLine, fileName, lineCount); } if (readAttributes) { if (!trimmedLine.startsWith(StringPool.FORWARD_SLASH) && !trimmedLine.startsWith(StringPool.GREATER_THAN)) { int pos = trimmedLine.indexOf(StringPool.EQUAL); if (pos != -1) { String attribute = trimmedLine.substring(0, pos); if (!trimmedLine.endsWith(StringPool.APOSTROPHE) && !trimmedLine.endsWith(StringPool.GREATER_THAN) && !trimmedLine.endsWith(StringPool.QUOTE)) { processErrorMessage(fileName, "attribute: " + fileName + " " + lineCount); readAttributes = false; } else if (trimmedLine.endsWith(StringPool.APOSTROPHE) && !trimmedLine.contains(StringPool.QUOTE)) { line = StringUtil.replace(line, StringPool.APOSTROPHE, StringPool.QUOTE); readAttributes = false; } else if (Validator.isNotNull(previousAttribute)) { if (!isAttributName(attribute) && !attribute.startsWith(StringPool.LESS_THAN)) { processErrorMessage(fileName, "attribute: " + fileName + " " + lineCount); readAttributes = false; } else if (Validator.isNull(previousAttributeAndValue) && (previousAttribute.compareTo(attribute) > 0)) { previousAttributeAndValue = previousLine; currentAttributeAndValue = line; } } if (!readAttributes) { previousAttribute = null; previousAttributeAndValue = null; } else { previousAttribute = attribute; } } } else { previousAttribute = null; readAttributes = false; } } if (!hasUnsortedExceptions) { int x = line.indexOf("<liferay-ui:error exception=\"<%="); if (x != -1) { int y = line.indexOf(".class %>", x); if (y != -1) { currentException = line.substring(x, y); if (Validator.isNotNull(previousException) && (previousException.compareTo(currentException) > 0)) { currentException = line; previousException = previousLine; hasUnsortedExceptions = true; } } } if (!hasUnsortedExceptions) { previousException = currentException; currentException = null; } } if (trimmedLine.startsWith(StringPool.LESS_THAN) && !trimmedLine.startsWith("<%") && !trimmedLine.startsWith("<!")) { if (!trimmedLine.contains(StringPool.GREATER_THAN) && !trimmedLine.contains(StringPool.SPACE)) { readAttributes = true; } else { line = sortAttributes(fileName, line, lineCount, true); } } if (!trimmedLine.contains(StringPool.DOUBLE_SLASH) && !trimmedLine.startsWith(StringPool.STAR)) { while (trimmedLine.contains(StringPool.TAB)) { line = StringUtil.replaceLast(line, StringPool.TAB, StringPool.SPACE); trimmedLine = StringUtil.replaceLast(trimmedLine, StringPool.TAB, StringPool.SPACE); } while (trimmedLine.contains(StringPool.DOUBLE_SPACE) && !trimmedLine.contains(StringPool.QUOTE + StringPool.DOUBLE_SPACE) && !fileName.endsWith(".vm")) { line = StringUtil.replaceLast(line, StringPool.DOUBLE_SPACE, StringPool.SPACE); trimmedLine = StringUtil.replaceLast(trimmedLine, StringPool.DOUBLE_SPACE, StringPool.SPACE); } } if (!fileName.endsWith("/touch.jsp")) { int x = line.indexOf("<%@ include file"); if (x != -1) { x = line.indexOf(StringPool.QUOTE, x); int y = line.indexOf(StringPool.QUOTE, x + 1); if (y != -1) { String includeFileName = line.substring(x + 1, y); Matcher matcher = _jspIncludeFilePattern.matcher(includeFileName); if (!matcher.find()) { processErrorMessage(fileName, "include: " + fileName + " " + lineCount); } } } } line = replacePrimitiveWrapperInstantiation(fileName, line, lineCount); previousLine = line; sb.append(line); sb.append("\n"); } } content = sb.toString(); if (content.endsWith("\n")) { content = content.substring(0, content.length() - 1); } content = formatTaglibQuotes(fileName, content, StringPool.QUOTE); content = formatTaglibQuotes(fileName, content, StringPool.APOSTROPHE); if (Validator.isNotNull(previousAttributeAndValue)) { content = StringUtil.replaceFirst(content, previousAttributeAndValue + "\n" + currentAttributeAndValue, currentAttributeAndValue + "\n" + previousAttributeAndValue); } if (hasUnsortedExceptions) { if ((StringUtil.count(content, currentException) > 1) || (StringUtil.count(content, previousException) > 1)) { processErrorMessage(fileName, "unsorted exceptions: " + fileName); } else { content = StringUtil.replaceFirst(content, previousException, currentException); content = StringUtil.replaceLast(content, currentException, previousException); } } return content; } protected String formatTaglibQuotes(String fileName, String content, String quoteType) { String quoteFix = StringPool.APOSTROPHE; if (quoteFix.equals(quoteType)) { quoteFix = StringPool.QUOTE; } Pattern pattern = Pattern.compile(getTaglibRegex(quoteType)); Matcher matcher = pattern.matcher(content); while (matcher.find()) { int x = content.indexOf(quoteType + "<%=", matcher.start()); int y = content.indexOf("%>" + quoteType, x); while ((x != -1) && (y != -1)) { String beforeResult = content.substring(matcher.start(), x); if (beforeResult.contains(" />\"")) { break; } String result = content.substring(x + 1, y + 2); if (result.contains(quoteType)) { int lineCount = 1; char[] contentCharArray = content.toCharArray(); for (int i = 0; i < x; i++) { if (contentCharArray[i] == CharPool.NEW_LINE) { lineCount++; } } if (!result.contains(quoteFix)) { StringBundler sb = new StringBundler(5); sb.append(content.substring(0, x)); sb.append(quoteFix); sb.append(result); sb.append(quoteFix); sb.append(content.substring(y + 3, content.length())); content = sb.toString(); } else { processErrorMessage(fileName, "taglib: " + fileName + " " + lineCount); } } x = content.indexOf(quoteType + "<%=", y); if (x > matcher.end()) { break; } y = content.indexOf("%>" + quoteType, x); } } return content; } protected List<String> getJSPDuplicateImports(String fileName, String content, List<String> importLines) { List<String> duplicateImports = new ArrayList<String>(); for (String importLine : importLines) { int x = content.indexOf("<%@ include file="); if (x == -1) { continue; } int y = content.indexOf("<%@ page import="); if (y == -1) { continue; } if ((x < y) && isJSPDuplicateImport(fileName, importLine, false)) { duplicateImports.add(importLine); } } return duplicateImports; } protected String getTaglibRegex(String quoteType) { StringBuilder sb = new StringBuilder(); sb.append("<("); for (int i = 0; i < _TAG_LIBRARIES.length; i++) { sb.append(_TAG_LIBRARIES[i]); sb.append(StringPool.PIPE); } sb.deleteCharAt(sb.length() - 1); sb.append("):([^>]|%>)*"); sb.append(quoteType); sb.append("<%=.*"); sb.append(quoteType); sb.append(".*%>"); sb.append(quoteType); sb.append("([^>]|%>)*>"); return sb.toString(); } protected String getVariableName(String line) { if (!line.endsWith(";") || line.startsWith("//")) { return null; } String variableName = null; int x = line.indexOf(" = "); if (x == -1) { int y = line.lastIndexOf(" "); if (y != -1) { variableName = line.substring(y + 1, line.length() - 1); } } else { line = line.substring(0, x); int y = line.lastIndexOf(" "); if (y != -1) { variableName = line.substring(y + 1); } } if (Validator.isVariableName(variableName)) { return variableName; } return null; } protected boolean hasUnusedJSPTerm(String fileName, String regex, String type) { _includeFileNames.add(fileName); Set<String> checkedForUnusedJSPTerm = new HashSet<String>(); return !isJSPTermRequired(fileName, regex, type, checkedForUnusedJSPTerm); } protected boolean hasUnusedTaglib(String fileName, String line) { if (!line.startsWith("<%@ taglib uri=")) { return false; } int x = line.indexOf(" prefix="); if (x == -1) { return false; } x = line.indexOf(StringPool.QUOTE, x); int y = line.indexOf(StringPool.QUOTE, x + 1); if ((x == -1) || (y == -1)) { return false; } String taglibPrefix = line.substring(x + 1, y); String regex = StringPool.LESS_THAN + taglibPrefix + StringPool.COLON; return hasUnusedJSPTerm(fileName, regex, "taglib"); } protected boolean hasUnusedVariable(String fileName, String line) { if (line.contains(": ")) { return false; } String variableName = getVariableName(line); if (Validator.isNull(variableName) || variableName.equals("false") || variableName.equals("true")) { return false; } String regex = "[^A-Za-z0-9_\"]" + variableName + "[^A-Za-z0-9_\"]"; return hasUnusedJSPTerm(fileName, regex, "variable"); } protected boolean isJSPDuplicateImport(String fileName, String importLine, boolean checkFile) { String content = _jspContents.get(fileName); if (Validator.isNull(content)) { return false; } int x = importLine.indexOf("page"); if (x == -1) { return false; } if (checkFile && content.contains(importLine.substring(x))) { return true; } int y = content.indexOf("<%@ include file="); if (y == -1) { return false; } y = content.indexOf(StringPool.QUOTE, y); if (y == -1) { return false; } int z = content.indexOf(StringPool.QUOTE, y + 1); if (z == -1) { return false; } String includeFileName = content.substring(y + 1, z); includeFileName = buildFullPathIncludeFileName(fileName, includeFileName); return isJSPDuplicateImport(includeFileName, importLine, true); } protected boolean isJSPTermRequired(String fileName, String regex, String type, Set<String> checkedForUnusedJSPTerm) { if (checkedForUnusedJSPTerm.contains(fileName)) { return false; } checkedForUnusedJSPTerm.add(fileName); String content = _jspContents.get(fileName); if (Validator.isNull(content)) { return false; } Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(content); if (matcher.find() && (!type.equals("variable") || (checkedForUnusedJSPTerm.size() > 1) || matcher.find())) { return true; } if (!_checkedForIncludesFileNames.contains(fileName)) { addJSPIncludeFileNames(fileName); if (fileName.endsWith("init.jsp") || fileName.endsWith("init.jspf") || fileName.contains("init-ext.jsp")) { addJSPReferenceFileNames(fileName); } } _checkedForIncludesFileNames.add(fileName); String[] includeFileNamesArray = _includeFileNames.toArray(new String[_includeFileNames.size()]); for (String includeFileName : includeFileNamesArray) { if (!checkedForUnusedJSPTerm.contains(includeFileName) && isJSPTermRequired(includeFileName, regex, type, checkedForUnusedJSPTerm)) { return true; } } return false; } protected void moveFrequentlyUsedImportsToCommonInit(int minCount) throws IOException { if (_importCountMap.isEmpty()) { return; } String commonInitFileName = "portal-web/docroot/html/common/init.jsp"; File commonInitFile = null; String commonInitFileContent = null; int x = -1; for (Map.Entry<String, Integer> importCount : _importCountMap.entrySet()) { Integer count = importCount.getValue(); if (count < minCount) { continue; } String importName = importCount.getKey(); int y = importName.lastIndexOf(StringPool.PERIOD); String importClassName = importName.substring(y + 1); if (_duplicateImportClassNames.contains(importClassName)) { continue; } if (commonInitFileContent == null) { commonInitFile = new File(commonInitFileName); commonInitFileContent = fileUtil.read(commonInitFile); x = commonInitFileContent.indexOf("<%@ page import"); } commonInitFileContent = StringUtil.insert(commonInitFileContent, "<%@ page import=\"" + importName + "\" %>\n", x); } if (commonInitFileContent != null) { fileUtil.write(commonInitFile, commonInitFileContent); _jspContents.put(commonInitFileName, commonInitFileContent); } } protected String stripJSPImports(String fileName, String content) throws IOException { fileName = fileName.replace(CharPool.BACK_SLASH, CharPool.FORWARD_SLASH); if (fileName.endsWith("init-ext.jsp")) { return content; } Matcher matcher = _jspImportPattern.matcher(content); if (!matcher.find()) { return content; } String imports = matcher.group(); imports = StringUtil.replace(imports, new String[] { "%><%@\r\n", "%><%@\n" }, new String[] { "%>\r\n<%@ ", "%>\n<%@ " }); List<String> importLines = new ArrayList<String>(); UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(new UnsyncStringReader(imports)); String line = null; while ((line = unsyncBufferedReader.readLine()) != null) { if (line.contains("import=")) { importLines.add(line); } } List<String> unneededImports = getJSPDuplicateImports(fileName, content, importLines); addJSPUnusedImports(fileName, importLines, unneededImports); for (String unneededImport : unneededImports) { imports = StringUtil.replace(imports, unneededImport, StringPool.BLANK); } ImportsFormatter importsFormatter = new JSPImportsFormatter(); imports = importsFormatter.format(imports); String beforeImports = content.substring(0, matcher.start()); if (Validator.isNull(imports)) { beforeImports = StringUtil.replaceLast(beforeImports, "\n", StringPool.BLANK); } String afterImports = content.substring(matcher.end()); if (Validator.isNull(afterImports)) { imports = StringUtil.replaceLast(imports, "\n", StringPool.BLANK); content = beforeImports + imports; return content; } content = beforeImports + imports + "\n" + afterImports; return content; } private static final String[] _TAG_LIBRARIES = new String[] { "aui", "c", "html", "jsp", "liferay-portlet", "liferay-security", "liferay-theme", "liferay-ui", "liferay-util", "portlet", "struts", "tiles" }; private Set<String> _checkedForIncludesFileNames = new HashSet<String>(); private List<String> _duplicateImportClassNames = new ArrayList<String>(); private List<String> _importClassNames = new ArrayList<String>(); private Map<String, Integer> _importCountMap = new HashMap<String, Integer>(); private Pattern _importsPattern = Pattern.compile("page import=\"(.+)\""); private Set<String> _includeFileNames = new HashSet<String>(); private Pattern _javaClassPattern = Pattern .compile("\n(private|protected|public).* class ([A-Za-z0-9]+) " + "([\\s\\S]*?)\n\\}\n"); private Map<String, String> _jspContents = new HashMap<String, String>(); private Pattern _jspImportPattern = Pattern.compile("(<.*\n*page.import=\".*>\n*)+", Pattern.MULTILINE); private Pattern _jspIncludeFilePattern = Pattern.compile("/.*[.]jsp[f]?"); private boolean _moveFrequentlyUsedImportsToCommonInit; private boolean _stripJSPImports = true; private Pattern _taglibLanguageKeyPattern1 = Pattern .compile("(?:confirmation|label|(?:M|m)essage|message key|names|title)=\"[^A-Z" + "<=%\\[\\s]+\""); private Pattern _taglibLanguageKeyPattern2 = Pattern .compile("(aui:)(?:input|select|field-wrapper) (?!.*label=(?:'|\").+(?:'|\").*" + "name=\"[^<=%\\[\\s]+\")(?!.*name=\"[^<=%\\[\\s]+\".*title=" + "(?:'|\").+(?:'|\"))(?!.*name=\"[^<=%\\[\\s]+\".*type=\"" + "hidden\").*name=\"([^<=%\\[\\s]+)\""); private Pattern _taglibLanguageKeyPattern3 = Pattern .compile("(liferay-ui:)(?:input-resource) .*id=\"([^<=%\\[\\s]+)\"(?!.*title=" + "(?:'|\").+(?:'|\"))"); private List<String> _unusedVariablesExclusions; private Pattern _xssPattern = Pattern.compile("\\s+([^\\s]+)\\s*=\\s*(Bean)?ParamUtil\\.getString\\("); }