According to the Javadoc for java.util.ServiceLoader (http://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html): [quote]A service provider is identified by placing a provider-configuration file in the resource directory META-INF/services. The file's name is the fully-qualified binary name of the service's type. The file contains a list of fully-qualified binary names of concrete provider classes, one per line. Space and tab characters surrounding each name, as well as blank lines, are ignored. The comment character is '#' ('\u0023', NUMBER SIGN); on each line all characters following the first comment character are ignored. The file must be encoded in UTF-8.[/quote] However, based on the error below it appears that Tomcat does not abide by this requirement. The Log4j Core JAR for 2.0-beta8 will have a ServletContainerInitializer in it, and the provider-configuration file for this SCI contains a copyright statement. Tomcat barfs and fails to deploy the application due to this copyright statement. This problem exists in both Tomcat 7 and Tomcat 8. SEVERE: The ServletContentInitializer [# Licensed to the Apache Software Foundation (ASF) under one or more] could not be created java.lang.ClassNotFoundException: # Licensed to the Apache Software Foundation (ASF) under one or more at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1465) at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1310) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:339) at org.apache.catalina.startup.ContextConfig.getServletContainerInitializer(ContextConfig.java:1526) at org.apache.catalina.startup.ContextConfig.processServletContainerInitializers(ContextConfig.java:1436) at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1174) at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:814) at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:321) at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119) at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5100) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:726) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:702) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:698) at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1491) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:491) at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300) at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819) at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:792) at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:468) at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:415) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:491) at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300) at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819) at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:792) at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1465) at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:75) at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1306) at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1398) at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:827) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:491) at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:322) at sun.rmi.transport.Transport$1.run(Transport.java:177) at sun.rmi.transport.Transport$1.run(Transport.java:174) at java.security.AccessController.doPrivileged(Native Method) at sun.rmi.transport.Transport.serviceCall(Transport.java:173) at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:556) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:811) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:670) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:724)
Looking at the code for ContextConfig, Tomcat also does not parse multiple SCIs in a provider-configuration file, which is another violation of the service provider standard.
Created attachment 30564 [details] Proposed patch that resolves this issue Updated ContextConfig to 1) ignore comments (both whole-line comments and end-of-line comments) and 2) allow multiple SCIs in a single provider-configuration file.
Thanks for the report and the patch. It was applied to trunk and 7.0.x and will be included in 7.0.43 onwards.
Excellent! Thanks for acting on it so quickly!