View Javadoc

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  
20  package org.apache.myfaces.tobago.facelets;
21  
22  import org.slf4j.Logger;
23  import org.slf4j.LoggerFactory;
24  
25  import javax.faces.context.ExternalContext;
26  import javax.faces.context.FacesContext;
27  import javax.servlet.ServletContext;
28  import java.io.FileNotFoundException;
29  import java.io.IOException;
30  import java.io.InputStream;
31  import java.net.MalformedURLException;
32  import java.net.URL;
33  import java.net.URLConnection;
34  import java.net.URLStreamHandler;
35  
36  /*
37   * Was copied from MyFaces-Impl, because there is no JSF base class.
38   */
39  public final class Resource {
40  
41    private static final Logger LOG = LoggerFactory.getLogger(Resource.class);
42  
43    private Resource() {
44    }
45  
46    /**
47     * Get an URL of an internal resource. First, {@link javax.faces.context.ExternalContext#getResource(String)} is
48     * 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
49     * for a packed war), a URL with a special URL handler is constructed, which can be used for <em>opening</em> a
50     * serlvet resource later. Internally, this special URL handler will call
51     * {@link javax.servlet.ServletContext#getResourceAsStream(String)} when an inputstream is requested.
52     * This works even on Weblogic 8.1
53     *
54     * @param ctx  the faces context from which to retrieve the resource
55     * @param path an URL path
56     * @return an url representing the URL and on which getInputStream() can be called to get the resource
57     * @throws java.net.MalformedURLException
58     */
59    public static URL getResourceUrl(final FacesContext ctx, final String path) throws MalformedURLException {
60      final ExternalContext externalContext = ctx.getExternalContext();
61      URL url = externalContext.getResource(path);
62      if (LOG.isTraceEnabled()) {
63        LOG.trace("Resource-Url from external context: " + url);
64      }
65      if (url == null) {
66        // This might happen on Servlet container which doesnot return
67        // anything
68        // for getResource() (like weblogic 8.1 for packaged wars) we
69        // are trying
70        // to use an own URL protocol in order to use
71        // ServletContext.getResourceAsStream()
72        // when opening the url
73        if (resourceExist(externalContext, path)) {
74          url = getUrlForResourceAsStream(externalContext, path);
75        }
76      }
77      return url;
78    }
79  
80    // This method could be used above to provide a 'fail fast' if a
81    // resource
82    // doesnt exist. Otherwise, the URL will fail on the first access.
83    private static boolean resourceExist(final ExternalContext externalContext, final String path) {
84      if ("/".equals(path)) {
85        // The root context exists always
86        return true;
87      }
88      final Object ctx = externalContext.getContext();
89      if (ctx instanceof ServletContext) {
90        final ServletContext servletContext = (ServletContext) ctx;
91        final InputStream stream = servletContext.getResourceAsStream(path);
92        if (stream != null) {
93          try {
94            stream.close();
95          } catch (final IOException e) {
96            // Ignore here, since we donnot wanted to read from this
97            // resource anyway
98          }
99          return true;
100       }
101     }
102     return false;
103   }
104 
105   // Construct URL with special URLStreamHandler for proxying
106   // ServletContext.getResourceAsStream()
107   private static URL getUrlForResourceAsStream(final ExternalContext externalContext, final String path)
108       throws MalformedURLException {
109     final URLStreamHandler handler = new URLStreamHandler() {
110       protected URLConnection openConnection(final URL u) throws IOException {
111         final String file = u.getFile();
112         return new URLConnection(u) {
113           public void connect() throws IOException {
114           }
115 
116           public InputStream getInputStream() throws IOException {
117             if (LOG.isTraceEnabled()) {
118               LOG.trace("Opening internal url to " + file);
119             }
120             final Object ctx = externalContext.getContext();
121             // Or maybe fetch the external context afresh ?
122             // Object ctx =
123             // FacesContext.getCurrentInstance().getExternalContext().getContext();
124 
125             if (ctx instanceof ServletContext) {
126               final ServletContext servletContext = (ServletContext) ctx;
127               final InputStream stream = servletContext.getResourceAsStream(file);
128               if (stream == null) {
129                 throw new FileNotFoundException("Cannot open resource " + file);
130               }
131               return stream;
132             } else {
133               throw new IOException("Cannot open resource for an context of "
134                   + (ctx != null ? ctx.getClass() : null));
135             }
136           }
137         };
138       }
139     };
140     return new URL("internal", null, 0, path, handler);
141   }
142 }