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  package org.apache.myfaces.shared.renderkit.html.util;
20  
21  import java.io.IOException;
22  import javax.faces.FacesWrapper;
23  
24  import javax.faces.application.Resource;
25  import javax.faces.application.ResourceHandler;
26  import javax.faces.component.UIComponent;
27  import javax.faces.context.FacesContext;
28  import javax.faces.context.ResponseWriter;
29  
30  import org.apache.myfaces.shared.config.MyfacesConfig;
31  import org.apache.myfaces.shared.renderkit.JSFAttr;
32  import org.apache.myfaces.shared.renderkit.html.HTML;
33  import org.apache.myfaces.shared.resource.ContractResource;
34  
35  /**
36   * @since 4.0.1
37   */
38  public class ResourceUtils
39  {
40      @Deprecated //Use the one from JSF 2.3 ResourceHandler
41      public final static String JAVAX_FACES_LIBRARY_NAME = "javax.faces";
42      @Deprecated //Use the one from JSF 2.3 ResourceHandler
43      public final static String JSF_JS_RESOURCE_NAME = "jsf.js";
44  
45      public final static String MYFACES_JS_RESOURCE_NAME = "oamSubmit.js";
46      public final static String MYFACES_JS_RESOURCE_NAME_UNCOMPRESSED = "oamSubmit-uncompressed.js";
47      public final static String MYFACES_LIBRARY_NAME = "org.apache.myfaces";
48      private final static String RENDERED_MYFACES_JS = "org.apache.myfaces.RENDERED_MYFACES_JS";
49  
50      public final static String JSF_MYFACES_JSFJS_MINIMAL = "minimal";
51      public final static String JSF_MYFACES_JSFJS_MINIMAL_MODERN = "minimal-modern";
52      public final static String JSF_MYFACES_JSFJS_NORMAL = "normal";
53      
54      public final static String JSF_UNCOMPRESSED_JS_RESOURCE_NAME = "jsf-uncompressed.js";
55      public final static String JSF_MINIMAL_JS_RESOURCE_NAME = "jsf-minimal.js";
56      public final static String JSF_MINIMAL_MODERN_JS_RESOURCE_NAME = "jsf-minimal-modern.js";
57      
58      public final static String JSF_MYFACES_JSFJS_I18N = "jsf-i18n.js";
59      public final static String JSF_MYFACES_JSFJS_EXPERIMENTAL = "jsf-experimental.js";
60      public final static String JSF_MYFACES_JSFJS_LEGACY = "jsf-legacy.js";
61  
62      private final static String RENDERED_JSF_JS = "org.apache.myfaces.RENDERED_JSF_JS";
63      public final static String HEAD_TARGET = "head";
64      public final static String BODY_TARGET = "body";
65      public final static String FORM_TARGET = "form";
66  
67      public static final String JAVAX_FACES_OUTPUT_COMPONENT_TYPE = "javax.faces.Output";
68      public static final String JAVAX_FACES_TEXT_RENDERER_TYPE = "javax.faces.Text";
69      public static final String DEFAULT_SCRIPT_RENDERER_TYPE = "javax.faces.resource.Script";
70      public static final String DEFAULT_STYLESHEET_RENDERER_TYPE = "javax.faces.resource.Stylesheet";
71  
72      public static void markScriptAsRendered(FacesContext facesContext, String libraryName, String resourceName)
73      {
74          facesContext.getApplication().getResourceHandler().markResourceRendered(
75                  facesContext, resourceName, libraryName);
76      }
77      
78      public static void markStylesheetAsRendered(FacesContext facesContext, String libraryName, String resourceName)
79      {
80          facesContext.getApplication().getResourceHandler().markResourceRendered(
81                  facesContext, resourceName, libraryName);
82      }
83      
84      public static boolean isRenderedScript(FacesContext facesContext, String libraryName, String resourceName)
85      {
86          return facesContext.getApplication().getResourceHandler().isResourceRendered(
87                  facesContext, resourceName, libraryName);
88      }
89      
90      public static boolean isRenderedStylesheet(FacesContext facesContext, String libraryName, String resourceName)
91      {
92          return facesContext.getApplication().getResourceHandler().isResourceRendered(
93                  facesContext, resourceName, libraryName);
94      }
95      
96      public static void writeScriptInline(FacesContext facesContext, ResponseWriter writer, String libraryName, 
97              String resourceName) throws IOException
98      {
99          if (!ResourceUtils.isRenderedScript(facesContext, libraryName, resourceName))
100         {
101             if (MyfacesConfig.getCurrentInstance(facesContext.getExternalContext()).isRiImplAvailable())
102             {
103                 //Use more compatible way.
104                 UIComponent outputScript = facesContext.getApplication().
105                     createComponent(facesContext, JAVAX_FACES_OUTPUT_COMPONENT_TYPE, DEFAULT_SCRIPT_RENDERER_TYPE);
106                 outputScript.getAttributes().put(JSFAttr.NAME_ATTR, resourceName);
107                 outputScript.getAttributes().put(JSFAttr.LIBRARY_ATTR, libraryName);
108                 outputScript.encodeAll(facesContext);
109             }
110             else
111             {
112                 //Fast shortcut, don't create component instance and do what HtmlScriptRenderer do.
113                 Resource resource = facesContext.getApplication().getResourceHandler().createResource(
114                         resourceName, libraryName);
115                 markScriptAsRendered(facesContext, libraryName, resourceName);
116                 writer.startElement(HTML.SCRIPT_ELEM, null);
117                 writer.writeAttribute(HTML.SCRIPT_TYPE_ATTR, HTML.SCRIPT_TYPE_TEXT_JAVASCRIPT , null);
118                 writer.writeURIAttribute(HTML.SRC_ATTR, resource.getRequestPath(), null);
119                 writer.endElement(HTML.SCRIPT_ELEM);
120             }
121         }
122     }
123     
124     public static void renderDefaultJsfJsInlineIfNecessary(FacesContext facesContext, ResponseWriter writer) 
125         throws IOException
126     {
127         if (facesContext.getAttributes().containsKey(RENDERED_JSF_JS))
128         {
129             return;
130         }
131         
132         // Check first if we have lucky, we are using myfaces and the script has
133         // been previously rendered
134         if (isRenderedScript(facesContext, ResourceHandler.JSF_SCRIPT_LIBRARY_NAME,
135                 ResourceHandler.JSF_SCRIPT_RESOURCE_NAME))
136         {
137             facesContext.getAttributes().put(RENDERED_JSF_JS, Boolean.TRUE);
138             return;
139         }
140 
141         // Check if this is an ajax request. If so, we don't need to include it, because that was
142         // already done and in the worst case, jsf script was already loaded on the page.
143         if (facesContext.getPartialViewContext() != null && 
144                 (facesContext.getPartialViewContext().isPartialRequest() ||
145                  facesContext.getPartialViewContext().isAjaxRequest() )
146             )
147         {
148             return;
149         }
150         
151 
152         // Here we have two cases:
153         // 1. The standard script could be put in another target (body or form).
154         // 2. RI is used so it is not used our set to check for rendered resources
155         //    and we don't have access to that one.
156         // 
157         // Check if we have the resource registered on UIViewRoot "body" or "form" target
158         // is not safe, because the page could not use h:body or h:form. 
159         // Anyway, there is no clear reason why page authors could do the first one, 
160         // but the second one could be.
161         //
162         // Finally we need to force render the script. If the script has been already rendered
163         // (RI used and rendered as a h:outputScript not relocated), nothing will happen because the default
164         // script renderer will check if the script has been rendered first.
165         if (MyfacesConfig.getCurrentInstance(facesContext.getExternalContext()).isRiImplAvailable())
166         {
167             //Use more compatible way.
168             UIComponent outputScript = facesContext.getApplication().
169                     createComponent(facesContext, JAVAX_FACES_OUTPUT_COMPONENT_TYPE, DEFAULT_SCRIPT_RENDERER_TYPE);
170             outputScript.getAttributes().put(JSFAttr.NAME_ATTR, ResourceHandler.JSF_SCRIPT_RESOURCE_NAME);
171             outputScript.getAttributes().put(JSFAttr.LIBRARY_ATTR, ResourceHandler.JSF_SCRIPT_LIBRARY_NAME);
172             outputScript.encodeAll(facesContext);
173         }
174         else
175         {
176             //Fast shortcut, don't create component instance and do what HtmlScriptRenderer do.
177             Resource resource = facesContext.getApplication().getResourceHandler().createResource(
178                     ResourceHandler.JSF_SCRIPT_RESOURCE_NAME, ResourceHandler.JSF_SCRIPT_LIBRARY_NAME);
179             markScriptAsRendered(facesContext, ResourceHandler.JSF_SCRIPT_LIBRARY_NAME,
180                     ResourceHandler.JSF_SCRIPT_RESOURCE_NAME);
181             writer.startElement(HTML.SCRIPT_ELEM, null);
182             writer.writeAttribute(HTML.SCRIPT_TYPE_ATTR, HTML.SCRIPT_TYPE_TEXT_JAVASCRIPT, null);
183             writer.writeURIAttribute(HTML.SRC_ATTR, resource.getRequestPath(), null);
184             writer.endElement(HTML.SCRIPT_ELEM);
185         }
186 
187         //mark as rendered
188         facesContext.getAttributes().put(RENDERED_JSF_JS, Boolean.TRUE);
189         return;
190     }
191 
192     public static void renderMyfacesJSInlineIfNecessary(FacesContext facesContext, ResponseWriter writer)
193         throws IOException
194     {
195         if (facesContext.getAttributes().containsKey(RENDERED_MYFACES_JS))
196         {
197             return;
198         }
199 
200 
201         //we only are allowed to do this on partial requests
202         //because on normal requests a static viewroot still could mean that a full page refresh is performed
203         //only in a ppr case this means we have the script already loaded and parsed
204         if (facesContext.getPartialViewContext() != null && 
205                 (facesContext.getPartialViewContext().isPartialRequest() ||
206                  facesContext.getPartialViewContext().isAjaxRequest() )
207             )
208         {
209             return;
210         }
211         // Check first if we have lucky, we are using myfaces and the script has
212         // been previously rendered
213         if (isRenderedScript(facesContext, MYFACES_LIBRARY_NAME, MYFACES_JS_RESOURCE_NAME))
214         {
215             facesContext.getAttributes().put(RENDERED_MYFACES_JS, Boolean.TRUE);
216             return;
217         }
218 
219         // Here we have two cases:
220         // 1. The standard script could be put in another target (body or form).
221         // 2. RI is used so it is not used our set to check for rendered resources
222         //    and we don't have access to that one.
223         //
224         // Check if we have the resource registered on UIViewRoot "body" or "form" target
225         // is not safe, because the page could not use h:body or h:form.
226         // Anyway, there is no clear reason why page authors could do the first one,
227         // but the second one could be.
228         //
229         // Finally we need to force render the script. If the script has been already rendered
230         // (RI used and rendered as a h:outputScript not relocated), nothing will happen because the default
231         // script renderer will check if the script has been rendered first.
232         if (MyfacesConfig.getCurrentInstance(facesContext.getExternalContext()).isRiImplAvailable())
233         {
234             //Use more compatible way.
235             UIComponent outputScript = facesContext.getApplication().
236                     createComponent(facesContext, JAVAX_FACES_OUTPUT_COMPONENT_TYPE, DEFAULT_SCRIPT_RENDERER_TYPE);
237             outputScript.getAttributes().put(JSFAttr.NAME_ATTR, MYFACES_JS_RESOURCE_NAME);
238             outputScript.getAttributes().put(JSFAttr.LIBRARY_ATTR, MYFACES_LIBRARY_NAME);
239             outputScript.encodeAll(facesContext);
240         }
241         else
242         {
243             //Fast shortcut, don't create component instance and do what HtmlScriptRenderer do.
244             Resource resource = facesContext.getApplication().getResourceHandler().createResource(
245                     MYFACES_JS_RESOURCE_NAME, MYFACES_LIBRARY_NAME);
246             markScriptAsRendered(facesContext, MYFACES_LIBRARY_NAME, MYFACES_JS_RESOURCE_NAME);
247             writer.startElement(HTML.SCRIPT_ELEM, null);
248             writer.writeAttribute(HTML.SCRIPT_TYPE_ATTR, HTML.SCRIPT_TYPE_TEXT_JAVASCRIPT, null);
249             writer.writeURIAttribute(HTML.SRC_ATTR, resource.getRequestPath(), null);
250             writer.endElement(HTML.SCRIPT_ELEM);
251         }
252 
253         //mark as rendered
254         facesContext.getAttributes().put(RENDERED_MYFACES_JS, Boolean.TRUE);
255         return;
256     }
257 
258     public static String getContractName(Resource resource)
259     {
260         while (resource != null)
261         {
262             if (resource instanceof ContractResource)
263             {
264                 return ((ContractResource)resource).getContractName();
265             }
266             else if (resource instanceof FacesWrapper)
267             {
268                 resource = (Resource)((FacesWrapper)resource).getWrapped();
269             }
270             else
271             {
272                 resource = null;
273             }
274         }
275         return null;
276     }
277 }