1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.myfaces.view.facelets.util;
20
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.net.MalformedURLException;
25 import java.net.URL;
26 import java.net.URLConnection;
27 import java.net.URLStreamHandler;
28 import java.util.logging.Level;
29 import java.util.logging.Logger;
30
31 import javax.faces.context.ExternalContext;
32 import javax.faces.context.FacesContext;
33 import javax.servlet.ServletContext;
34
35 /**
36 * @author Roland Huss
37 *
38 */
39 public final class Resource
40 {
41
42 //protected final static Logger log = Logger.getLogger("facelets.factory");
43 protected final static Logger log = Logger.getLogger(Resource.class.getName());
44
45 /**
46 * Get an URL of an internal resource. First, {@link javax.faces.context.ExternalContext#getResource(String)} is
47 * checked for an non-null URL return value. In the case of a null return value (as it is the case for Weblogic 8.1
48 * for a packed war), a URL with a special URL handler is constructed, which can be used for <em>opening</em> a
49 * serlvet resource later. Internally, this special URL handler will call
50 * {@link ServletContext#getResourceAsStream(String)} when an inputstream is requested. This works even on Weblogic
51 * 8.1
52 *
53 * @param ctx
54 * the faces context from which to retrieve the resource
55 * @param path
56 * an URL path
57 *
58 * @return an url representing the URL and on which getInputStream() can be called to get the resource
59 * @throws MalformedURLException
60 */
61 public static URL getResourceUrl(FacesContext ctx, String path) throws MalformedURLException
62 {
63 final ExternalContext externalContext = ctx.getExternalContext();
64 URL url = externalContext.getResource(path);
65 if (log.isLoggable(Level.FINE))
66 {
67 log.fine("Resource-Url from external context: " + url);
68 }
69 if (url == null)
70 {
71 // This might happen on Servlet container which doesnot return
72 // anything
73 // for getResource() (like weblogic 8.1 for packaged wars) we
74 // are trying
75 // to use an own URL protocol in order to use
76 // ServletContext.getResourceAsStream()
77 // when opening the url
78 if (resourceExist(externalContext, path))
79 {
80 url = getUrlForResourceAsStream(externalContext, path);
81 }
82 }
83 return url;
84 }
85
86 // This method could be used above to provide a 'fail fast' if a
87 // resource
88 // doesnt exist. Otherwise, the URL will fail on the first access.
89 private static boolean resourceExist(ExternalContext externalContext, String path)
90 {
91 if ("/".equals(path))
92 {
93 // The root context exists always
94 return true;
95 }
96 Object ctx = externalContext.getContext();
97 if (ctx instanceof ServletContext)
98 {
99 ServletContext servletContext = (ServletContext) ctx;
100 InputStream stream = servletContext.getResourceAsStream(path);
101 if (stream != null)
102 {
103 try
104 {
105 stream.close();
106 }
107 catch (IOException e)
108 {
109 // Ignore here, since we donnot wanted to read from this
110 // resource anyway
111 }
112 return true;
113 }
114 }
115 return false;
116 }
117
118 // Construct URL with special URLStreamHandler for proxying
119 // ServletContext.getResourceAsStream()
120 private static URL getUrlForResourceAsStream(final ExternalContext externalContext, String path)
121 throws MalformedURLException
122 {
123 URLStreamHandler handler = new URLStreamHandler()
124 {
125 protected URLConnection openConnection(URL u) throws IOException
126 {
127 final String file = u.getFile();
128 return new URLConnection(u)
129 {
130 public void connect() throws IOException
131 {
132 }
133
134 public InputStream getInputStream() throws IOException
135 {
136 if (log.isLoggable(Level.FINE))
137 {
138 log.fine("Opening internal url to " + file);
139 }
140 Object ctx = externalContext.getContext();
141 // Or maybe fetch the external context afresh ?
142 // Object ctx =
143 // FacesContext.getCurrentInstance().getExternalContext().getContext();
144
145 if (ctx instanceof ServletContext)
146 {
147 ServletContext servletContext = (ServletContext) ctx;
148 InputStream stream = servletContext.getResourceAsStream(file);
149 if (stream == null)
150 {
151 throw new FileNotFoundException("Cannot open resource " + file);
152 }
153 return stream;
154 }
155 else
156 {
157 throw new IOException("Cannot open resource for an context of "
158 + (ctx != null ? ctx.getClass() : null));
159 }
160 }
161 };
162 }
163 };
164 return new URL("internal", null, 0, path, handler);
165 }
166 }