All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.fabric8.forge.camel.maven.EndpointMojo Maven / Gradle / Ivy

There is a newer version: 2.3.90
Show newest version
/**
 * Copyright 2005-2015 Red Hat, Inc.
 * 

* Red Hat licenses this file to you under the Apache License, version * 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at *

* http://www.apache.org/licenses/LICENSE-2.0 *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. */ package io.fabric8.forge.camel.maven; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import io.fabric8.forge.camel.commands.project.helper.RouteBuilderParser; import io.fabric8.forge.camel.commands.project.helper.XmlRouteParser; import io.fabric8.forge.camel.commands.project.model.CamelEndpointDetails; import io.fabric8.forge.camel.commands.project.model.CamelSimpleDetails; import org.apache.camel.catalog.CamelCatalog; import org.apache.camel.catalog.DefaultCamelCatalog; import org.apache.camel.catalog.EndpointValidationResult; import org.apache.camel.catalog.SimpleValidationResult; import org.apache.camel.catalog.lucene.LuceneSuggestionStrategy; import org.apache.camel.catalog.maven.MavenVersionManager; import org.apache.maven.model.Dependency; import org.apache.maven.model.Resource; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; import org.jboss.forge.roaster.Roaster; import org.jboss.forge.roaster.model.JavaType; import org.jboss.forge.roaster.model.source.JavaClassSource; /** * Analyses the project source code for Camel routes, and validates the endpoint uris and simple expressions. */ @Mojo(name = "validate", defaultPhase = LifecyclePhase.PROCESS_TEST_CLASSES, requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME) public class EndpointMojo extends AbstractMojo { @Parameter(defaultValue = "${project}", readonly = true, required = true) private MavenProject project; /** * Whether to fail if invalid Camel endpoints was found. By default the plugin logs the errors at WARN level */ @Parameter(property = "failOnError", defaultValue = "false", readonly = true, required = false) private boolean failOnError; /** * Whether to log endpoint URIs which was un-parsable and therefore not possible to validate */ @Parameter(property = "logUnparseable", defaultValue = "false", readonly = true, required = false) private boolean logUnparseable; /** * Whether to include Java files to be validated for invalid Camel endpoints */ @Parameter(property = "includeJava", defaultValue = "true", readonly = true, required = false) private boolean includeJava; /** * Whether to include XML files to be validated for invalid Camel endpoints */ @Parameter(property = "includeXml", defaultValue = "true", readonly = true, required = false) private boolean includeXml; /** * Whether to include test source code */ @Parameter(property = "includeTest", defaultValue = "false", readonly = true, required = false) private boolean includeTest; /** * To filter the names of java and xml files to only include files matching any of the given list of patterns (wildcard and regular expression). * Multiple values can be separated by comma. */ @Parameter(property = "includes", readonly = true, required = false) private String includes; /** * To filter the names of java and xml files to exclude files matching any of the given list of patterns (wildcard and regular expression). * Multiple values can be separated by comma. */ @Parameter(property = "excludes", readonly = true, required = false) private String excludes; /** * Whether to ignore unknown components */ @Parameter(property = "ignoreUnknownComponent", defaultValue = "true", readonly = true, required = false) private boolean ignoreUnknownComponent; /** * Whether to ignore incapable of parsing the endpoint uri */ @Parameter(property = "ignoreIncapable", defaultValue = "true", readonly = true, required = false) private boolean ignoreIncapable; /** * Whether to ignore components that uses lenient properties. When this is true, then the uri validation is stricter * but would fail on properties that are not part of the component but in the uri because of using lenient properties. * For example using the HTTP components to provide query parameters in the endpoint uri. */ @Parameter(property = "ignoreLenientProperties", defaultValue = "true", readonly = true, required = false) private boolean ignoreLenientProperties; /** * Whether to show all endpoints and simple expressions (both invalid and valid). */ @Parameter(property = "showAll", defaultValue = "false", readonly = true, required = false) private boolean showAll; /** * Whether to allow downloading Camel catalog version from the internet. This is needed if the project * uses a different Camel version than this plugin is using by default. */ @Parameter(property = "downloadVersion", defaultValue = "true", readonly = true, required = false) private boolean downloadVersion; @Override public void execute() throws MojoExecutionException, MojoFailureException { CamelCatalog catalog = new DefaultCamelCatalog(); // add activemq as known component catalog.addComponent("activemq", "org.apache.activemq.camel.component.ActiveMQComponent"); // enable did you mean catalog.setSuggestionStrategy(new LuceneSuggestionStrategy()); // enable loading other catalog versions dynamically catalog.setVersionManager(new MavenVersionManager()); if (downloadVersion) { String camelVersion = findCamelVersion(project); if (camelVersion != null && !camelVersion.equals(catalog.getCatalogVersion())) { // the project uses a different Camel version so attempt to load it getLog().info("Downloading Camel version: " + camelVersion); boolean loaded = catalog.loadVersion(camelVersion); if (!loaded) { getLog().warn("Error downloading Camel version: " + camelVersion); } } } if (catalog.getLoadedVersion() != null) { getLog().info("Using Camel version: " + catalog.getLoadedVersion()); } else { getLog().info("Using Camel version: " + catalog.getCatalogVersion()); } List endpoints = new ArrayList<>(); List simpleExpressions = new ArrayList<>(); Set javaFiles = new LinkedHashSet(); Set xmlFiles = new LinkedHashSet(); // find all java route builder classes if (includeJava) { for (String dir : project.getCompileSourceRoots()) { findJavaFiles(new File(dir), javaFiles); } if (includeTest) { for (String dir : project.getTestCompileSourceRoots()) { findJavaFiles(new File(dir), javaFiles); } } } // find all xml routes if (includeXml) { for (Resource dir : project.getResources()) { findXmlFiles(new File(dir.getDirectory()), xmlFiles); } if (includeTest) { for (Resource dir : project.getTestResources()) { findXmlFiles(new File(dir.getDirectory()), xmlFiles); } } } for (File file : javaFiles) { if (matchFile(file)) { try { List fileEndpoints = new ArrayList<>(); List fileSimpleExpressions = new ArrayList<>(); List unparsable = new ArrayList<>(); // parse the java source code and find Camel RouteBuilder classes String fqn = file.getPath(); String baseDir = "."; JavaType out = Roaster.parse(file); // we should only parse java classes (not interfaces and enums etc) if (out != null && out instanceof JavaClassSource) { JavaClassSource clazz = (JavaClassSource) out; RouteBuilderParser.parseRouteBuilderEndpoints(clazz, baseDir, fqn, fileEndpoints, unparsable, includeTest); RouteBuilderParser.parseRouteBuilderSimpleExpressions(clazz, baseDir, fqn, fileSimpleExpressions); // add what we found in this file to the total list endpoints.addAll(fileEndpoints); simpleExpressions.addAll(fileSimpleExpressions); // was there any unparsable? if (logUnparseable && !unparsable.isEmpty()) { for (String uri : unparsable) { getLog().warn("Cannot parse endpoint uri " + uri + " in java file " + file); } } } } catch (Exception e) { getLog().warn("Error parsing java file " + file + " code due " + e.getMessage(), e); } } } for (File file : xmlFiles) { if (matchFile(file)) { try { List fileEndpoints = new ArrayList<>(); List fileSimpleExpressions = new ArrayList<>(); // parse the xml source code and find Camel routes String fqn = file.getPath(); String baseDir = "."; InputStream is = new FileInputStream(file); XmlRouteParser.parseXmlRouteEndpoints(is, baseDir, fqn, fileEndpoints); is.close(); // need a new stream is = new FileInputStream(file); XmlRouteParser.parseXmlRouteSimpleExpressions(is, baseDir, fqn, fileSimpleExpressions); is.close(); // add what we found in this file to the total list endpoints.addAll(fileEndpoints); simpleExpressions.addAll(fileSimpleExpressions); } catch (Exception e) { getLog().warn("Error parsing xml file " + file + " code due " + e.getMessage(), e); } } } int endpointErrors = 0; int unknownComponents = 0; int incapableErrors = 0; for (CamelEndpointDetails detail : endpoints) { EndpointValidationResult result = catalog.validateEndpointProperties(detail.getEndpointUri(), ignoreLenientProperties); boolean ok = result.isSuccess(); if (!ok && ignoreUnknownComponent && result.getUnknownComponent() != null) { // if we failed due unknown component then be okay if we should ignore that unknownComponents++; ok = true; } if (!ok && ignoreIncapable && result.getIncapable() != null) { // if we failed due incapable then be okay if we should ignore that incapableErrors++; ok = true; } if (!ok) { if (result.getUnknownComponent() != null) { unknownComponents++; } else if (result.getIncapable() != null) { incapableErrors++; } else { endpointErrors++; } StringBuilder sb = new StringBuilder(); sb.append("Endpoint validation error at: "); if (detail.getClassName() != null && detail.getLineNumber() != null) { // this is from java code sb.append(detail.getClassName()); if (detail.getMethodName() != null) { sb.append(".").append(detail.getMethodName()); } sb.append("(").append(asSimpleClassName(detail.getClassName())).append(".java:"); sb.append(detail.getLineNumber()).append(")"); } else if (detail.getLineNumber() != null) { // this is from xml String fqn = stripRootPath(asRelativeFile(detail.getFileName())); if (fqn.endsWith(".xml")) { fqn = fqn.substring(0, fqn.length() - 4); fqn = asPackageName(fqn); } sb.append(fqn); sb.append("(").append(asSimpleClassName(fqn)).append(".xml:"); sb.append(detail.getLineNumber()).append(")"); } else { sb.append(detail.getFileName()); } sb.append("\n\n"); String out = result.summaryErrorMessage(false); sb.append(out); sb.append("\n\n"); getLog().warn(sb.toString()); } else if (showAll) { StringBuilder sb = new StringBuilder(); sb.append("Endpoint validation passsed at: "); if (detail.getClassName() != null && detail.getLineNumber() != null) { // this is from java code sb.append(detail.getClassName()); if (detail.getMethodName() != null) { sb.append(".").append(detail.getMethodName()); } sb.append("(").append(asSimpleClassName(detail.getClassName())).append(".java:"); sb.append(detail.getLineNumber()).append(")"); } else if (detail.getLineNumber() != null) { // this is from xml String fqn = stripRootPath(asRelativeFile(detail.getFileName())); if (fqn.endsWith(".xml")) { fqn = fqn.substring(0, fqn.length() - 4); fqn = asPackageName(fqn); } sb.append(fqn); sb.append("(").append(asSimpleClassName(fqn)).append(".xml:"); sb.append(detail.getLineNumber()).append(")"); } else { sb.append(detail.getFileName()); } sb.append("\n"); sb.append("\n\t").append(result.getUri()); sb.append("\n\n"); getLog().info(sb.toString()); } } String endpointSummary; if (endpointErrors == 0) { int ok = endpoints.size() - endpointErrors - incapableErrors - unknownComponents; endpointSummary = String.format("Endpoint validation success: (%s = passed, %s = invalid, %s = incapable, %s = unknown components)", ok, endpointErrors, incapableErrors, unknownComponents); } else { int ok = endpoints.size() - endpointErrors - incapableErrors - unknownComponents; endpointSummary = String.format("Endpoint validation error: (%s = passed, %s = invalid, %s = incapable, %s = unknown components)", ok, endpointErrors, incapableErrors, unknownComponents); } if (endpointErrors > 0) { getLog().warn(endpointSummary); } else { getLog().info(endpointSummary); } int simpleErrors = 0; for (CamelSimpleDetails detail : simpleExpressions) { SimpleValidationResult result = catalog.validateSimpleExpression(detail.getSimple()); if (!result.isSuccess()) { simpleErrors++; StringBuilder sb = new StringBuilder(); sb.append("Simple validation error at: "); if (detail.getClassName() != null && detail.getLineNumber() != null) { // this is from java code sb.append(detail.getClassName()); if (detail.getMethodName() != null) { sb.append(".").append(detail.getMethodName()); } sb.append("(").append(asSimpleClassName(detail.getClassName())).append(".java:"); sb.append(detail.getLineNumber()).append(")"); } else if (detail.getLineNumber() != null) { // this is from xml String fqn = stripRootPath(asRelativeFile(detail.getFileName())); if (fqn.endsWith(".xml")) { fqn = fqn.substring(0, fqn.length() - 4); fqn = asPackageName(fqn); } sb.append(fqn); sb.append("(").append(asSimpleClassName(fqn)).append(".xml:"); sb.append(detail.getLineNumber()).append(")"); } else { sb.append(detail.getFileName()); } sb.append("\n"); String[] lines = result.getError().split("\n"); for (String line : lines) { sb.append("\n\t").append(line); } sb.append("\n"); getLog().warn(sb.toString()); } else if (showAll) { StringBuilder sb = new StringBuilder(); sb.append("Simple validation passed at: "); if (detail.getClassName() != null && detail.getLineNumber() != null) { // this is from java code sb.append(detail.getClassName()); if (detail.getMethodName() != null) { sb.append(".").append(detail.getMethodName()); } sb.append("(").append(asSimpleClassName(detail.getClassName())).append(".java:"); sb.append(detail.getLineNumber()).append(")"); } else if (detail.getLineNumber() != null) { // this is from xml String fqn = stripRootPath(asRelativeFile(detail.getFileName())); if (fqn.endsWith(".xml")) { fqn = fqn.substring(0, fqn.length() - 4); fqn = asPackageName(fqn); } sb.append(fqn); sb.append("(").append(asSimpleClassName(fqn)).append(".xml:"); sb.append(detail.getLineNumber()).append(")"); } else { sb.append(detail.getFileName()); } sb.append("\n"); sb.append("\n\t").append(result.getSimple()); sb.append("\n\n"); getLog().info(sb.toString()); } } String simpleSummary; if (simpleErrors == 0) { int ok = simpleExpressions.size() - simpleErrors; simpleSummary = String.format("Simple validation success: (%s = passed, %s = invalid)", ok, simpleErrors); } else { int ok = simpleExpressions.size() - simpleErrors; simpleSummary = String.format("Simple validation error: (%s = passed, %s = invalid)", ok, simpleErrors); } if (failOnError && (endpointErrors > 0 || simpleErrors > 0)) { throw new MojoExecutionException(endpointSummary + "\n" + simpleSummary); } if (simpleErrors > 0) { getLog().warn(simpleSummary); } else { getLog().info(simpleSummary); } } private static String findCamelVersion(MavenProject project) { Dependency candidate = null; for (Dependency dep : project.getDependencies()) { if ("org.apache.camel".equals(dep.getGroupId())) { if ("camel-core".equals(dep.getArtifactId())) { // favor camel-core candidate = dep; break; } else { candidate = dep; } } } if (candidate != null) { return candidate.getVersion(); } return null; } private void findJavaFiles(File dir, Set javaFiles) { File[] files = dir.isDirectory() ? dir.listFiles() : null; if (files != null) { for (File file : files) { if (file.getName().endsWith(".java")) { javaFiles.add(file); } else if (file.isDirectory()) { findJavaFiles(file, javaFiles); } } } } private void findXmlFiles(File dir, Set xmlFiles) { File[] files = dir.isDirectory() ? dir.listFiles() : null; if (files != null) { for (File file : files) { if (file.getName().endsWith(".xml")) { xmlFiles.add(file); } else if (file.isDirectory()) { findXmlFiles(file, xmlFiles); } } } } private boolean matchFile(File file) { if (excludes == null && includes == null) { return true; } // exclude take precedence if (excludes != null) { for (String exclude : excludes.split(",")) { exclude = exclude.trim(); // try both with and without directory in the name String fqn = stripRootPath(asRelativeFile(file.getAbsolutePath())); boolean match = EndpointHelper.matchPattern(fqn, exclude) || EndpointHelper.matchPattern(file.getName(), exclude); if (match) { return false; } } } // include if (includes != null) { for (String include : includes.split(",")) { include = include.trim(); // try both with and without directory in the name String fqn = stripRootPath(asRelativeFile(file.getAbsolutePath())); boolean match = EndpointHelper.matchPattern(fqn, include) || EndpointHelper.matchPattern(file.getName(), include); if (match) { return true; } } // did not match any includes return false; } // was not excluded nor failed include so its accepted return true; } private String asRelativeFile(String name) { String answer = name; String base = project.getBasedir().getAbsolutePath(); if (name.startsWith(base)) { answer = name.substring(base.length()); // skip leading slash for relative path if (answer.startsWith(File.separator)) { answer = answer.substring(1); } } return answer; } private String stripRootPath(String name) { // strip out any leading source / resource directory for (String dir : project.getCompileSourceRoots()) { dir = asRelativeFile(dir); if (name.startsWith(dir)) { return name.substring(dir.length() + 1); } } for (String dir : project.getTestCompileSourceRoots()) { dir = asRelativeFile(dir); if (name.startsWith(dir)) { return name.substring(dir.length() + 1); } } for (Resource resource : project.getResources()) { String dir = asRelativeFile(resource.getDirectory()); if (name.startsWith(dir)) { return name.substring(dir.length() + 1); } } for (Resource resource : project.getTestResources()) { String dir = asRelativeFile(resource.getDirectory()); if (name.startsWith(dir)) { return name.substring(dir.length() + 1); } } return name; } private static String asPackageName(String name) { return name.replace(File.separator, "."); } private static String asSimpleClassName(String className) { int dot = className.lastIndexOf('.'); if (dot > 0) { return className.substring(dot + 1); } else { return className; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy