You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by cm...@apache.org on 2012/07/03 15:14:19 UTC

git commit: WICKET-4617 untangled ResourceFinder and ResourceStreamLocator, dropped IResourcePath, added ClassPathResourceFinder, removed classloading from ResourceStreamLocator

Updated Branches:
  refs/heads/master d699add00 -> 8fd628188


WICKET-4617 untangled ResourceFinder and ResourceStreamLocator, dropped IResourcePath, added ClassPathResourceFinder, removed classloading from ResourceStreamLocator

Squashed commit of the following:

commit 12ee50952a0e75c6cf22a607a902894611dc16ef
Author: Carl-Eric Menzel <cm...@wicketbuch.de>
Date:   Tue Jul 3 15:11:06 2012 +0200

    WICKET-4617 some cleanup

commit 3b7febb59db848c63740346259df3f07bc30541d
Merge: 5032891 d699add
Author: Carl-Eric Menzel <cm...@wicketbuch.de>
Date:   Tue Jul 3 14:21:24 2012 +0200

    Merge branch 'master' into sandbox/resourcefinder

    Conflicts:
    	wicket-core/src/test/java/org/apache/wicket/util/resource/PathTest.java

commit 5032891aca7d4e0f0b865e3ea46d0ca2697536a9
Author: Carl-Eric Menzel <cm...@wicketbuch.de>
Date:   Thu Jun 28 15:06:43 2012 +0200

    WICKET-4617 fix jmx resource settings

commit a10b711875a9dfa1e837315c4b141cd4ae3cc72e
Author: Carl-Eric Menzel <cm...@wicketbuch.de>
Date:   Thu Jun 28 10:13:03 2012 +0200

    WICKET-4617 fix test for jenkins

commit af8492c4716a6949654ea8e40b4227dfb062bf8f
Author: Carl-Eric Menzel <cm...@wicketbuch.de>
Date:   Wed Jun 27 23:47:19 2012 +0200

    WICKET-4617 added javadoc

commit bba8177b4525e77233a97f6c09bb4ef426d6dd96
Author: Carl-Eric Menzel <cm...@wicketbuch.de>
Date:   Wed Jun 27 19:21:06 2012 +0200

    WICKET-4617 complete tests

commit d11c4073745c9587eb467541d111da7b973d0c6b
Merge: 45db0cd ec7a022
Author: Carl-Eric Menzel <cm...@wicketbuch.de>
Date:   Wed Jun 27 18:40:58 2012 +0200

    Merge branch 'master' into sandbox/resourcefinder

    Conflicts:
    	wicket-core/src/test/java/org/apache/wicket/util/resource/ResourceStreamLocatorTest.java

commit 45db0cd5777215e12197d3fd78938aee48010ace
Author: Carl-Eric Menzel <cm...@wicketbuch.de>
Date:   Wed Jun 27 14:20:31 2012 +0200

    work in progress

commit 55303c08bd8e5025030236fd2921a7e826cc75d1
Author: Carl-Eric Menzel <cm...@wicketbuch.de>
Date:   Wed Jun 27 01:05:56 2012 +0200

    WICKET-4617 work in progress - does not compile yet


Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/8fd62818
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/8fd62818
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/8fd62818

Branch: refs/heads/master
Commit: 8fd628188b9fb92a8076508bb517ab0f95ba7fd0
Parents: d699add
Author: Carl-Eric Menzel <cm...@wicketbuch.de>
Authored: Tue Jul 3 15:12:49 2012 +0200
Committer: Carl-Eric Menzel <cm...@wicketbuch.de>
Committed: Tue Jul 3 15:12:49 2012 +0200

----------------------------------------------------------------------
 .../main/java/org/apache/wicket/Application.java   |   10 +-
 .../wicket/core/util/file/WebApplicationPath.java  |  101 ++++---------
 .../util/resource/ClassPathResourceFinder.java     |  114 +++++++++++++++
 .../resource/locator/IResourceStreamLocator.java   |    2 +-
 .../resource/locator/ResourceStreamLocator.java    |  109 +++++---------
 .../wicket/protocol/http/WebApplication.java       |   35 ++---
 .../apache/wicket/settings/IResourceSettings.java  |   56 ++++----
 .../wicket/settings/def/ResourceSettings.java      |   49 ++-----
 .../util/resource/ClassPathResourceFinderTest.java |   54 +++++++
 .../wicket/util/file/WebApplicationPathTest.java   |    5 +-
 .../org/apache/wicket/util/resource/PathTest.java  |    5 +-
 .../util/resource/ResourceStreamLocatorTest.java   |   11 +-
 .../org/apache/wicket/jmx/ResourceSettings.java    |   12 +-
 .../apache/wicket/jmx/ResourceSettingsMBean.java   |    2 +-
 .../org/apache/wicket/util/file/IResourcePath.java |   31 ----
 .../java/org/apache/wicket/util/file/Path.java     |  101 ++++----------
 .../org/apache/wicket/velocity/Initializer.java    |    6 +-
 17 files changed, 352 insertions(+), 351 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/8fd62818/wicket-core/src/main/java/org/apache/wicket/Application.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/Application.java b/wicket-core/src/main/java/org/apache/wicket/Application.java
index bf16fa9..98a7145 100644
--- a/wicket-core/src/main/java/org/apache/wicket/Application.java
+++ b/wicket-core/src/main/java/org/apache/wicket/Application.java
@@ -37,6 +37,7 @@ import org.apache.wicket.application.IComponentInstantiationListener;
 import org.apache.wicket.core.request.mapper.IMapperContext;
 import org.apache.wicket.core.util.lang.PropertyResolver;
 import org.apache.wicket.core.util.lang.WicketObjects;
+import org.apache.wicket.core.util.resource.ClassPathResourceFinder;
 import org.apache.wicket.event.IEvent;
 import org.apache.wicket.event.IEventSink;
 import org.apache.wicket.javascript.DefaultJavaScriptCompressor;
