`svn merge -c1799289 ^/tiles/request/branches/TREQ_1_0_X`

TREQ-21: Convert IOException to FileNotFoundException on local protocols
- Separate between local and remote URL protocols, check on construction time whether the URL points to a local resource
- Always throw a FileNotFoundException when the URL points to a local resource and url.openConnection throws an IOException
- Added system property 'tiles.remoteProtocols' which can be used to specify additional remote protocols
- Added OSGi tests including PAX-EXAM dependencies

references:
 - pull request: https://github.com/apache/tiles-request/pull/2
 - ticket: https://issues.apache.org/jira/browse/TREQ-21

Contributed by Roland Hauser ( https://github.com/SourcePond )

This closes #2


git-svn-id: https://svn.apache.org/repos/asf/tiles/request/trunk@1799291 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/tiles-request-api/pom.xml b/tiles-request-api/pom.xml
index 2a32ef0..a917316 100644
--- a/tiles-request-api/pom.xml
+++ b/tiles-request-api/pom.xml
@@ -31,10 +31,12 @@
     <version>1.1-SNAPSHOT</version>
     <name>Tiles request - API</name>
     <description>API for the Tiles Request framework.</description>
+
     <dependencies>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
+            <version>1.7.25</version>
         </dependency>
         <dependency>
             <groupId>junit</groupId>
@@ -46,5 +48,53 @@
             <artifactId>easymockclassextension</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.exam</groupId>
+            <artifactId>pax-exam-container-native</artifactId>
+            <version>4.11.0</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.exam</groupId>
+            <artifactId>pax-exam-junit4</artifactId>
+            <version>4.11.0</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.exam</groupId>
+            <artifactId>pax-exam-link-mvn</artifactId>
+            <version>4.11.0</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.url</groupId>
+            <artifactId>pax-url-aether</artifactId>
+            <version>2.5.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.framework</artifactId>
+            <version>5.6.4</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-core</artifactId>
+            <version>1.2.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <version>1.2.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <version>6.0.0</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>
diff --git a/tiles-request-api/src/main/java/org/apache/tiles/request/locale/URLApplicationResource.java b/tiles-request-api/src/main/java/org/apache/tiles/request/locale/URLApplicationResource.java
index d9c4f1c..fe9572c 100644
--- a/tiles-request-api/src/main/java/org/apache/tiles/request/locale/URLApplicationResource.java
+++ b/tiles-request-api/src/main/java/org/apache/tiles/request/locale/URLApplicationResource.java
@@ -23,6 +23,7 @@
 
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.JarURLConnection;
@@ -30,11 +31,16 @@
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLConnection;
+import java.util.HashSet;
 import java.util.Locale;
+import java.util.Set;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static java.lang.System.getProperty;
+import static java.util.Collections.unmodifiableSet;
+
 /**
  * A {@link PostfixedApplicationResource} that can be accessed through a URL.
  *
@@ -42,12 +48,73 @@
  */
 
 public class URLApplicationResource extends PostfixedApplicationResource {
+    /**
+     * System parameter to specify additional remote protocols. If a url has a remote protocol, then any
+     * {@link IOException} will be thrown directly. If a url has a local protocol, then any {@link IOException}
+     * will be caught and transformed into a {@link FileNotFoundException}.
+     */
+    static final String REMOTE_PROTOCOLS_PROPERTY = "tiles.remoteProtocols";
     private static final Logger LOG = LoggerFactory.getLogger(URLApplicationResource.class);
+    private static final Set<String> REMOTE_PROTOCOLS;
+
+    static {
+        REMOTE_PROTOCOLS = initRemoteProtocols();
+    }
+
+    /**
+     * Creates an unmodifiable set of <em>remote</em> protocols which are used in {@link URL} objects, see {@link URL#getProtocol()}.
+     * A url with a remote protocol establishes a network connection when its {@link URL#openConnection()} is being called.
+     * The set will always contain the built-in remote protocols below:
+     * <ul>
+     *  <li><a href="http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/sun/net/www/protocol/ftp">ftp</a></li>
+     *  <li><a href="http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/sun/net/www/protocol/http">http</a></li>
+     *  <li><a href="http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/sun/net/www/protocol/https">https</a></li>
+     *  <li><a href="http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/sun/net/www/protocol/mailto">mailto</a></li>
+     *  <li><a href="http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/sun/net/www/protocol/netdoc">netdoc</a></li>
+     * </ul>
+     * It's possible, that your environment provides additional remote protocols because of following reasons:
+     * <ul>
+     *     <li>your application server adds more remote protocols, see its documentation for further details.</li>
+     *     <li>your application supplies custom remote protocols trough its own {@link java.net.URLStreamHandlerFactory}
+     *     (see following excellent <a href="https://stackoverflow.com/questions/26363573/registering-and-using-a-custom-java-net-url-protocol">explanation</a>
+     *     for getting an idea how to do this)</li>
+     * </ul>
+     * If you need to use such extra remote protocols in Tiles, you may enhance the set via system property {@code tiles.remoteProtocols}. Suppose
+     * you need to add your custom remote protocols "foo" and "bar". To do so, add following parameter to the command line (use ";" as separator):
+     * <pre>
+     *     -Dtiles.remoteProtocols=foo;bar
+     * </pre>
+     * The resulting set will then contain the built-in protocols plus "foo" and "bar".
+     *
+     * @return Unmodifiable set of remote protocols, never {@code null}
+     */
+    static Set<String> initRemoteProtocols() {
+        Set<String> remoteProtocols = new HashSet<String>();
+        remoteProtocols.add("ftp");
+        remoteProtocols.add("http");
+        remoteProtocols.add("https");
+        remoteProtocols.add("mailto");
+        remoteProtocols.add("netdoc");
+
+        String protocolsProp = getProperty(REMOTE_PROTOCOLS_PROPERTY);
+        if (protocolsProp != null) {
+            for (String protocol : protocolsProp.split(";")) {
+                remoteProtocols.add(protocol.trim());
+            }
+        }
+        return unmodifiableSet(remoteProtocols);
+    }
+
+    private static boolean isLocal(URL url) {
+        return !REMOTE_PROTOCOLS.contains(url.getProtocol());
+    }
 
     /** the URL where the contents can be found. */
-    private URL url;
+    private final URL url;
     /** if the URL matches a file, this is the file. */
     private File file;
+    /** if the URL points to a local resource */
+    private final boolean local;
 
     /**
      * Creates a URLApplicationResource for the specified path that can be accessed through the specified URL.
@@ -61,6 +128,7 @@
         if ("file".equals(url.getProtocol())) {
             file = getFile(url);
         }
+        local = isLocal(url);
     }
 
     /**
@@ -76,24 +144,41 @@
         if ("file".equals(url.getProtocol())) {
             file = getFile(url);
         }
+        local = isLocal(url);
+    }
+
+    private URLConnection openConnection() throws IOException {
+        try {
+            return url.openConnection();
+        } catch (IOException e) {
+            // If the url points to a local resource but it cannot be
+            // opened, then the resource actually does not exist. In this
+            // case throw a FileNotFoundException
+            if (local) {
+                FileNotFoundException fne = new FileNotFoundException(url.toString());
+                fne.initCause(e);
+                throw fne;
+            }
+            throw e;
+        }
     }
 
     private static File getFile(URL url) {
-    	try {
-			return new File(new URI(url.toExternalForm()).getSchemeSpecificPart());
-		} catch (URISyntaxException e) {
-			LOG.debug("Cannot translate URL to file name, expect a performance impact", e);
-			return null;
-		}
+        try {
+            return new File(new URI(url.toExternalForm()).getSchemeSpecificPart());
+        } catch (URISyntaxException e) {
+            LOG.debug("Cannot translate URL to file name, expect a performance impact", e);
+            return null;
+        }
     }
-    
+
     /** {@inheritDoc} */
     @Override
     public InputStream getInputStream() throws IOException {
         if (file != null) {
             return new FileInputStream(file);
         } else {
-            return url.openConnection().getInputStream();
+            return openConnection().getInputStream();
         }
     }
 
@@ -103,7 +188,7 @@
         if (file != null) {
             return file.lastModified();
         } else {
-            URLConnection connection = url.openConnection();
+            URLConnection connection = openConnection();
             if (connection instanceof JarURLConnection) {
                 return ((JarURLConnection) connection).getJarEntry().getTime();
             } else {
diff --git a/tiles-request-api/src/test/java/org/apache/tiles/request/locale/URLApplicationResourceTest.java b/tiles-request-api/src/test/java/org/apache/tiles/request/locale/URLApplicationResourceTest.java
index bb76ee8..d9be5bc 100644
--- a/tiles-request-api/src/test/java/org/apache/tiles/request/locale/URLApplicationResourceTest.java
+++ b/tiles-request-api/src/test/java/org/apache/tiles/request/locale/URLApplicationResourceTest.java
@@ -20,21 +20,33 @@
  */
 
 package org.apache.tiles.request.locale;
+
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
+import java.lang.reflect.Field;
 import java.net.MalformedURLException;
 import java.net.URISyntaxException;
 import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+import java.net.URLStreamHandlerFactory;
 import java.util.Locale;
 
+import org.junit.After;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
+import static java.lang.System.setProperty;
+import static java.lang.reflect.Modifier.FINAL;
+import static org.apache.tiles.request.locale.URLApplicationResource.REMOTE_PROTOCOLS_PROPERTY;
+import static org.apache.tiles.request.locale.URLApplicationResource.initRemoteProtocols;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 /**
  * Tests URLApplicationResource.
  *
@@ -42,33 +54,44 @@
  */
 public class URLApplicationResourceTest {
 
-    private class TestApplicationResource extends URLApplicationResource {
-        public TestApplicationResource(String localePath, URL url) throws URISyntaxException {
-            super(localePath, url);
-        }
+    private static final String EXPECTED_MESSAGE = "aMessage";
 
-        public TestApplicationResource(String path, Locale locale, URL url) throws MalformedURLException, URISyntaxException {
-            super(path, locale, url);
-        }
+    private static class TestUrlStreamHandler extends URLStreamHandler {
 
         @Override
-        protected URL getURL(){
-            return super.getURL();
+        protected URLConnection openConnection(final URL u) throws IOException {
+            throw new IOException(EXPECTED_MESSAGE);
         }
+    }
+
+    private static class TestURLStreamHandlerFactory implements URLStreamHandlerFactory {
 
         @Override
-        protected File getFile(){
-            return super.getFile();
+        public URLStreamHandler createURLStreamHandler(final String protocol) {
+            if ("test1".equals(protocol) || "test2".equals(protocol)) {
+                return new TestUrlStreamHandler();
+            }
+            return null;
         }
-    };
+    }
+
+    @BeforeClass
+    public static void setURLStreamHandlerFactory() {
+        URL.setURLStreamHandlerFactory(new TestURLStreamHandlerFactory());
+    }
+
+    @After
+    public void tearDown() {
+        setProperty(REMOTE_PROTOCOLS_PROPERTY, "");
+    }
 
     /**
      * Test getLocalePath(String path, Locale locale).
-     * @throws URISyntaxException 
+     * @throws URISyntaxException
      */
     @Test
     public void testGetLocalePath() throws MalformedURLException, URISyntaxException {
-        TestApplicationResource resource = new TestApplicationResource("/my test/path_fr.html", new URL("file:///"));
+        URLApplicationResource resource = new URLApplicationResource("/my test/path_fr.html", new URL("file:///"));
         assertEquals("/my test/path.html", resource.getLocalePath(null));
         assertEquals("/my test/path.html", resource.getLocalePath(Locale.ROOT));
         assertEquals("/my test/path_it.html", resource.getLocalePath(Locale.ITALIAN));
@@ -80,61 +103,61 @@
 
     @Test
     public void testBuildFromString() throws MalformedURLException, URISyntaxException {
-        TestApplicationResource resource = new TestApplicationResource("/my test/path_en_GB_scotland.html", new URL("file:///"));
+        URLApplicationResource resource = new URLApplicationResource("/my test/path_en_GB_scotland.html", new URL("file:///"));
         assertEquals("/my test/path_en_GB_scotland.html", resource.getLocalePath());
         assertEquals("/my test/path.html", resource.getPath());
         assertEquals("file:/", resource.getURL().toString());
         assertEquals(File.separator, resource.getFile().toString());
         assertEquals(new Locale("en", "GB", "scotland"), resource.getLocale());
-        resource = new TestApplicationResource("/my test/path_it_IT.html", new URL("file:///"));
+        resource = new URLApplicationResource("/my test/path_it_IT.html", new URL("file:///"));
         assertEquals("/my test/path_it_IT.html", resource.getLocalePath());
         assertEquals("/my test/path.html", resource.getPath());
         assertEquals("file:/", resource.getURL().toString());
         assertEquals(File.separator, resource.getFile().toString());
         assertEquals(Locale.ITALY, resource.getLocale());
-        resource = new TestApplicationResource("/my test/path_it.html", new URL("file:///"));
+        resource = new URLApplicationResource("/my test/path_it.html", new URL("file:///"));
         assertEquals("/my test/path_it.html", resource.getLocalePath());
         assertEquals("/my test/path.html", resource.getPath());
         assertEquals("file:/", resource.getURL().toString());
         assertEquals(File.separator, resource.getFile().toString());
         assertEquals(Locale.ITALIAN, resource.getLocale());
-        resource = new TestApplicationResource("/my test/path.html", new URL("file:///"));
+        resource = new URLApplicationResource("/my test/path.html", new URL("file:///"));
         assertEquals("/my test/path.html", resource.getLocalePath());
         assertEquals("/my test/path.html", resource.getPath());
         assertEquals("file:/", resource.getURL().toString());
         assertEquals(File.separator, resource.getFile().toString());
         assertEquals(Locale.ROOT, resource.getLocale());
-        resource = new TestApplicationResource("/my test/path_zz.html", new URL("file:///"));
+        resource = new URLApplicationResource("/my test/path_zz.html", new URL("file:///"));
         assertEquals("/my test/path_zz.html", resource.getLocalePath());
         assertEquals("/my test/path_zz.html", resource.getPath());
         assertEquals("file:/", resource.getURL().toString());
         assertEquals(File.separator, resource.getFile().toString());
         assertEquals(Locale.ROOT, resource.getLocale());
-        resource = new TestApplicationResource("/my test/path_en_ZZ.html", new URL("file:///"));
+        resource = new URLApplicationResource("/my test/path_en_ZZ.html", new URL("file:///"));
         assertEquals("/my test/path_en.html", resource.getLocalePath());
         assertEquals("/my test/path.html", resource.getPath());
         assertEquals("file:/", resource.getURL().toString());
         assertEquals(File.separator, resource.getFile().toString());
         assertEquals(new Locale("en"), resource.getLocale());
-        resource = new TestApplicationResource("/my test/path_tiles.html", new URL("file:///"));
+        resource = new URLApplicationResource("/my test/path_tiles.html", new URL("file:///"));
         assertEquals("/my test/path_tiles.html", resource.getLocalePath());
         assertEquals("/my test/path_tiles.html", resource.getPath());
         assertEquals("file:/", resource.getURL().toString());
         assertEquals(File.separator, resource.getFile().toString());
         assertEquals(Locale.ROOT, resource.getLocale());
-        resource = new TestApplicationResource("/my test/path_longwordthatbreaksISO639.html", new URL("file:///"));
+        resource = new URLApplicationResource("/my test/path_longwordthatbreaksISO639.html", new URL("file:///"));
         assertEquals("/my test/path_longwordthatbreaksISO639.html", resource.getLocalePath());
         assertEquals("/my test/path_longwordthatbreaksISO639.html", resource.getPath());
         assertEquals("file:/", resource.getURL().toString());
         assertEquals(File.separator, resource.getFile().toString());
         assertEquals(Locale.ROOT, resource.getLocale());
-        resource = new TestApplicationResource("/my test/path_en_tiles.html", new URL("file:///"));
+        resource = new URLApplicationResource("/my test/path_en_tiles.html", new URL("file:///"));
         assertEquals("/my test/path_en.html", resource.getLocalePath());
         assertEquals("/my test/path.html", resource.getPath());
         assertEquals("file:/", resource.getURL().toString());
         assertEquals(File.separator, resource.getFile().toString());
         assertEquals(new Locale("en"), resource.getLocale());
-        resource = new TestApplicationResource("/my test/path_en_longwordthatbreaksISO3166.html", new URL("file:///"));
+        resource = new URLApplicationResource("/my test/path_en_longwordthatbreaksISO3166.html", new URL("file:///"));
         assertEquals("/my test/path_en.html", resource.getLocalePath());
         assertEquals("/my test/path.html", resource.getPath());
         assertEquals("file:/", resource.getURL().toString());
@@ -144,25 +167,25 @@
 
     @Test
     public void testBuildFromStringAndLocale() throws MalformedURLException, URISyntaxException {
-        TestApplicationResource resource = new TestApplicationResource("/my test/path.html", new Locale("en", "GB", "scotland"), new URL("file:///"));
+        URLApplicationResource resource = new URLApplicationResource("/my test/path.html", new Locale("en", "GB", "scotland"), new URL("file:///"));
         assertEquals("/my test/path_en_GB_scotland.html", resource.getLocalePath());
         assertEquals("/my test/path.html", resource.getPath());
         assertEquals(new Locale("en", "GB", "scotland"), resource.getLocale());
         assertEquals("file:/", resource.getURL().toString());
         assertEquals(File.separator, resource.getFile().toString());
-        resource = new TestApplicationResource("/my test/path.html", Locale.ITALY, new URL("file:///"));
+        resource = new URLApplicationResource("/my test/path.html", Locale.ITALY, new URL("file:///"));
         assertEquals("/my test/path_it_IT.html", resource.getLocalePath());
         assertEquals("/my test/path.html", resource.getPath());
         assertEquals(Locale.ITALY, resource.getLocale());
         assertEquals("file:/", resource.getURL().toString());
         assertEquals(File.separator, resource.getFile().toString());
-        resource = new TestApplicationResource("/my test/path.html", Locale.ITALIAN, new URL("file:///"));
+        resource = new URLApplicationResource("/my test/path.html", Locale.ITALIAN, new URL("file:///"));
         assertEquals("/my test/path_it.html", resource.getLocalePath());
         assertEquals("/my test/path.html", resource.getPath());
         assertEquals(Locale.ITALIAN, resource.getLocale());
         assertEquals("file:/", resource.getURL().toString());
         assertEquals(File.separator, resource.getFile().toString());
-        resource = new TestApplicationResource("/my test/path.html", Locale.ROOT, new URL("file:///"));
+        resource = new URLApplicationResource("/my test/path.html", Locale.ROOT, new URL("file:///"));
         assertEquals("/my test/path.html", resource.getLocalePath());
         assertEquals("/my test/path.html", resource.getPath());
         assertEquals(Locale.ROOT, resource.getLocale());
@@ -201,4 +224,32 @@
     	assertNotNull(is);
     	is.close();
     }
+
+    @Test(expected = FileNotFoundException.class)
+    public void testLocalProtocol() throws IOException {
+        URL url = new URL("test1://foo/bar.txt");
+        URLApplicationResource resource = new URLApplicationResource("org/apache/tiles/request/test/locale/resource.txt", url);
+        resource.getInputStream();
+    }
+
+    @Test
+    public void testAdditionalRemoteProtocolViaSystemProperties() throws Exception {
+        setProperty(REMOTE_PROTOCOLS_PROPERTY, "test1;test2");
+        Field f = URLApplicationResource.class.getDeclaredField("REMOTE_PROTOCOLS");
+        Field m = Field.class.getDeclaredField("modifiers");
+        m.setAccessible(true);
+        m.setInt(f, f.getModifiers() & ~FINAL);
+        f.setAccessible(true);
+        f.set(URLApplicationResource.class, initRemoteProtocols());
+
+        URL url = new URL("test1://foo/bar.txt");
+        URLApplicationResource resource = new URLApplicationResource("org/apache/tiles/request/test/locale/resource.txt", url);
+        try {
+            resource.getInputStream();
+        } catch (FileNotFoundException e) {
+            fail("FileNotFoundException not allowed here");
+        } catch (IOException e) {
+            assertEquals(EXPECTED_MESSAGE, e.getMessage());
+        }
+    }
 }
diff --git a/tiles-request-api/src/test/java/org/apache/tiles/request/osgi/URLBundleApplicationResourceTest.java b/tiles-request-api/src/test/java/org/apache/tiles/request/osgi/URLBundleApplicationResourceTest.java
new file mode 100644
index 0000000..8ff797c
--- /dev/null
+++ b/tiles-request-api/src/test/java/org/apache/tiles/request/osgi/URLBundleApplicationResourceTest.java
@@ -0,0 +1,71 @@
+/*
+ * $Id$
+ *
+ * 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.tiles.request.osgi;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URL;
+
+import org.apache.tiles.request.locale.URLApplicationResource;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+
+import static org.junit.Assert.fail;
+import static org.ops4j.pax.exam.CoreOptions.bootDelegationPackage;
+import static org.ops4j.pax.exam.CoreOptions.frameworkProperty;
+import static org.ops4j.pax.exam.CoreOptions.junitBundles;
+
+
+/**
+ * Tests OSGi behaviour of URLApplicationResource.
+ *
+ * @version $Rev$ $Date$
+ */
+@RunWith(PaxExam.class)
+public class URLBundleApplicationResourceTest {
+
+    @Configuration
+    public Option[] configuration() throws IOException {
+        return new Option[]{
+                junitBundles(),
+                frameworkProperty("org.osgi.framework.bundle.parent").value("app"),
+                bootDelegationPackage("org.apache.tiles.request.locale"),
+        };
+    }
+
+    @Test(expected = FileNotFoundException.class)
+    public void testGetLastModified() throws Exception {
+        URL url = new URL(getClass().getResource("/org/apache/tiles/request/test/locale/resource.txt"), "notExisting");
+        URLApplicationResource resource = new URLApplicationResource("/my test/path_fr.html", url);
+        resource.getLastModified();
+    }
+
+    @Test(expected = FileNotFoundException.class)
+    public void testGetInputStream() throws IOException {
+        URL url = new URL(getClass().getResource("/org/apache/tiles/request/test/locale/resource.txt"), "notExisting");
+        URLApplicationResource resource = new URLApplicationResource("org/apache/tiles/request/test/locale/resource.txt", url);
+        resource.getInputStream();
+    }
+}