--- java/org/apache/catalina/loader/WebappLoader.java +++ java/org/apache/catalina/loader/WebappLoader.java @@ -57,7 +57,7 @@ import org.apache.catalina.core.StandardContext; import org.apache.catalina.mbeans.MBeanUtils; import org.apache.catalina.util.LifecycleMBeanBase; import org.apache.naming.resources.DirContextURLStreamHandler; -import org.apache.naming.resources.DirContextURLStreamHandlerFactory; +import org.apache.naming.resources.TomcatURLStreamHandlerFactory; import org.apache.naming.resources.Resource; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.modeler.Registry; @@ -560,7 +560,7 @@ public class WebappLoader extends LifecycleMBeanBase // Register a stream handler factory for the JNDI protocol URLStreamHandlerFactory streamHandlerFactory = - DirContextURLStreamHandlerFactory.getInstance(); + TomcatURLStreamHandlerFactory.getInstance(); if (first) { first = false; try { --- java/org/apache/catalina/realm/MemoryRealm.java +++ java/org/apache/catalina/realm/MemoryRealm.java @@ -19,17 +19,18 @@ package org.apache.catalina.realm; -import java.io.File; +import java.io.IOException; +import java.io.InputStream; import java.security.Principal; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; -import org.apache.catalina.Globals; import org.apache.catalina.LifecycleException; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.digester.Digester; +import org.apache.tomcat.util.file.ConfigFileLoader; /** @@ -282,30 +283,42 @@ public class MemoryRealm extends RealmBase { @Override protected void startInternal() throws LifecycleException { - // Validate the existence of our database file - File file = new File(pathname); - if (!file.isAbsolute()) - file = new File(System.getProperty(Globals.CATALINA_BASE_PROP), pathname); - if (!file.exists() || !file.canRead()) - throw new LifecycleException - (sm.getString("memoryRealm.loadExist", - file.getAbsolutePath())); - - // Load the contents of the database file - if (log.isDebugEnabled()) - log.debug(sm.getString("memoryRealm.loadPath", - file.getAbsolutePath())); - Digester digester = getDigester(); + String pathName = getPathname(); + InputStream is = null; + try { - synchronized (digester) { - digester.push(this); - digester.parse(file); + is = ConfigFileLoader.getInputStream(pathName); + + // Load the contents of the database file + if (log.isDebugEnabled()) { + log.debug(sm.getString("memoryRealm.loadPath", pathName)); } - } catch (Exception e) { - throw new LifecycleException - (sm.getString("memoryRealm.readXml"), e); + + Digester digester = getDigester(); + try { + synchronized (digester) { + digester.push(this); + digester.parse(is); + } + } catch (Exception e) { + throw new LifecycleException + (sm.getString("memoryRealm.readXml"), e); + } finally { + digester.reset(); + } + + } catch (IOException ioe) { + throw new LifecycleException(sm.getString("memoryRealm.loadExist", + pathName), ioe); + } finally { - digester.reset(); + if (is != null) { + try { + is.close(); + } catch (IOException e) { + // ignore + } + } } super.startInternal(); --- java/org/apache/catalina/users/MemoryUserDatabase.java +++ java/org/apache/catalina/users/MemoryUserDatabase.java @@ -17,9 +17,9 @@ package org.apache.catalina.users; import java.io.File; -import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.HashMap; @@ -34,6 +34,7 @@ import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.digester.AbstractObjectCreationFactory; import org.apache.tomcat.util.digester.Digester; +import org.apache.tomcat.util.file.ConfigFileLoader; import org.apache.tomcat.util.res.StringManager; import org.xml.sax.Attributes; @@ -394,52 +395,44 @@ public class MemoryUserDatabase implements UserDatabase { groups.clear(); roles.clear(); - // Construct a reader for the XML input file (if it exists) - File file = new File(pathname); - if (!file.isAbsolute()) { - file = new File(System.getProperty(Globals.CATALINA_BASE_PROP), - pathname); - } - if (!file.exists()) { - log.error(sm.getString("memoryUserDatabase.fileNotFound", - file.getAbsolutePath())); - return; - } + String pathName = getPathname(); + InputStream is = null; - // Construct a digester to read the XML input file - Digester digester = new Digester(); - try { - digester.setFeature( - "http://apache.org/xml/features/allow-java-encodings", - true); - } catch (Exception e) { - log.warn(sm.getString("memoryUserDatabase.xmlFeatureEncoding"), e); - } - digester.addFactoryCreate - ("tomcat-users/group", - new MemoryGroupCreationFactory(this), true); - digester.addFactoryCreate - ("tomcat-users/role", - new MemoryRoleCreationFactory(this), true); - digester.addFactoryCreate - ("tomcat-users/user", - new MemoryUserCreationFactory(this), true); - - // Parse the XML input file to load this database - FileInputStream fis = null; try { - fis = new FileInputStream(file); - digester.parse(fis); + is = ConfigFileLoader.getInputStream(pathName); + + // Construct a digester to read the XML input file + Digester digester = new Digester(); + try { + digester.setFeature( + "http://apache.org/xml/features/allow-java-encodings", + true); + } catch (Exception e) { + log.warn(sm.getString("memoryUserDatabase.xmlFeatureEncoding"), e); + } + digester.addFactoryCreate + ("tomcat-users/group", + new MemoryGroupCreationFactory(this), true); + digester.addFactoryCreate + ("tomcat-users/role", + new MemoryRoleCreationFactory(this), true); + digester.addFactoryCreate + ("tomcat-users/user", + new MemoryUserCreationFactory(this), true); + + // Parse the XML input to load this database + digester.parse(is); + } catch (IOException ioe) { + log.error(sm.getString("memoryUserDatabase.fileNotFound", pathName)); } finally { - if (fis != null) { + if (is != null) { try { - fis.close(); + is.close(); } catch (IOException ioe) { // Ignore } } } - } } --- java/org/apache/naming/resources/ClasspathURLStreamHandler.java +++ java/org/apache/naming/resources/ClasspathURLStreamHandler.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 org.apache.naming.resources; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +import org.apache.tomcat.util.res.StringManager; + +public class ClasspathURLStreamHandler extends URLStreamHandler { + + private static final StringManager sm = + StringManager.getManager(Constants.Package); + + + @Override + protected URLConnection openConnection(URL u) throws IOException { + String path = u.getPath(); + + // Thread context class loader first + URL classpathUrl = Thread.currentThread().getContextClassLoader().getResource(path); + if (classpathUrl == null) { + // This class's class loader if no joy with the tccl + classpathUrl = ClasspathURLStreamHandler.class.getResource(path); + } + + if (classpathUrl == null) { + throw new FileNotFoundException(sm.getString("classpathUrlStreamHandler.notFound", u)); + } + + return classpathUrl.openConnection(); + } +} --- java/org/apache/naming/resources/DirContextURLStreamHandlerFactory.java +++ java/org/apache/naming/resources/DirContextURLStreamHandlerFactory.java @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF 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 org.apache.naming.resources; - -import java.net.URLStreamHandler; -import java.net.URLStreamHandlerFactory; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * Factory for Stream handlers to a JNDI directory context that also supports - * users specifying additional stream handler. - * - * @author Remy Maucherat - */ -public class DirContextURLStreamHandlerFactory - implements URLStreamHandlerFactory { - - // Singleton - private static DirContextURLStreamHandlerFactory instance = - new DirContextURLStreamHandlerFactory(); - - public static DirContextURLStreamHandlerFactory getInstance() { - return instance; - } - - public static void addUserFactory(URLStreamHandlerFactory factory) { - instance.userFactories.add(factory); - } - - - private List userFactories = - new CopyOnWriteArrayList(); - - private DirContextURLStreamHandlerFactory() { - // Hide the default constructor - } - - - /** - * Creates a new URLStreamHandler instance with the specified protocol. - * Will return null if the protocol is not jndi. - * - * @param protocol the protocol (must be "jndi" here) - * @return a URLStreamHandler for the jndi protocol, or null if the - * protocol is not JNDI - */ - @Override - public URLStreamHandler createURLStreamHandler(String protocol) { - if (protocol.equals("jndi")) { - return new DirContextURLStreamHandler(); - } else { - for (URLStreamHandlerFactory factory : userFactories) { - URLStreamHandler handler = - factory.createURLStreamHandler(protocol); - if (handler != null) { - return handler; - } - } - return null; - } - } - - -} --- java/org/apache/naming/resources/LocalStrings.properties +++ java/org/apache/naming/resources/LocalStrings.properties @@ -43,3 +43,4 @@ standardResources.exists=File base {0} does not exist standardResources.notStarted=Resources has not yet been started standardResources.null=Document base cannot be null standardResources.slash=Document base {0} must not end with a slash +classpathUrlStreamHandler.notFound=Unable to load the resource [{0}] using the thread context class loader or the current class's class loader --- java/org/apache/naming/resources/TomcatURLStreamHandlerFactory.java +++ java/org/apache/naming/resources/TomcatURLStreamHandlerFactory.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 org.apache.naming.resources; + +import java.net.URLStreamHandler; +import java.net.URLStreamHandlerFactory; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * Factory for Stream handlers to a JNDI directory context, + * or for Stream handlers to a classpath url, + * which also supports users specifying additional stream handler. + * + * @author Remy Maucherat + */ +public class TomcatURLStreamHandlerFactory + implements URLStreamHandlerFactory { + + // Singleton + private static TomcatURLStreamHandlerFactory instance = + new TomcatURLStreamHandlerFactory(); + + public static TomcatURLStreamHandlerFactory getInstance() { + return instance; + } + + public static void addUserFactory(URLStreamHandlerFactory factory) { + instance.userFactories.add(factory); + } + + + private List userFactories = + new CopyOnWriteArrayList(); + + private TomcatURLStreamHandlerFactory() { + // Hide the default constructor + } + + + /** + * Creates a new URLStreamHandler instance with the specified protocol. + * Will return null if the protocol is not jndi. + * + * @param protocol the protocol (must be "jndi" here) + * @return a URLStreamHandler for the jndi protocol, or null if the + * protocol is not JNDI + */ + @Override + public URLStreamHandler createURLStreamHandler(String protocol) { + if (protocol.equals("jndi")) { + return new DirContextURLStreamHandler(); + } else if (protocol.equals("classpath")) { + return new ClasspathURLStreamHandler(); + } else { + for (URLStreamHandlerFactory factory : userFactories) { + URLStreamHandler handler = + factory.createURLStreamHandler(protocol); + if (handler != null) { + return handler; + } + } + return null; + } + } + + +} --- java/org/apache/tomcat/util/file/ConfigFileLoader.java +++ java/org/apache/tomcat/util/file/ConfigFileLoader.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 org.apache.tomcat.util.file; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URL; + +/** + * This class is used to obtain {@link InputStream}s for configuration files + * from a given location String. This allows greater flexibility than these + * files having to be loaded directly from a file system. + */ +public class ConfigFileLoader { + + private static final URI CATALINA_BASE_URI; + + static { + File catalinaBase = new File(System.getProperty("catalina.base")); + CATALINA_BASE_URI = catalinaBase.toURI(); + } + + private ConfigFileLoader() { + // Utility class. Hide the default constructor. + } + + + /** + * Load the resource from the specified location. + * + * @param location The location for the resource of interest. The location + * may be a URL or a file path. Relative paths will be + * resolved against CATALINA_BASE. + * + * @return The InputStream for the given resource. The caller is responsible + * for closing this stream when it is no longer used. + * + * @throws IOException If an InputStream cannot be created using the + * provided location + */ + public static InputStream getInputStream(String location) throws IOException { + + // Absolute URIs will be left alone + // Relative files will be resolved relative to catalina base + // Absolute files will be converted to URIs + URI uri = CATALINA_BASE_URI.resolve(location); + URL url = uri.toURL(); + + return url.openConnection().getInputStream(); + } +} --- java/org/apache/tomcat/util/net/AbstractEndpoint.java +++ java/org/apache/tomcat/util/net/AbstractEndpoint.java @@ -16,7 +16,6 @@ */ package org.apache.tomcat.util.net; -import java.io.File; import java.io.OutputStreamWriter; import java.net.InetAddress; import java.net.InetSocketAddress; @@ -728,25 +727,6 @@ public abstract class AbstractEndpoint { } } - - public String adjustRelativePath(String path, String relativeTo) { - // Empty or null path can't point to anything useful. The assumption is - // that the value is deliberately empty / null so leave it that way. - if (path == null || path.length() == 0) { - return path; - } - String newPath = path; - File f = new File(newPath); - if ( !f.isAbsolute()) { - newPath = relativeTo + File.separator + newPath; - f = new File(newPath); - } - if (!f.exists()) { - getLog().warn("configured file:["+newPath+"] does not exist."); - } - return newPath; - } - protected abstract Log getLog(); // Flags to indicate optional feature support // Some of these are always hard-coded, some are hard-coded to false (i.e. @@ -833,8 +813,7 @@ public abstract class AbstractEndpoint { private String keystoreFile = System.getProperty("user.home")+"/.keystore"; public String getKeystoreFile() { return keystoreFile;} public void setKeystoreFile(String s ) { - keystoreFile = adjustRelativePath(s, - System.getProperty(Constants.CATALINA_BASE_PROP)); + keystoreFile = s; } private String keystorePass = null; @@ -874,8 +853,7 @@ public abstract class AbstractEndpoint { private String truststoreFile = System.getProperty("javax.net.ssl.trustStore"); public String getTruststoreFile() {return truststoreFile;} public void setTruststoreFile(String s) { - truststoreFile = adjustRelativePath(s, - System.getProperty(Constants.CATALINA_BASE_PROP)); + truststoreFile = s; } private String truststorePass = --- java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java +++ java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java @@ -17,8 +17,6 @@ package org.apache.tomcat.util.net.jsse; -import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -63,6 +61,7 @@ import javax.net.ssl.X509KeyManager; import org.apache.tomcat.util.compat.JreCompat; import org.apache.tomcat.util.compat.JreVendor; +import org.apache.tomcat.util.file.ConfigFileLoader; import org.apache.tomcat.util.net.AbstractEndpoint; import org.apache.tomcat.util.net.Constants; import org.apache.tomcat.util.net.SSLUtil; @@ -431,12 +430,7 @@ public class JSSESocketFactory implements ServerSocketFactory, SSLUtil { } if(!("PKCS11".equalsIgnoreCase(type) || "".equalsIgnoreCase(path))) { - File keyStoreFile = new File(path); - if (!keyStoreFile.isAbsolute()) { - keyStoreFile = new File(System.getProperty( - Constants.CATALINA_BASE_PROP), path); - } - istream = new FileInputStream(keyStoreFile); + istream = ConfigFileLoader.getInputStream(path); } char[] storePass = null; @@ -718,16 +712,11 @@ public class JSSESocketFactory implements ServerSocketFactory, SSLUtil { protected Collection getCRLs(String crlf) throws IOException, CRLException, CertificateException { - File crlFile = new File(crlf); - if( !crlFile.isAbsolute() ) { - crlFile = new File( - System.getProperty(Constants.CATALINA_BASE_PROP), crlf); - } Collection crls = null; InputStream is = null; try { CertificateFactory cf = CertificateFactory.getInstance("X.509"); - is = new FileInputStream(crlFile); + is = ConfigFileLoader.getInputStream(crlf); crls = cf.generateCRLs(is); } catch(IOException iex) { throw iex; --- test/org/apache/naming/resources/TestClasspathUrlStreamHandler.java +++ test/org/apache/naming/resources/TestClasspathUrlStreamHandler.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 org.apache.naming.resources; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Properties; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class TestClasspathUrlStreamHandler { + + @BeforeClass + public static void setup() { + URL.setURLStreamHandlerFactory(TomcatURLStreamHandlerFactory.getInstance()); + } + + @Test + public void testClasspathURL01() throws IOException { + URL u = new URL("classpath:/org/apache/naming/resources/LocalStrings.properties"); + InputStream is = u.openStream(); + Properties p = new Properties(); + p.load(is); + String msg = (String) p.get("resources.null"); + Assert.assertEquals("Document base cannot be null", msg); + } +} --- test/org/apache/naming/resources/TestDirContextURLStreamHandlerFactory.java +++ test/org/apache/naming/resources/TestDirContextURLStreamHandlerFactory.java @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF 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 org.apache.naming.resources; - -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLStreamHandler; -import java.net.URLStreamHandlerFactory; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -import org.junit.Test; - -public class TestDirContextURLStreamHandlerFactory { - - @Test - public void testUserSuppliedFactory() throws Exception { - - URL url = null; - - // Initially unknown - try { - url = new URL("foo://www.apache.org"); - } catch (MalformedURLException ignore) { - // Ignore - } - assertNull(url); - - // Set the factory - URL.setURLStreamHandlerFactory( - DirContextURLStreamHandlerFactory.getInstance()); - - // Still unknown - try { - url = new URL("foo://www.apache.org"); - } catch (MalformedURLException ignore) { - // Ignore - } - assertNull(url); - - // Register a user factory - DirContextURLStreamHandlerFactory.addUserFactory( - new FooURLStreamHandlerFactory()); - - // Now it works - try { - url = new URL("foo://www.apache.org"); - } catch (MalformedURLException ignore) { - // Ignore - } - assertNotNull(url); - } - - public static class FooURLStreamHandlerFactory - implements URLStreamHandlerFactory { - - @Override - public URLStreamHandler createURLStreamHandler(String protocol) { - if ("foo".equals(protocol)) { - // This is good enough for this test but not for actual use - return new DirContextURLStreamHandler(); - } else { - return null; - } - } - } -} --- test/org/apache/naming/resources/TestTomcatURLStreamHandlerFactory.java +++ test/org/apache/naming/resources/TestTomcatURLStreamHandlerFactory.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 org.apache.naming.resources; + +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLStreamHandler; +import java.net.URLStreamHandlerFactory; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import org.junit.Test; + +public class TestTomcatURLStreamHandlerFactory { + + @Test + public void testUserSuppliedFactory() throws Exception { + + URL url = null; + + // Initially unknown + try { + url = new URL("foo://www.apache.org"); + } catch (MalformedURLException ignore) { + // Ignore + } + assertNull(url); + + // Set the factory + URL.setURLStreamHandlerFactory( + TomcatURLStreamHandlerFactory.getInstance()); + + // Still unknown + try { + url = new URL("foo://www.apache.org"); + } catch (MalformedURLException ignore) { + // Ignore + } + assertNull(url); + + // Register a user factory + TomcatURLStreamHandlerFactory.addUserFactory( + new FooURLStreamHandlerFactory()); + + // Now it works + try { + url = new URL("foo://www.apache.org"); + } catch (MalformedURLException ignore) { + // Ignore + } + assertNotNull(url); + } + + public static class FooURLStreamHandlerFactory + implements URLStreamHandlerFactory { + + @Override + public URLStreamHandler createURLStreamHandler(String protocol) { + if ("foo".equals(protocol)) { + // This is good enough for this test but not for actual use + return new DirContextURLStreamHandler(); + } else { + return null; + } + } + } +} --- test/org/apache/tomcat/util/file/TestConfigFileLoader.java +++ test/org/apache/tomcat/util/file/TestConfigFileLoader.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 org.apache.tomcat.util.file; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +import org.apache.naming.resources.TomcatURLStreamHandlerFactory; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class TestConfigFileLoader { + + @BeforeClass + public static void setup() { + URL.setURLStreamHandlerFactory( + TomcatURLStreamHandlerFactory.getInstance()); + File buildDir = new File( + System.getProperty("tomcat.test.tomcatbuild", "output/build")); + System.setProperty("catalina.base", buildDir.getAbsolutePath()); + } + + @Test + public void test01() throws IOException { + doTest("classpath:org/apache/catalina/mbeans-descriptors.xml"); + } + + @Test(expected=FileNotFoundException.class) + public void test02() throws IOException { + doTest("classpath:org/apache/catalina/foo"); + } + + @Test + public void test03() throws IOException { + doTest("conf/server.xml"); + } + + @Test(expected=FileNotFoundException.class) + public void test04() throws IOException { + doTest("conf/unknown"); + } + + private void doTest(String path) throws IOException { + InputStream is = null; + try { + is = ConfigFileLoader.getInputStream(path); + Assert.assertNotNull(is); + } finally { + if (is != null) { + is.close(); + } + } + } +} --- webapps/docs/config/http.xml +++ webapps/docs/config/http.xml @@ -1017,7 +1017,8 @@

