rdf4j icon indicating copy to clipboard operation
rdf4j copied to clipboard

embedded tomcat broke btwn 4.2.4 and 4.3.1

Open nguyenm100 opened this issue 1 year ago • 3 comments

Current Behavior

we have some code to use embedded tomcat to run/debug locally which was working in 4.2.x but upon upgrading to 4.3.x, it no longer works. appears to be something related to workbench (e.g. if i just add server war to the context, it runs fine).

error is:

SEVERE: Exception starting filter [CacheFilter] java.lang.LinkageError: loader constraint violation: when resolving method 'org.slf4j.ILoggerFactory org.slf4j.impl.StaticLoggerBinder.getLoggerFactory()' the class loader org.apache.catalina.loader.ParallelWebappClassLoader @1b1438f7 of the current class, org/slf4j/LoggerFactory, and the class loader 'app' for the method's defining class, org/slf4j/impl/StaticLoggerBinder, have different Class objects for the type org/slf4j/ILoggerFactory used in the signature (org.slf4j.LoggerFactory is in unnamed module of loader org.apache.catalina.loader.ParallelWebappClassLoader @1b1438f7, parent loader 'app'; org.slf4j.impl.StaticLoggerBinder is in unnamed module of loader 'app') at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:423) at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:362) at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:388) at org.eclipse.rdf4j.workbench.proxy.CacheFilter.(CacheFilter.java:34) at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499) at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480) at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:120) at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:264) at org.apache.catalina.core.ApplicationFilterConfig.(ApplicationFilterConfig.java:108) at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4591) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5233) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1419) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:833)

and I've ensured there is only one version of slf4j-api (slf4j-api-1.7.36.jar) in the rdf4j-workbench\WEB-INF\lib (verified through mvn dependency:tree as well).

looks like a lot changed btwn 4.2.x and 4.3.x but curious if anyone would know what may have changed around slf4j btwn the versions that might cause this problem.

Expected Behavior

for it to work :-)

Steps To Reproduce

embedded tomcat code is pretty straight-forward:

public static void main(final String[] args) throws Exception {
	final Tomcat tomcat = startRd4jServer("/.../sandbox.properties",
			"/.../rdf4j-server.war", "/.../rdf4j-workbench.war");
	tomcat.getServer().await();
}

public static Tomcat startRd4jServer(final String propLocation, final String warLocation, final String workbenchLocation) throws IOException, ServletException, LifecycleException {
	System.getProperties().putAll(loadFromFile(propLocation));
	final int port = Integer.parseInt(System.getProperty("port.http"));
	FileUtils.createParentDirectories(new File("./tomcat." + port + "/webapps/" + RDF4J_SERVER));

	FileUtils.createParentDirectories(new File("./tomcat." + port + "/webapps/" + RDF4J_WORKBENCH));

	final Tomcat tomcat = new Tomcat();
	tomcat.setPort(port);

	final StandardContext ctx1 = (StandardContext) tomcat.addWebapp("/" + RDF4J_SERVER, new File(warLocation).getAbsolutePath());
	ctx1.setResources(new StandardRoot(ctx1));
	final StandardContext ctx2 = (StandardContext) tomcat.addWebapp("/" + RDF4J_WORKBENCH, new File(workbenchLocation).getAbsolutePath());
	ctx2.setResources(new StandardRoot(ctx2));

	tomcat.start();
	Runtime.getRuntime().addShutdownHook(new Thread(() -> {
		try {
			tomcat.stop();
		} catch (final LifecycleException e) {
			log.error("Failed to stop Tomcat. Will execute `System.exit(1)`", e);
			System.exit(1);
		}
	}));
	return tomcat;
}

Version

4.3.4 (but tested 4.2.4 and 4.3.1 and saw it broke)

Are you interested in contributing a solution yourself?

None

Anything else?

No response

nguyenm100 avatar Aug 09 '23 21:08 nguyenm100

receive the same error when using vanilla 4.3.5 workbench.

when I use vanilla 4.2.4 it starts but I see:

SLF4J: Found binding in [jar:file:/C:/m2/repository/ch/qos/logback/logback-classic/1.2.10/logback-classic-1.2.10.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: Found binding in [jar:file:/C:/rdf4j-workbench/WEB-INF/lib/slf4j-jdk14-1.7.36.jar!/org/slf4j/impl/StaticLoggerBinder.class]

nguyenm100 avatar Aug 10 '23 12:08 nguyenm100

looks like rdf4j 4.3.x removed jar: slf4j-jdk14-1.7.36.jar manually adding this back into the embedded tomcat deployment rdf4j-workbench/webinf/lib directory resolves the issue

i'm guessing there's an underlying logging initializing/dependency issue in rdf4j, possibly, due to the various loggers (logback, jcl, jdk, etc.) that it drags in.

nguyenm100 avatar Aug 12 '23 21:08 nguyenm100

btw- lmk if adding embedded tomcat to rdf4j scope:test is desirable. it does make debugging workbench/server a bit easier for us.

nguyenm100 avatar Aug 12 '23 21:08 nguyenm100