package org.jboss.windup.rules.apps.javaee.rules; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.jboss.windup.ast.java.data.ClassReference; import org.jboss.windup.ast.java.data.ResolutionStatus; import org.jboss.windup.ast.java.data.TypeReferenceLocation; import org.jboss.windup.config.AbstractRuleProvider; import org.jboss.windup.config.GraphRewrite; import org.jboss.windup.config.loader.RuleLoaderContext; import org.jboss.windup.config.metadata.RuleMetadata; import org.jboss.windup.config.operation.iteration.AbstractIterationOperation; import org.jboss.windup.config.phase.InitialAnalysisPhase; import org.jboss.windup.config.query.Query; import org.jboss.windup.reporting.service.ClassificationService; import org.jboss.windup.rules.apps.java.model.JavaClassModel; import org.jboss.windup.rules.apps.java.scan.ast.JavaTypeReferenceModel; import org.jboss.windup.rules.apps.java.scan.ast.TypeInterestFactory; import org.jboss.windup.rules.apps.java.service.JavaClassService; import org.jboss.windup.rules.apps.java.service.TypeReferenceService; import org.jboss.windup.rules.apps.javaee.model.JspSourceFileModel; import org.ocpsoft.rewrite.config.Configuration; import org.ocpsoft.rewrite.config.ConfigurationBuilder; import org.ocpsoft.rewrite.context.EvaluationContext; /** * Extracts type references from JSP files. * * @author <a href="mailto:jesse.sightler@gmail.com">Jesse Sightler</a> */ @RuleMetadata(phase = InitialAnalysisPhase.class, haltOnException = true) public class AnalyzeJSPFileRuleProvider extends AbstractRuleProvider { final static String UNPARSEABLE_JSP_CLASSIFICATION = "Unparseable JSP File"; final static String UNPARSEABLE_JSP_DESCRIPTION = "This JSP file could not be parsed"; // @formatter:off @Override public Configuration getConfiguration(RuleLoaderContext ruleLoaderContext) { return ConfigurationBuilder.begin() .addRule() .when(Query.fromType(JspSourceFileModel.class)) .perform(new ParseSourceOperation()); } // @formatter:on private class ParseSourceOperation extends AbstractIterationOperation<JspSourceFileModel> { @Override public void perform(GraphRewrite event, EvaluationContext context, JspSourceFileModel sourceFile) { TypeReferenceService typeReferenceService = new TypeReferenceService(event.getGraphContext()); try { // Setup some basic details about the "Java Class" // source root, is decompiled, javaclass. package name sourceFile.setPackageName(""); JavaClassService javaClassService = new JavaClassService(event.getGraphContext()); JavaClassModel classModel = javaClassService.create(); classModel.setPackageName(""); classModel.setSimpleName(sourceFile.getFileName()); classModel.setQualifiedName(sourceFile.getFileName()); classModel.setExtends(javaClassService.getOrCreatePhantom("javax.servlet.http.HttpServlet")); classModel.setOriginalSource(sourceFile); sourceFile.addJavaClass(classModel); Iterable<ClassReference> references = getClassReferences(typeReferenceService, sourceFile); for (ClassReference reference : references) { JavaTypeReferenceModel typeReference = typeReferenceService.createTypeReference(sourceFile, reference.getLocation(), reference.getResolutionStatus(), reference.getLineNumber(), reference.getColumn(), reference.getLength(), reference.getQualifiedName(), reference.getLine()); } } catch (Exception e) { ClassificationService classificationService = new ClassificationService(event.getGraphContext()); classificationService.attachClassification(event, context, sourceFile, UNPARSEABLE_JSP_CLASSIFICATION, UNPARSEABLE_JSP_DESCRIPTION); sourceFile.setParseError("JSP file could not be parsed: " + e.getMessage()); } } } private Iterable<ClassReference> getClassReferences(TypeReferenceService service, JspSourceFileModel sourceFile) throws IOException { String source = FileUtils.readFileToString(sourceFile.asFile()); List<ClassReference> results = new ArrayList<>(); results.addAll(findImports(source)); results.addAll(findTaglib(source)); return results; } private List<ClassReference> findImports(String source) { List<ClassReference> results = new ArrayList<>(); Pattern jspImport = Pattern.compile("<%@\\s*page\\s+[^>]*\\s*import\\s*=\\s*['\"]([^'\"]+)['\"].*?%>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE); Matcher matcher = jspImport.matcher(source); while (matcher.find()) { String matched = matcher.group(1); if (StringUtils.isNotBlank(matched)) { String[] imports = StringUtils.split(matched, ","); if (imports != null) { for (String imported : imports) { imported = StringUtils.trim(imported); if (TypeInterestFactory.matchesAny(imported, TypeReferenceLocation.IMPORT)) { ClassReference reference = createClassReference(TypeReferenceLocation.IMPORT, source, imported, matcher.start()); results.add(reference); } } } } } return results; } private List<ClassReference> findTaglib(String source) { List<ClassReference> results = new ArrayList<>(); Pattern taglibPattern = Pattern.compile("<%@\\s*taglib\\s+[^>]*\\s*uri\\s*=\\s*['\"]([^'\"]+)['\"].*?%>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE); Matcher matcher = taglibPattern.matcher(source); while (matcher.find()) { String matched = matcher.group(1); if (StringUtils.isNotBlank(matched)) { if (TypeInterestFactory.matchesAny(matched, TypeReferenceLocation.TAGLIB_IMPORT)) { ClassReference reference = createClassReference(TypeReferenceLocation.TAGLIB_IMPORT, source, matched, matcher.start()); results.add(reference); } } } return results; } private ClassReference createClassReference(TypeReferenceLocation location, String source, String reference, int startPosition) { String subString = StringUtils.substring(source, 0, startPosition + 1); String[] lines = subString.split("\r\n|\r|\n"); int lineNumber = lines.length; int column = lines[lines.length - 1].indexOf(source.substring(startPosition)); int length = reference.length(); return new ClassReference(reference, null, null, null, ResolutionStatus.UNKNOWN, location, lineNumber, column, length, reference); } }