The certificate revocation list to be used to verify client certificates. If not defined, client certificates will not be checked - against a certificate revocation list.

+ against a certificate revocation list. The file may be specified using a + URL, an absolute path or a relative (to CATAINA_BASE) path.

@@ -1042,7 +1043,8 @@ the file ".keystore" in the operating system home directory of the user that is running Tomcat. If your keystoreType doesn't need a file use "" - (empty string) for this parameter.

+ (empty string) for this parameter. The file may be specified using a + URL, an absolute path or a relative (to CATAINA_BASE) path.

@@ -1136,7 +1138,8 @@

The trust store file to use to validate client certificates. The default is the value of the javax.net.ssl.trustStore system property. If neither this attribute nor the default system property is - set, no trust store will be configured.

+ set, no trust store will be configured. The file may be specified using a + URL, an absolute path or a relative (to CATAINA_BASE) path.

--- webapps/docs/config/realm.xml +++ webapps/docs/config/realm.xml @@ -811,8 +811,8 @@ -

Absolute or relative (to $CATALINA_BASE) pathname to the XML file - containing our user information. See below for details on the +

URL, absolute path or relative path (to $CATALINA_BASE) for the XML + file containing our user information. See below for details on the XML element format required. If no pathname is specified, the default value is conf/tomcat-users.xml.

--- webapps/docs/jndi-resources-howto.xml +++ webapps/docs/jndi-resources-howto.xml @@ -471,8 +471,9 @@ public class MyBean2 { pathname="conf/tomcat-users.xml" readonly="false" />]]> -

The pathname attribute can be absolute or relative. If - relative, it is relative to $CATALINA_BASE.

+

The pathname attribute can be a URL, an absolute path or a + relative path. If relative, it is relative to $CATALINA_BASE. +

The readonly attribute is optional and defaults to true if not supplied. If the XML is writeable then it will be