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: [email protected]
For additional commands, e-mail: [email protected]