@@ -587,7 +588,8 @@ public abstract class Application implements UnboundListener, IEventSink
 	}
 
 	/**
-	 * Iterate initializers list, calling their {@link IInitializer#destroy(Application) destroy} methods.
+	 * Iterate initializers list, calling their {@link IInitializer#destroy(Application) destroy}
+	 * methods.
 	 */
 	private void destroyInitializers()
 	{
@@ -692,6 +694,8 @@ public abstract class Application implements UnboundListener, IEventSink
 		pageSettings.addComponentResolver(new WicketMessageTagHandler());
 		pageSettings.addComponentResolver(new WicketContainerResolver());
 
+		getResourceSettings().getResourceFinders().add(new ClassPathResourceFinder(""));
+
 		// Install button image resource factory
 		getResourceSettings().addResourceFactory("buttonFactory",
 			new DefaultButtonImageResourceFactory());
@@ -1322,7 +1326,7 @@ public abstract class Application implements UnboundListener, IEventSink
 	}
 
 	/**
-	 * 
+	 *
 	 */
 	private void checkSettingsAvailable()
 	{
@@ -1590,7 +1594,7 @@ public abstract class Application implements UnboundListener, IEventSink
 	}
 
 	/**
-	 * 
+	 *
 	 */
 	private static class DefaultRequestCycleProvider implements IRequestCycleProvider
 	{

http://git-wip-us.apache.org/repos/asf/wicket/blob/8fd62818/wicket-core/src/main/java/org/apache/wicket/core/util/file/WebApplicationPath.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/core/util/file/WebApplicationPath.java b/wicket-core/src/main/java/org/apache/wicket/core/util/file/WebApplicationPath.java
index 4394067..412a084 100644
--- a/wicket-core/src/main/java/org/apache/wicket/core/util/file/WebApplicationPath.java
+++ b/wicket-core/src/main/java/org/apache/wicket/core/util/file/WebApplicationPath.java
@@ -17,128 +17,91 @@
 package org.apache.wicket.core.util.file;
 
 import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
 
 import javax.servlet.ServletContext;
 
-import org.apache.wicket.util.file.Folder;
-import org.apache.wicket.util.file.Path;
-import org.apache.wicket.util.resource.IResourceStream;
 import org.apache.wicket.core.util.resource.UrlResourceStream;
-import org.apache.wicket.util.string.StringList;
+import org.apache.wicket.util.file.IResourceFinder;
+import org.apache.wicket.util.resource.IResourceStream;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 
 /**
- * Maintain a list of paths which might either be ordinary folders of the filesystem or relative
- * paths to the web application's servlet context.
- *
+ * An {@link IResourceFinder} that looks in a folder in the webapp context path. It will
+ * <em>not</em> load files inside WEB-INF.
+ * 
  * @author Johan Compagner
+ * @author Carl-Eric Menzel
  */
-public final class WebApplicationPath extends Path
+public final class WebApplicationPath implements IResourceFinder
 {
 	private final static Logger log = LoggerFactory.getLogger(WebApplicationPath.class);
 
 	private static final String WEB_INF = "WEB-INF/";
 
-	/** The list of urls in the path */
-	private final List<String> webappPaths = new ArrayList<String>();
-
 	/** The web apps servlet context */
 	private final ServletContext servletContext;
 
+	private final String path;
+
 	/**
 	 * Constructor
-	 *
+	 * 
 	 * @param servletContext
 	 *            The webapplication context where the resources must be loaded from
-	 */
-	public WebApplicationPath(final ServletContext servletContext)
-	{
-		this.servletContext = servletContext;
-
-		// adding root so servlet context resources are always checked
-		webappPaths.add("/");
-	}
-
-	/**
 	 * @param path
-	 *            add a path that is lookup through the servlet context
+	 *            The path inside the app context where to look.
 	 */
-	@Override
-	public void add(String path)
+	public WebApplicationPath(final ServletContext servletContext, String path)
 	{
-		final Folder folder = new Folder(path);
-		if (folder.exists())
+		this.servletContext = servletContext;
+		if (!path.startsWith("/"))
 		{
-			log.debug("Added path '{}' as a folder.", path);
-			super.add(folder);
+			path = "/" + path;
 		}
-		else
+		if (!path.endsWith("/"))
 		{
-			if (!path.startsWith("/"))
-			{
-				path = "/" + path;
-			}
-			if (!path.endsWith("/"))
-			{
-				path += "/";
-			}
-			log.debug("Added path '{}' as a web path.", path);
-			webappPaths.add(path);
+			path += "/";
 		}
+		this.path = path;
 	}
 
+
 	/**
-	 *
+	 * 
 	 * @see org.apache.wicket.util.file.IResourceFinder#find(Class, String)
 	 */
 	@Override
 	public IResourceStream find(final Class<?> clazz, final String pathname)
 	{
-		if (pathname == null)
-		{
-			return null;
-		}
-
-		IResourceStream resourceStream = super.find(clazz, pathname);
-
-		if (resourceStream == null && pathname.startsWith(WEB_INF) == false)
+		IResourceStream resourceStream = null;
+		if (pathname.startsWith(WEB_INF) == false)
 		{
-			for (String path : webappPaths)
+			try
 			{
-				try
+				final URL url = servletContext.getResource(path + pathname);
+				if (url != null)
 				{
-					final URL url = servletContext.getResource(path + pathname);
-					if (url != null)
-					{
-						resourceStream = new UrlResourceStream(url);
-						break;
-					}
-				}
-				catch (Exception ex)
-				{
-					// ignore, file couldn't be found
+					resourceStream = new UrlResourceStream(url);
 				}
 			}
+			catch (Exception ex)
+			{
+				// ignore, file couldn't be found
+			}
 		}
 
 		return resourceStream;
 	}
 
-	public List<String> getWebappPaths()
-	{
-		return webappPaths;
-	}
+
 	/**
 	 * @see java.lang.Object#toString()
 	 */
 	@Override
 	public String toString()
 	{
-		return "[folders = " + StringList.valueOf(getFolders()) + ", webapppaths: " +
-			StringList.valueOf(webappPaths) + "]";
+		return "[webapppath: " + path + "]";
 	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/8fd62818/wicket-core/src/main/java/org/apache/wicket/core/util/resource/ClassPathResourceFinder.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/core/util/resource/ClassPathResourceFinder.java b/wicket-core/src/main/java/org/apache/wicket/core/util/resource/ClassPathResourceFinder.java
new file mode 100644
index 0000000..fc4e029
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/core/util/resource/ClassPathResourceFinder.java
@@ -0,0 +1,114 @@
+/*
+ * 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.wicket.core.util.resource;
+
+import java.net.URL;
+
+import org.apache.wicket.util.file.IResourceFinder;
+import org.apache.wicket.util.lang.Args;
+import org.apache.wicket.util.resource.IResourceStream;
+import org.apache.wicket.util.string.Strings;
+
+/**
+ * An {@link IResourceFinder} that looks in a folder in the classpath.
+ * 
+ * @author Carl-Eric Menzel
+ */
+public class ClassPathResourceFinder implements IResourceFinder
+{
+	private final String prefix;
+
+	/**
+	 * @param prefix
+	 *            The path prefix. May be null or empty to look in the classpath root.
+	 */
+	public ClassPathResourceFinder(String prefix)
+	{
+		if (Strings.isEmpty(prefix))
+		{
+			this.prefix = "";
+		}
+		else if (prefix.endsWith("/"))
+		{
+			this.prefix = prefix;
+		}
+		else
+		{
+			this.prefix = prefix + "/";
+		}
+	}
+
+	@Override
+	public IResourceStream find(Class<?> clazz, String path)
+	{
+		Args.notEmpty(path, "path");
+		String fullPath = prefix + (path.startsWith("/") ? path.substring(1) : path);
+		IResourceStream resourceStream;
+		if (clazz != null)
+		{
+			resourceStream = getResourceStreamWithClassLoader(clazz.getClassLoader(), fullPath);
+			if (resourceStream != null)
+			{
+				return resourceStream;
+			}
+		}
+
+		// use context classloader when no specific classloader is set
+		// (package resources for instance)
+		resourceStream = getResourceStreamWithClassLoader(Thread.currentThread()
+			.getContextClassLoader(), fullPath);
+		if (resourceStream != null)
+		{
+			return resourceStream;
+		}
+
+		// use Wicket classloader when no specific classloader is set
+		resourceStream = getResourceStreamWithClassLoader(getClass().getClassLoader(), fullPath);
+		if (resourceStream != null)
+		{
+			return resourceStream;
+		}
+
+		return null;
+	}
+
+	private IResourceStream getResourceStreamWithClassLoader(ClassLoader classLoader, String path)
+	{
+		if (classLoader != null)
+		{
+			URL url = classLoader.getResource(path);
+			if (url != null)
+			{
+				return new UrlResourceStream(url);
+			}
+		}
+		return null;
+	}
+
+	@Override
+	public String toString()
+	{
+		if (Strings.isEmpty(prefix))
+		{
+			return "[classpath]";
+		}
+		else
+		{
+			return "[classpath: " + prefix + "]";
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/8fd62818/wicket-core/src/main/java/org/apache/wicket/core/util/resource/locator/IResourceStreamLocator.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/core/util/resource/locator/IResourceStreamLocator.java b/wicket-core/src/main/java/org/apache/wicket/core/util/resource/locator/IResourceStreamLocator.java
index 86fa41a..c0a34e3 100644
--- a/wicket-core/src/main/java/org/apache/wicket/core/util/resource/locator/IResourceStreamLocator.java
+++ b/wicket-core/src/main/java/org/apache/wicket/core/util/resource/locator/IResourceStreamLocator.java
@@ -22,7 +22,7 @@ import org.apache.wicket.util.resource.IResourceStream;
 
 
 /**
- * Interface for code that locates resources.
+ * Interface for code that locates resources, taking into account variations for locale and style.
  * 
  * @author Jonathan Locke
  */

http://git-wip-us.apache.org/repos/asf/wicket/blob/8fd62818/wicket-core/src/main/java/org/apache/wicket/core/util/resource/locator/ResourceStreamLocator.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/core/util/resource/locator/ResourceStreamLocator.java b/wicket-core/src/main/java/org/apache/wicket/core/util/resource/locator/ResourceStreamLocator.java
index b78cc67..e81a679 100644
--- a/wicket-core/src/main/java/org/apache/wicket/core/util/resource/locator/ResourceStreamLocator.java
+++ b/wicket-core/src/main/java/org/apache/wicket/core/util/resource/locator/ResourceStreamLocator.java
@@ -20,11 +20,15 @@ import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.List;
 import java.util.Locale;
 
 import org.apache.wicket.Application;
+import org.apache.wicket.core.util.file.WebApplicationPath;
 import org.apache.wicket.core.util.resource.UrlResourceStream;
+import org.apache.wicket.settings.IResourceSettings;
 import org.apache.wicket.util.file.IResourceFinder;
+import org.apache.wicket.util.file.Path;
 import org.apache.wicket.util.resource.IResourceStream;
 import org.apache.wicket.util.resource.ResourceUtils;
 import org.apache.wicket.util.resource.ResourceUtils.PathLocale;
@@ -55,6 +59,11 @@ import org.slf4j.LoggerFactory;
  * <li>&lt;language&gt;_&lt;country&gt;</li>
  * <li>&lt;language&gt;</li>
  * </ol>
+ * <p>
+ * Resources will be actually loaded by the {@link IResourceFinder}s defined in the resource
+ * settings. By default there are finders that look in the classpath and in the classpath in
+ * META-INF/resources. You can add more by adding {@link WebApplicationPath}s or {@link Path}s to
+ * {@link IResourceSettings#getResourceFinders()}.
  * 
  * @author Juergen Donnerstag
  * @author Jonathan Locke
@@ -67,24 +76,36 @@ public class ResourceStreamLocator implements IResourceStreamLocator
 	private static final Iterable<String> NO_EXTENSIONS = new ArrayList<String>(0);
 
 	/** If null, the application registered finder will be used */
-	private IResourceFinder finder;
+	private List<IResourceFinder> finders;
 
 	/**
 	 * Constructor
 	 */
 	public ResourceStreamLocator()
 	{
+		this((List<IResourceFinder>)null);
+	}
+
+	/**
+	 * Constructor
+	 * 
+	 * @param finders
+	 *            resource finders. These will be tried in the given order.
+	 */
+	public ResourceStreamLocator(final IResourceFinder... finders)
+	{
+		this(Arrays.asList(finders));
 	}
 
 	/**
 	 * Constructor
 	 * 
-	 * @param finder
-	 *            resource finder
+	 * @param finders
+	 *            resource finders. These will be tried in the given order.
 	 */
-	public ResourceStreamLocator(final IResourceFinder finder)
+	public ResourceStreamLocator(final List<IResourceFinder> finders)
 	{
-		this.finder = finder;
+		this.finders = finders;
 	}
 
 	/**
@@ -97,19 +118,21 @@ public class ResourceStreamLocator implements IResourceStreamLocator
 	{
 		// First try with the resource finder registered with the application
 		// (allows for markup reloading)
-		IResourceStream stream = locateByResourceFinder(clazz, path);
-		if (stream != null)
+		if (finders == null)
 		{
-			return stream;
+			finders = Application.get().getResourceSettings().getResourceFinders();
 		}
 
-		// Then search the resource on the classpath
-		stream = locateByClassLoader(clazz, path);
-		if (stream != null)
+		IResourceStream result;
+		for (IResourceFinder finder : finders)
 		{
-			return stream;
+			log.debug("Attempting to locate resource '{}' using finder'{}'", path, finder);
+			result = finder.find(clazz, path);
+			if (result != null)
+			{
+				return result;
+			}
 		}
-
 		return null;
 	}
 
@@ -151,42 +174,6 @@ public class ResourceStreamLocator implements IResourceStreamLocator
 		return null;
 	}
 
-	/**
-	 * Search the the resource my means of the various classloaders available
-	 * 
-	 * @param clazz
-	 * @param path
-	 * @return resource stream
-	 */
-	protected IResourceStream locateByClassLoader(final Class<?> clazz, final String path)
-	{
-		IResourceStream resourceStream = null;
-
-		if (clazz != null)
-		{
-			resourceStream = getResourceStream(clazz.getClassLoader(), path);
-			if (resourceStream != null)
-			{
-				return resourceStream;
-			}
-		}
-
-		// use context classloader when no specific classloader is set
-		// (package resources for instance)
-		resourceStream = getResourceStream(Thread.currentThread().getContextClassLoader(), path);
-		if (resourceStream != null)
-		{
-			return resourceStream;
-		}
-
-		// use Wicket classloader when no specific classloader is set
-		resourceStream = getResourceStream(getClass().getClassLoader(), path);
-		if (resourceStream != null)
-		{
-			return resourceStream;
-		}
-		return null;
-	}
 
 	/**
 	 * Get the resource
@@ -225,30 +212,6 @@ public class ResourceStreamLocator implements IResourceStreamLocator
 	}
 
 	/**
-	 * Search the resource by means of the application registered resource finder
-	 * 
-	 * @param clazz
-	 * @param path
-	 * @return resource stream
-	 */
-	protected IResourceStream locateByResourceFinder(final Class<?> clazz, final String path)
-	{
-		if (finder == null)
-		{
-			finder = Application.get().getResourceSettings().getResourceFinder();
-		}
-
-		// Log attempt
-		if (log.isDebugEnabled())
-		{
-			log.debug("Attempting to locate resource '" + path + "' on path " + finder);
-		}
-
-		// Try to find file resource on the path supplied
-		return finder.find(clazz, path);
-	}
-
-	/**
 	 * 
 	 * @see org.apache.wicket.core.util.resource.locator.IResourceStreamLocator#newResourceNameIterator(java.lang.String,
 	 *      java.util.Locale, java.lang.String, java.lang.String, java.lang.String, boolean)

http://git-wip-us.apache.org/repos/asf/wicket/blob/8fd62818/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java b/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
index 9880d5f..7a3892a 100644
--- a/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
+++ b/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebApplication.java
@@ -37,6 +37,7 @@ import org.apache.wicket.core.request.mapper.MountedMapper;
 import org.apache.wicket.core.request.mapper.PackageMapper;
 import org.apache.wicket.core.request.mapper.ResourceMapper;
 import org.apache.wicket.core.util.file.WebApplicationPath;
+import org.apache.wicket.core.util.resource.ClassPathResourceFinder;
 import org.apache.wicket.markup.MarkupType;
 import org.apache.wicket.markup.head.CssHeaderItem;
 import org.apache.wicket.markup.head.JavaScriptHeaderItem;
@@ -74,7 +75,7 @@ import org.apache.wicket.util.IProvider;
 import org.apache.wicket.util.crypt.CharEncoding;
 import org.apache.wicket.util.file.FileCleaner;
 import org.apache.wicket.util.file.IFileCleaner;
-import org.apache.wicket.util.file.IResourceFinder;
+import org.apache.wicket.util.file.Path;
 import org.apache.wicket.util.lang.Args;
 import org.apache.wicket.util.lang.PackageName;
 import org.apache.wicket.util.string.Strings;
@@ -129,6 +130,8 @@ public abstract class WebApplication extends Application
 	/** Log. */
 	private static final Logger log = LoggerFactory.getLogger(WebApplication.class);
 
+	public static final String META_INF_RESOURCES = "META-INF/resources";
+
 	private ServletContext servletContext;
 
 	private final AjaxRequestTargetListenerCollection ajaxRequestTargetListeners;
@@ -614,6 +617,11 @@ public abstract class WebApplication extends Application
 	{
 		super.internalInit();
 
+		getResourceSettings().getResourceFinders().add(
+			new WebApplicationPath(getServletContext(), ""));
+		getResourceSettings().getResourceFinders().add(
+			new ClassPathResourceFinder(META_INF_RESOURCES));
+
 		// Set default error pages for HTML markup
 		getApplicationSettings().setPageExpiredErrorPage(PageExpiredErrorPage.class);
 		getApplicationSettings().setInternalErrorPage(InternalErrorPage.class);
@@ -624,18 +632,17 @@ public abstract class WebApplication extends Application
 		getPageSettings().addComponentResolver(new AutoLabelResolver());
 		getPageSettings().addComponentResolver(new AutoLabelTextResolver());
 
-		// Set resource finder to web app path
-		getResourceSettings().setResourceFinder(getResourceFinder());
-
 		getResourceSettings().setFileCleaner(new FileCleaner());
 
-		// Add optional sourceFolder for resources.
-		String resourceFolder = getInitParameter("sourceFolder");
-		if (resourceFolder != null)
+		if (getConfigurationType() == RuntimeConfigurationType.DEVELOPMENT)
 		{
-			getResourceSettings().addResourceFolder(resourceFolder);
+			// Add optional sourceFolder for resources.
+			String resourceFolder = getInitParameter("sourceFolder");
+			if (resourceFolder != null)
+			{
+				getResourceSettings().getResourceFinders().add(new Path(resourceFolder));
+			}
 		}
-
 		setPageRendererProvider(new WebPageRendererProvider());
 		setSessionStoreProvider(new WebSessionStoreProvider());
 		setAjaxRequestTargetProvider(new DefaultAjaxRequestTargetProvider());
@@ -782,16 +789,6 @@ public abstract class WebApplication extends Application
 	}
 
 	/**
-	 * By default it return a WebApplicationPath
-	 * 
-	 * @return resource finder
-	 */
-	protected IResourceFinder getResourceFinder()
-	{
-		return new WebApplicationPath(getServletContext());
-	}
-
-	/**
 	 * Creates a new ajax request target used to control ajax responses
 	 * 
 	 * @param page

http://git-wip-us.apache.org/repos/asf/wicket/blob/8fd62818/wicket-core/src/main/java/org/apache/wicket/settings/IResourceSettings.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/settings/IResourceSettings.java b/wicket-core/src/main/java/org/apache/wicket/settings/IResourceSettings.java
index be9c864..c9edd31 100644
--- a/wicket-core/src/main/java/org/apache/wicket/settings/IResourceSettings.java
+++ b/wicket-core/src/main/java/org/apache/wicket/settings/IResourceSettings.java
@@ -21,6 +21,7 @@ import java.util.List;
 
 import org.apache.wicket.IResourceFactory;
 import org.apache.wicket.Localizer;
+import org.apache.wicket.core.util.resource.locator.IResourceStreamLocator;
 import org.apache.wicket.css.ICssCompressor;
 import org.apache.wicket.javascript.IJavaScriptCompressor;
 import org.apache.wicket.markup.head.PriorityFirstComparator;
@@ -29,13 +30,13 @@ import org.apache.wicket.markup.head.ResourceAggregator.RecordedHeaderItem;
 import org.apache.wicket.markup.html.IPackageResourceGuard;
 import org.apache.wicket.markup.html.PackageResourceGuard;
 import org.apache.wicket.model.IModel;
+import org.apache.wicket.protocol.http.WebApplication;
 import org.apache.wicket.request.resource.caching.IResourceCachingStrategy;
 import org.apache.wicket.resource.IPropertiesFactory;
 import org.apache.wicket.resource.IPropertiesFactoryContext;
 import org.apache.wicket.resource.loader.IStringResourceLoader;
 import org.apache.wicket.util.file.IFileCleaner;
 import org.apache.wicket.util.file.IResourceFinder;
-import org.apache.wicket.core.util.resource.locator.IResourceStreamLocator;
 import org.apache.wicket.util.time.Duration;
 import org.apache.wicket.util.watch.IModificationWatcher;
 
@@ -46,7 +47,7 @@ import org.apache.wicket.util.watch.IModificationWatcher;
  * <i>resourcePollFrequency </i> (defaults to no polling frequency) - Frequency at which resources
  * should be polled for changes.
  * <p>
- * <i>resourceFinder </i> (classpath) - Set this to alter the search path for resources.
+ * <i>resourceFinders</i> - Add/modify this to alter the search path for resources.
  * <p>
  * <i>useDefaultOnMissingResource </i> (defaults to true) - Set to true to return a default value if
  * available when a required string resource is not found. If set to false then the
@@ -92,16 +93,6 @@ public interface IResourceSettings extends IPropertiesFactoryContext
 	void addResourceFactory(final String name, final IResourceFactory resourceFactory);
 
 	/**
-	 * Convenience method that sets the resource search path to a single folder. use when searching
-	 * for resources. By default, the resources are located on the classpath. If you want to
-	 * configure other, additional, search paths, you can use this method
-	 * 
-	 * @param resourceFolder
-	 *            The resourceFolder to set
-	 */
-	void addResourceFolder(final String resourceFolder);
-
-	/**
 	 * Get the the default cache duration for resources.
 	 * <p/>
 	 * 
@@ -133,12 +124,15 @@ public interface IResourceSettings extends IPropertiesFactoryContext
 	IResourceFactory getResourceFactory(final String name);
 
 	/**
-	 * Gets the resource finder to use when searching for resources.
+	 * Gets the resource finders to use when searching for resources. By default, a finder that
+	 * looks in the classpath root is configured. {@link WebApplication} adds the classpath
+	 * directory META-INF/resources. To configure additional search paths or filesystem paths, add
+	 * to this list.
 	 * 
-	 * @return Returns the resourceFinder.
+	 * @return Returns the resourceFinders.
 	 * @see IResourceSettings#setResourceFinder(IResourceFinder)
 	 */
-	IResourceFinder getResourceFinder();
+	List<IResourceFinder> getResourceFinders();
 
 	/**
 	 * @return Returns the resourcePollFrequency.
@@ -199,14 +193,15 @@ public interface IResourceSettings extends IPropertiesFactoryContext
 	void setPropertiesFactory(IPropertiesFactory factory);
 
 	/**
-	 * Sets the finder to use when searching for resources. By default, the resources are located on
-	 * the classpath. If you want to configure other, additional, search paths, you can use this
-	 * method.
+	 * Sets the finders to use when searching for resources. By default, the resources are located
+	 * on the classpath. To add additional search paths, add to the list given by
+	 * {@link #getResourceFinders()}. Use this method if you want to completely exchange the list of
+	 * resource finders.
 	 * 
 	 * @param resourceFinder
 	 *            The resourceFinder to set
 	 */
-	void setResourceFinder(final IResourceFinder resourceFinder);
+	void setResourceFinders(final List<IResourceFinder> resourceFinder);
 
 	/**
 	 * Sets the resource polling frequency. This is the duration of time between checks of resource
@@ -385,22 +380,23 @@ public interface IResourceSettings extends IPropertiesFactoryContext
 	Comparator<? super RecordedHeaderItem> getHeaderItemComparator();
 
 	/**
-	 * A flag indicating whether static resources should have <tt>jsessionid</tt> encoded
-	 * in their url.
-	 *
-	 * @return {@code true} if the jsessionid should be encoded in the url for resources implementing
-	 * {@link org.apache.wicket.request.resource.caching.IStaticCacheableResource} when the cookies
-	 * are disabled and there is an active http session.
+	 * A flag indicating whether static resources should have <tt>jsessionid</tt> encoded in their
+	 * url.
+	 * 
+	 * @return {@code true} if the jsessionid should be encoded in the url for resources
+	 *         implementing
+	 *         {@link org.apache.wicket.request.resource.caching.IStaticCacheableResource} when the
+	 *         cookies are disabled and there is an active http session.
 	 */
 	boolean isEncodeJSessionId();
 
 	/**
-	 * Sets a flag indicating whether the jsessionid should be encoded in the url for resources implementing
-	 * {@link org.apache.wicket.request.resource.caching.IStaticCacheableResource} when the cookies are
-	 * disabled and there is an active http session.
-	 *
+	 * Sets a flag indicating whether the jsessionid should be encoded in the url for resources
+	 * implementing {@link org.apache.wicket.request.resource.caching.IStaticCacheableResource} when
+	 * the cookies are disabled and there is an active http session.
+	 * 
 	 * @param encodeJSessionId
-	 *      {@code true} when the jsessionid should be encoded, {@code false} - otherwise
+	 *            {@code true} when the jsessionid should be encoded, {@code false} - otherwise
 	 */
 	void setEncodeJSessionId(boolean encodeJSessionId);
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/8fd62818/wicket-core/src/main/java/org/apache/wicket/settings/def/ResourceSettings.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/settings/def/ResourceSettings.java b/wicket-core/src/main/java/org/apache/wicket/settings/def/ResourceSettings.java
index e2fbb3e..cc613a4 100644
--- a/wicket-core/src/main/java/org/apache/wicket/settings/def/ResourceSettings.java
+++ b/wicket-core/src/main/java/org/apache/wicket/settings/def/ResourceSettings.java
@@ -16,6 +16,7 @@
  */
 package org.apache.wicket.settings.def;
 
+import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
@@ -24,6 +25,9 @@ import org.apache.wicket.Application;
 import org.apache.wicket.Component;
 import org.apache.wicket.IResourceFactory;
 import org.apache.wicket.Localizer;
+import org.apache.wicket.core.util.resource.locator.IResourceStreamLocator;
+import org.apache.wicket.core.util.resource.locator.ResourceStreamLocator;
+import org.apache.wicket.core.util.resource.locator.caching.CachingResourceStreamLocator;
 import org.apache.wicket.css.ICssCompressor;
 import org.apache.wicket.javascript.IJavaScriptCompressor;
 import org.apache.wicket.markup.head.PriorityFirstComparator;
@@ -49,14 +53,9 @@ import org.apache.wicket.resource.loader.ValidatorStringResourceLoader;
 import org.apache.wicket.settings.IResourceSettings;
 import org.apache.wicket.util.file.IFileCleaner;
 import org.apache.wicket.util.file.IResourceFinder;
-import org.apache.wicket.util.file.IResourcePath;
-import org.apache.wicket.util.file.Path;
 import org.apache.wicket.util.lang.Args;
 import org.apache.wicket.util.lang.Generics;
 import org.apache.wicket.util.resource.IResourceStream;
-import org.apache.wicket.core.util.resource.locator.IResourceStreamLocator;
-import org.apache.wicket.core.util.resource.locator.ResourceStreamLocator;
-import org.apache.wicket.core.util.resource.locator.caching.CachingResourceStreamLocator;
 import org.apache.wicket.util.time.Duration;
 import org.apache.wicket.util.watch.IModificationWatcher;
 import org.apache.wicket.util.watch.ModificationWatcher;
@@ -80,14 +79,14 @@ public class ResourceSettings implements IResourceSettings
 	private final Map<String, IResourceFactory> nameToResourceFactory = Generics.newHashMap();
 
 	/** The package resource guard. */
-	private IPackageResourceGuard packageResourceGuard =
-			new SecurePackageResourceGuard(new SecurePackageResourceGuard.SimpleCache(100));
+	private IPackageResourceGuard packageResourceGuard = new SecurePackageResourceGuard(
+		new SecurePackageResourceGuard.SimpleCache(100));
 
 	/** The factory to be used for the property files */
 	private org.apache.wicket.resource.IPropertiesFactory propertiesFactory;
 
 	/** Filesystem Path to search for resources */
-	private IResourceFinder resourceFinder = new Path();
+	private List<IResourceFinder> resourceFinders = new ArrayList<IResourceFinder>();
 
 	/** Frequency at which files should be polled */
 	private Duration resourcePollFrequency = null;
@@ -201,27 +200,6 @@ public class ResourceSettings implements IResourceSettings
 	}
 
 	/**
-	 * @see org.apache.wicket.settings.IResourceSettings#addResourceFolder(java.lang.String)
-	 */
-	@Override
-	public void addResourceFolder(final String resourceFolder)
-	{
-		// Get resource finder
-		final IResourceFinder finder = getResourceFinder();
-
-		// Make sure it's a path
-		if (!(finder instanceof IResourcePath))
-		{
-			throw new IllegalArgumentException(
-				"To add a resource folder, the application's resource finder must be an instance of IResourcePath");
-		}
-
-		// Cast to resource path and add folder
-		final IResourcePath path = (IResourcePath)finder;
-		path.add(resourceFolder);
-	}
-
-	/**
 	 * @see org.apache.wicket.settings.IResourceSettings#getLocalizer()
 	 */
 	@Override
@@ -266,12 +244,12 @@ public class ResourceSettings implements IResourceSettings
 	}
 
 	/**
-	 * @see org.apache.wicket.settings.IResourceSettings#getResourceFinder()
+	 * @see org.apache.wicket.settings.IResourceSettings#getResourceFinders()
 	 */
 	@Override
-	public IResourceFinder getResourceFinder()
+	public List<IResourceFinder> getResourceFinders()
 	{
-		return resourceFinder;
+		return resourceFinders;
 	}
 
 	/**
@@ -293,7 +271,7 @@ public class ResourceSettings implements IResourceSettings
 		{
 			// Create compound resource locator using source path from
 			// application settings
-			resourceStreamLocator = new ResourceStreamLocator(getResourceFinder());
+			resourceStreamLocator = new ResourceStreamLocator(getResourceFinders());
 			resourceStreamLocator = new CachingResourceStreamLocator(resourceStreamLocator);
 		}
 		return resourceStreamLocator;
@@ -395,9 +373,10 @@ public class ResourceSettings implements IResourceSettings
 	 * @see org.apache.wicket.settings.IResourceSettings#setResourceFinder(org.apache.wicket.util.file.IResourceFinder)
 	 */
 	@Override
-	public void setResourceFinder(final IResourceFinder resourceFinder)
+	public void setResourceFinders(final List<IResourceFinder> resourceFinders)
 	{
-		this.resourceFinder = resourceFinder;
+		Args.notNull(resourceFinders, "resourceFinders");
+		this.resourceFinders = resourceFinders;
 
 		// Cause resource locator to get recreated
 		resourceStreamLocator = null;

http://git-wip-us.apache.org/repos/asf/wicket/blob/8fd62818/wicket-core/src/test/java/org/apache/wicket/core/util/resource/ClassPathResourceFinderTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/core/util/resource/ClassPathResourceFinderTest.java b/wicket-core/src/test/java/org/apache/wicket/core/util/resource/ClassPathResourceFinderTest.java
new file mode 100644
index 0000000..c3ac327
--- /dev/null
+++ b/wicket-core/src/test/java/org/apache/wicket/core/util/resource/ClassPathResourceFinderTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.wicket.core.util.resource;
+
+import static org.apache.wicket.util.resource.ResourceStreamLocatorTest.*;
+
+import java.io.File;
+
+import org.apache.wicket.WicketTestCase;
+import org.apache.wicket.protocol.http.WebApplication;
+import org.apache.wicket.util.resource.IResourceStream;
+import org.junit.Test;
+
+public class ClassPathResourceFinderTest extends WicketTestCase
+{
+	@Test
+	public void loadStartingFromClasspathRoot() throws Exception
+	{
+		ClassPathResourceFinder finder = new ClassPathResourceFinder("");
+		String filename = ClassPathResourceFinderTest.class.getName().replace('.',
+			File.separatorChar) +
+			".class";
+		IResourceStream rs = finder.find(WebApplication.class, filename);
+		assertNotNull(rs);
+		assertEquals(ClassPathResourceFinderTest.class.getSimpleName() + ".class", getFilename(rs));
+	}
+
+	@Test
+	public void loadStartingFromPrefix() throws Exception
+	{
+		ClassPathResourceFinder finder = new ClassPathResourceFinder(
+			ClassPathResourceFinderTest.class.getPackage()
+				.getName()
+				.replace('.', File.separatorChar));
+		String filename = ClassPathResourceFinderTest.class.getSimpleName() + ".class";
+		IResourceStream rs = finder.find(WebApplication.class, filename);
+		assertNotNull(rs);
+		assertEquals(ClassPathResourceFinderTest.class.getSimpleName() + ".class", getFilename(rs));
+	}
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/8fd62818/wicket-core/src/test/java/org/apache/wicket/util/file/WebApplicationPathTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/util/file/WebApplicationPathTest.java b/wicket-core/src/test/java/org/apache/wicket/util/file/WebApplicationPathTest.java
index f88d62e..fc71fe4 100644
--- a/wicket-core/src/test/java/org/apache/wicket/util/file/WebApplicationPathTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/util/file/WebApplicationPathTest.java
@@ -24,6 +24,7 @@ import org.apache.wicket.core.util.file.WebApplicationPath;
 import org.apache.wicket.util.resource.IResourceStream;
 import org.junit.Assert;
 import org.junit.Test;
+import org.mockito.Matchers;
 import org.mockito.Mockito;
 
 /**
@@ -37,9 +38,9 @@ public class WebApplicationPathTest extends Assert
 		URL webUrl = new URL("file://dummyFile");
 
 		ServletContext context = Mockito.mock(ServletContext.class);
-		Mockito.when(context.getResource(Mockito.any(String.class))).thenReturn(webUrl);
+		Mockito.when(context.getResource(Matchers.any(String.class))).thenReturn(webUrl);
 
-		WebApplicationPath path = new WebApplicationPath(context);
+		WebApplicationPath path = new WebApplicationPath(context, "");
 		IResourceStream resourceStream = path.find(String.class, "WEB-INF/web.xml");
 		assertNull(resourceStream);
 

http://git-wip-us.apache.org/repos/asf/wicket/blob/8fd62818/wicket-core/src/test/java/org/apache/wicket/util/resource/PathTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/util/resource/PathTest.java b/wicket-core/src/test/java/org/apache/wicket/util/resource/PathTest.java
index 9025853..52efe32 100644
--- a/wicket-core/src/test/java/org/apache/wicket/util/resource/PathTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/util/resource/PathTest.java
@@ -30,13 +30,14 @@ import org.junit.Test;
 
 public class PathTest extends WicketTestCase
 {
+
 	@Test
 	public void loadFromRootUsingSubpathInFilename() throws Exception
 	{
 		final String contents = PathTest.class.getName() + ": loaded from root";
 		final File file = createTempFile(contents);
 		final File root = findRoot(file);
-		final Path path = new Path(new Folder(root.getCanonicalPath()));
+		final Path path = new Path(root.getCanonicalPath());
 		IResourceStream rs = path.find(PathTest.class, file.getCanonicalPath());
 		assertNotNull(rs);
 		assertContents(contents, rs);
@@ -69,7 +70,7 @@ public class PathTest extends WicketTestCase
 		final String contents = PathTest.class.getName() + ": loaded from prefix";
 		final File file = createTempFile(contents);
 		final File parent = file.getParentFile();
-		final Path path = new Path(new Folder(parent.getCanonicalPath()));
+		final Path path = new Path(parent.getCanonicalPath());
 		IResourceStream rs = path.find(PathTest.class, file.getName());
 		assertNotNull(rs);
 		assertContents(contents, rs);

http://git-wip-us.apache.org/repos/asf/wicket/blob/8fd62818/wicket-core/src/test/java/org/apache/wicket/util/resource/ResourceStreamLocatorTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/util/resource/ResourceStreamLocatorTest.java b/wicket-core/src/test/java/org/apache/wicket/util/resource/ResourceStreamLocatorTest.java
index 3e9d2f3..08b1ca9 100644
--- a/wicket-core/src/test/java/org/apache/wicket/util/resource/ResourceStreamLocatorTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/util/resource/ResourceStreamLocatorTest.java
@@ -24,16 +24,17 @@ import java.net.URL;
 import java.util.Locale;
 
 import org.apache.wicket.WicketTestCase;
+import org.apache.wicket.core.util.resource.ClassPathResourceFinder;
 import org.apache.wicket.core.util.resource.UrlResourceStream;
 import org.apache.wicket.core.util.resource.locator.IResourceStreamLocator;
 import org.apache.wicket.core.util.resource.locator.ResourceStreamLocator;
-import org.apache.wicket.util.file.Path;
+import org.apache.wicket.util.file.IResourceFinder;
 import org.apache.wicket.util.string.Strings;
 import org.junit.Test;
 
 
 /**
- * ResourceStreamLocator test. Tests construction of resource names with 
+ * ResourceStreamLocator test. Tests construction of resource names with
  * 
  * @author Juergen Donnerstag
  */
@@ -63,7 +64,7 @@ public class ResourceStreamLocatorTest extends WicketTestCase
 	 * @param locale
 	 * @param extension
 	 */
-	public void createAndTestResource(Path sourcePath, String style, String variation,
+	public void createAndTestResource(IResourceFinder sourcePath, String style, String variation,
 		Locale locale, String extension)
 	{
 		IResourceStreamLocator locator = new ResourceStreamLocator(sourcePath);
@@ -77,7 +78,7 @@ public class ResourceStreamLocatorTest extends WicketTestCase
 	 * 
 	 * @param sourcePath
 	 */
-	public void executeMultiple(Path sourcePath)
+	public void executeMultiple(IResourceFinder sourcePath)
 	{
 		createAndTestResource(sourcePath, null, null, null, "");
 		createAndTestResource(sourcePath, "style", null, null, "_style");
@@ -114,7 +115,7 @@ public class ResourceStreamLocatorTest extends WicketTestCase
 	public void locateInClasspath()
 	{
 		// Execute without source path
-		executeMultiple(new Path());
+		executeMultiple(new ClassPathResourceFinder(""));
 
 		// Determine source path
 		IResourceStreamLocator locator = new ResourceStreamLocator();

http://git-wip-us.apache.org/repos/asf/wicket/blob/8fd62818/wicket-jmx/src/main/java/org/apache/wicket/jmx/ResourceSettings.java
----------------------------------------------------------------------
diff --git a/wicket-jmx/src/main/java/org/apache/wicket/jmx/ResourceSettings.java b/wicket-jmx/src/main/java/org/apache/wicket/jmx/ResourceSettings.java
index d38e274..970adc4 100644
--- a/wicket-jmx/src/main/java/org/apache/wicket/jmx/ResourceSettings.java
+++ b/wicket-jmx/src/main/java/org/apache/wicket/jmx/ResourceSettings.java
@@ -20,6 +20,7 @@ import java.util.List;
 
 import org.apache.wicket.ThreadContext;
 import org.apache.wicket.resource.loader.IStringResourceLoader;
+import org.apache.wicket.util.file.IResourceFinder;
 import org.apache.wicket.util.lang.Generics;
 import org.apache.wicket.util.time.Duration;
 
@@ -65,7 +66,7 @@ public class ResourceSettings implements ResourceSettingsMBean
 	public String getPropertiesFactory()
 	{
 		ThreadContext.setApplication(application);
-		
+
 		try
 		{
 			return Stringz.className(application.getResourceSettings().getPropertiesFactory());
@@ -79,9 +80,14 @@ public class ResourceSettings implements ResourceSettingsMBean
 	/**
 	 * {@inheritDoc}
 	 */
-	public String getResourceFinder()
+	public String getResourceFinders()
 	{
-		return Stringz.className(application.getResourceSettings().getResourceFinder());
+		StringBuilder builder = new StringBuilder();
+		for (IResourceFinder rf : application.getResourceSettings().getResourceFinders())
+		{
+			builder.append(Stringz.className(rf));
+		}
+		return builder.toString();
 	}
 
 	/**

http://git-wip-us.apache.org/repos/asf/wicket/blob/8fd62818/wicket-jmx/src/main/java/org/apache/wicket/jmx/ResourceSettingsMBean.java
----------------------------------------------------------------------
diff --git a/wicket-jmx/src/main/java/org/apache/wicket/jmx/ResourceSettingsMBean.java b/wicket-jmx/src/main/java/org/apache/wicket/jmx/ResourceSettingsMBean.java
index ecdd6bb..a7695fd 100644
--- a/wicket-jmx/src/main/java/org/apache/wicket/jmx/ResourceSettingsMBean.java
+++ b/wicket-jmx/src/main/java/org/apache/wicket/jmx/ResourceSettingsMBean.java
@@ -55,7 +55,7 @@ public interface ResourceSettingsMBean
 	 * @return Returns the resourceFinder.
 	 * @see IResourceSettings#setResourceFinder(IResourceFinder)
 	 */
-	String getResourceFinder();
+	String getResourceFinders();
 
 	/**
 	 * @return Returns the resourcePollFrequency.

http://git-wip-us.apache.org/repos/asf/wicket/blob/8fd62818/wicket-util/src/main/java/org/apache/wicket/util/file/IResourcePath.java
----------------------------------------------------------------------
diff --git a/wicket-util/src/main/java/org/apache/wicket/util/file/IResourcePath.java b/wicket-util/src/main/java/org/apache/wicket/util/file/IResourcePath.java
deleted file mode 100644
index 1ac2fcb..0000000
--- a/wicket-util/src/main/java/org/apache/wicket/util/file/IResourcePath.java
+++ /dev/null
@@ -1,31 +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.wicket.util.file;
-
-/**
- * Knows how to manage paths and folders, and how to find resources in them.
- * 
- * @author jcompagner
- */
-public interface IResourcePath extends IResourceFinder
-{
-	/**
-	 * @param folder
-	 *            Adds a folder to the path
-	 */
-	void add(String folder);
-}

http://git-wip-us.apache.org/repos/asf/wicket/blob/8fd62818/wicket-util/src/main/java/org/apache/wicket/util/file/Path.java
----------------------------------------------------------------------
diff --git a/wicket-util/src/main/java/org/apache/wicket/util/file/Path.java b/wicket-util/src/main/java/org/apache/wicket/util/file/Path.java
index 107acc6..7338e73 100644
--- a/wicket-util/src/main/java/org/apache/wicket/util/file/Path.java
+++ b/wicket-util/src/main/java/org/apache/wicket/util/file/Path.java
@@ -16,118 +16,64 @@
  */
 package org.apache.wicket.util.file;
 
-import java.util.ArrayList;
-import java.util.List;
+import java.io.IOException;
 
 import org.apache.wicket.util.resource.FileResourceStream;
 import org.apache.wicket.util.resource.IResourceStream;
-import org.apache.wicket.util.string.StringList;
 
 
 /**
- * Maintains a list of folders as a path.
+ * An {@link IResourceFinder} that looks for its resources in a filesystem path.
  * 
  * @author Jonathan Locke
+ * @author Carl-Eric Menzel
  */
-public class Path implements IResourcePath
+public class Path implements IResourceFinder
 {
-	/** The list of folders in the path */
-	private final List<Folder> folders = new ArrayList<Folder>();
-
-	/**
-	 * Constructor
-	 */
-	public Path()
-	{
-	}
+	private final Folder folder;
 
 	/**
 	 * Constructor
 	 * 
 	 * @param folder
-	 *            A single folder to add to the path
+	 *            The folder to look in
 	 */
-	public Path(final Folder folder)
+	public Path(final String folder)
 	{
-		add(folder);
+		this(new Folder(folder));
 	}
 
 	/**
 	 * Constructor
 	 * 
-	 * @param folders
-	 *            An array of folders to add to the path
-	 */
-	public Path(final Folder[] folders)
-	{
-		if (folders != null)
-		{
-			for (Folder folder : folders)
-			{
-				add(folder);
-			}
-		}
-	}
-
-	/**
 	 * @param folder
-	 *            Folder to add to path
+	 *            The folder to look in
 	 */
-	public void add(final Folder folder)
+	public Path(final Folder folder)
 	{
 		if (!folder.exists())
 		{
 			throw new IllegalArgumentException("Folder " + folder + " does not exist");
 		}
-
-		folders.add(folder);
-	}
-
-	/**
-	 * @param path
-	 *            Folder to add to path
-	 * @see org.apache.wicket.util.file.IResourcePath#add(java.lang.String)
-	 */
-	@Override
-	public void add(final String path)
-	{
-		add(new Folder(path));
+		this.folder = folder;
 	}
 
 	/**
-	 * 
 	 * @see org.apache.wicket.util.file.IResourceFinder#find(Class, String)
 	 */
 	@Override
 	public IResourceStream find(final Class<?> clazz, final String pathname)
 	{
-		for (Folder folder : folders)
-		{
-			final File file = new File(folder, pathname);
+		final File file = new File(folder, pathname);
 
-			if (file.exists())
-			{
-				return new FileResourceStream(file);
-			}
+		if (file.exists())
+		{
+			return new FileResourceStream(file);
+		}
+		else
+		{
+			return null;
 		}
-
-		return null;
-	}
-
-	/**
-	 * @return Returns the folders.
-	 */
-	public List<Folder> getFolders()
-	{
-		return folders;
-	}
-
-	/**
-	 * @return Number of folders on the path.
-	 */
-	public int size()
-	{
-		return folders.size();
 	}
 
 	/**
@@ -136,6 +82,13 @@ public class Path implements IResourcePath
 	@Override
 	public String toString()
 	{
-		return "[folders = " + StringList.valueOf(folders) + "]";
+		try
+		{
+			return "[Path: folder = " + folder.getCanonicalPath() + "]";
+		}
+		catch (IOException e)
+		{
+			return "[Path: exception while inspecting folder]";
+		}
 	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/8fd62818/wicket-velocity/src/main/java/org/apache/wicket/velocity/Initializer.java
----------------------------------------------------------------------
diff --git a/wicket-velocity/src/main/java/org/apache/wicket/velocity/Initializer.java b/wicket-velocity/src/main/java/org/apache/wicket/velocity/Initializer.java
index 9ccfe74..e6f2fe1 100644
--- a/wicket-velocity/src/main/java/org/apache/wicket/velocity/Initializer.java
+++ b/wicket-velocity/src/main/java/org/apache/wicket/velocity/Initializer.java
@@ -26,8 +26,8 @@ import org.apache.velocity.app.Velocity;
 import org.apache.wicket.Application;
 import org.apache.wicket.IInitializer;
 import org.apache.wicket.WicketRuntimeException;
-import org.apache.wicket.protocol.http.WebApplication;
 import org.apache.wicket.core.util.file.WebApplicationPath;
+import org.apache.wicket.protocol.http.WebApplication;
 import org.apache.wicket.util.io.IOUtils;
 import org.apache.wicket.util.resource.IResourceStream;
 import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
@@ -89,8 +89,8 @@ public class Initializer implements IInitializer
 
 			if (null != propertiesFolder)
 			{
-				WebApplicationPath webPath = new WebApplicationPath(servletContext);
-				webPath.add(propertiesFolder);
+				WebApplicationPath webPath = new WebApplicationPath(servletContext,
+					propertiesFolder);
 				IResourceStream stream = webPath.find(Initializer.class, velocityPropertiesFile);
 				InputStream is = null;
 				try