Hello everyone, In my company, one of our Maven projects create a war that we usually deploy in tomcat. For debug purpose, we added a test class that instanciate an embed Tomcat instance to run the application from an IDE (Intellij in my case).
Using tomcat-emded-core.8.5.4, at startup, it gives me a lot of warnings like: *Aug 29, 2016 11:22:57 AM org.apache.tomcat.util.scan.StandardJarScanner scan* *WARNING: Failed to scan [file:/home/olivier/maven/repo/net/sf/jung/jung-graph-impl/2.0.1/jung-api-2.0.1.jar] from classloader hierarchyjava.io.FileNotFoundException: /home/olivier/maven/repo/net/sf/jung/jung-graph-impl/2.0.1/jung-api-2.0.1.jar (No such file or directory)* Given maven repository architecture, it is logical that the scanner can't find the jar as we are looking for *jung-api *in* jung-graph-impl *folder *.* If I instead look in */home/olivier/maven/repo/net/sf/jung/jung-api/2.0.1/jung-api-2.0.1.jar,* I correctly find the wanted jar. After investigating the troubling jars and StandardJarScanner source code, I discovered that *jung-graph-impl* includes a MANIFEST file with the Class-Path attribute containing *jung-api*, among others. When this attribute is defined, the scanner reads the path of the jar containing the MANIFEST, and uses it to get the jars mentionned in the classpath. *Jar file: /home/olivier/maven/repo/net/sf/jung/jung-graph-impl/2.0.1/jung-api-2.0.1.jar* *-> Jar path: /home/olivier/maven/repo/net/sf/jung/jung-graph-impl/2.0.1/* *-> Looking for /home/olivier/maven/repo/net/sf/jung/jung-graph-impl/2.0.1/jung-api-2.0.1.jar* For Tomcat application (installed on a computer), this is fine as wars shipped all their needed jars in WEB-INF/lib. Thus, the algo to look for another jar is ok. This is less ok when Tomcat is run from an IDE, where the classpath is made from various locations. Eg: /opt/java/jdk1.8.0_92/bin/java -Dfile.encoding=UTF-8 *-classpath /opt/java/jdk1.8.0_92/jre/lib/charsets.jar:/opt/java/jdk1.8.0_92/jre/lib/deploy.jar:[... many jars]:/home/olivier/maven/repo/net/sf/jung/jung-graph-impl/2.0.1/jung-graph-impl-2.0.1.jar:/home/olivier/maven/repo/net/sf/jung/jung-api/2.0.1/jung-api-2.0.1.jar:[... more jars]* MyServer Is this a bug or is there something wrong with my Tomcat config or the jars I use ? I attached to the ticket the main class of my application, to show how I create my Tomcat instance. tomcat-embed is imported in my project by requiring the following maven dependency: +- org.apache.tomcat.embed:tomcat-embed-websocket:jar:8.5.4:test | \- org.apache.tomcat.embed:tomcat-embed-core:jar:8.5.4:test Thanks a lot for the help
import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import javax.servlet.ServletException; import org.apache.catalina.startup.Tomcat; public class MyServer { public static final int DEFAULT_PORT = 8081; /** * Creates a server running application. * @param port port to use * @param path path to static resources to serve * @return a Tomcat instance (not running) * @throws IOException if it fails to create a temporary directory for Tomcat * @throws ServletException if it fails to create a webapp */ public static Tomcat createServer(final int port, final String path) throws IOException, ServletException { final Tomcat tomcat = new Tomcat(); tomcat.setPort(port); final File base = createBaseDirectory(); tomcat.setBaseDir(base.getAbsolutePath()); tomcat.addWebapp("", getStaticResourceBasePath(path)); System.out.printf("Creating a server on port %d with resources from %s%n", port, path); return tomcat; } public static void main(final String[] args) throws Exception { int port = DEFAULT_PORT; if (args != null && args.length >= 1) { port = Integer.parseInt(args[0]); } final String resourcePath = args != null && args.length >= 2 ? args[1] : "default/path/to/app"; final Tomcat server = createServer(port, resourcePath); server.start(); server.getServer().await(); } /** * Give the path to the base directory where tomcat will work. * <p/> * We create a temporary folder because Tomcat will create temporary files in * it and we don't want to pollute current folder. * @return the base directory for tomcat. * @throws IOException if we could not create the temporary directory. */ protected static File createBaseDirectory() throws IOException { final File base = File.createTempFile("tmp-", ""); if (!base.delete()) { throw new IOException("Cannot (re)create base folder: " + base.getAbsolutePath()); } if (!base.mkdir()) { throw new IOException("Cannot create base folder: " + base.getAbsolutePath()); } return base; } /** * Give the path to the static resources. * <p/> * The resources are located under src/main/webapp/ as of Maven convention for webapps. * The output of the gulp build is the subfolder build. * @param resourcePath the path to web resources to load * @return the static resources folder. */ protected static String getStaticResourceBasePath(final String resourcePath) { // Since embedded Tomcat cannot use relative paths, we cheat by finding // another resource and change the end of the path to get our build // folder final String hintResource = "path/to/a/known/file.txt"; final File hintFile = new File(Thread.currentThread().getContextClassLoader().getResource(hintResource).getFile()); // Keep only the part before target/ and fill with our known path. final String hintPath = Paths.get("target", "classes", hintResource).toString(); return hintFile.getAbsolutePath().replace(hintPath, resourcePath); } }
--------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org