1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.view.jsp;
20
21 import java.io.IOException;
22 import java.util.Arrays;
23 import java.util.LinkedList;
24 import java.util.Locale;
25 import java.util.logging.Level;
26 import java.util.logging.Logger;
27 import java.util.stream.Stream;
28
29 import javax.faces.FacesException;
30 import javax.faces.application.ViewVisitOption;
31 import javax.faces.component.UIViewRoot;
32 import javax.faces.context.ExternalContext;
33 import javax.faces.context.FacesContext;
34 import javax.faces.event.PostAddToViewEvent;
35 import javax.faces.render.ResponseStateManager;
36 import javax.servlet.ServletRequest;
37 import javax.servlet.ServletResponse;
38 import javax.servlet.http.HttpServletResponse;
39 import javax.servlet.jsp.jstl.core.Config;
40
41 import org.apache.myfaces.application.jsp.ServletViewResponseWrapper;
42 import org.apache.myfaces.application.viewstate.StateCacheUtils;
43 import org.apache.myfaces.shared.view.JspViewDeclarationLanguageBase;
44 import org.apache.myfaces.view.ViewDeclarationLanguageStrategy;
45 import org.apache.myfaces.view.facelets.tag.composite.CompositeLibrary;
46 import org.apache.myfaces.view.facelets.tag.jsf.core.CoreLibrary;
47 import org.apache.myfaces.view.facelets.tag.jsf.html.HtmlLibrary;
48 import org.apache.myfaces.view.facelets.tag.ui.UILibrary;
49
50
51
52
53
54
55
56 public class JspViewDeclarationLanguage extends JspViewDeclarationLanguageBase
57 {
58 public static final Logger log = Logger.getLogger(JspViewDeclarationLanguage.class.getName());
59
60
61
62
63
64
65 public static final String[] FACELETS_ONLY_F_TAGS = {"ajax", "event", "metadata"};
66 public static final String[] FACELETS_ONLY_H_TAGS = {"outputScript", "outputStylesheet",
67 "head", "body", "button", "link"};
68
69 private final ViewDeclarationLanguageStrategy _strategy;
70 private LinkedList<String> _suffixes;
71
72
73
74
75 public JspViewDeclarationLanguage()
76 {
77 if (log.isLoggable(Level.FINEST))
78 {
79 log.finest("New JspViewDeclarationLanguage instance created");
80 }
81
82 _strategy = new JspViewDeclarationLanguageStrategy();
83 }
84
85 public JspViewDeclarationLanguage(FacesContext facesContext, ViewDeclarationLanguageStrategy strategy,
86 LinkedList<String> suffixes)
87 {
88 this._strategy = strategy;
89 this._suffixes = suffixes;
90 }
91
92
93
94
95 @Override
96 public void buildView(FacesContext context, UIViewRoot view) throws IOException
97 {
98
99 super.buildView(context, view);
100
101 ExternalContext externalContext = context.getExternalContext();
102 ServletResponse response = (ServletResponse) externalContext.getResponse();
103 ServletRequest request = (ServletRequest) externalContext.getRequest();
104
105 Locale locale = view.getLocale();
106 response.setLocale(locale);
107 Config.set(request, Config.FMT_LOCALE, context.getViewRoot().getLocale());
108
109 String viewId = view.getViewId();
110 ServletViewResponseWrapper wrappedResponse = new ServletViewResponseWrapper((HttpServletResponse) response);
111
112 externalContext.setResponse(wrappedResponse);
113 try
114 {
115 externalContext.dispatch(viewId);
116 }
117 catch (FacesException e)
118 {
119
120
121
122 String message = e.getMessage();
123
124
125 if (message != null)
126 {
127
128
129 if (message.contains("\"f\"")
130 || message.contains("\"" + CoreLibrary.NAMESPACE + "\""))
131 {
132
133 for (String tag : FACELETS_ONLY_F_TAGS)
134 {
135 if (message.contains("\"" + tag + "\""))
136 {
137 String exceptionMessage = "The tag f:" + tag +
138 " is only available on facelets.";
139 throw new FacesException(exceptionMessage,
140 new FaceletsOnlyException(exceptionMessage, e.getCause()));
141 }
142 }
143 }
144 else if (message.contains("\"h\"")
145 || message.contains("\"" + HtmlLibrary.NAMESPACE + "\""))
146 {
147
148 for (String tag : FACELETS_ONLY_H_TAGS)
149 {
150 if (message.contains("\"" + tag + "\""))
151 {
152 String exceptionMessage = "The tag h:" + tag +
153 " is only available on facelets.";
154 throw new FacesException(exceptionMessage,
155 new FaceletsOnlyException(exceptionMessage, e.getCause()));
156 }
157 }
158 }
159 else
160 {
161
162 String namespace = null;
163 if (message.contains(UILibrary.NAMESPACE))
164 {
165 namespace = UILibrary.NAMESPACE;
166 }
167 else if (message.contains(CompositeLibrary.NAMESPACE))
168 {
169 namespace = CompositeLibrary.NAMESPACE;
170 }
171
172 if (namespace != null)
173 {
174
175 String exceptionMessage = "All tags with namespace " +
176 namespace + " are only available on facelets.";
177 throw new FacesException(exceptionMessage,
178 new FaceletsOnlyException(exceptionMessage, e.getCause()));
179 }
180 }
181 }
182
183
184 throw e;
185 }
186 finally
187 {
188 externalContext.setResponse(response);
189 }
190
191 boolean errorResponse = wrappedResponse.getStatus() < 200 || wrappedResponse.getStatus() > 299;
192 if (errorResponse)
193 {
194 wrappedResponse.flushToWrappedResponse();
195 return;
196 }
197
198
199
200
201
202 if (!context.getPartialViewContext().isPartialRequest())
203 {
204
205 setAfterViewTagResponseWrapper(externalContext, wrappedResponse);
206 }
207
208
209 context.getApplication().publishEvent(context, PostAddToViewEvent.class, UIViewRoot.class, view);
210 }
211
212
213
214
215 @Override
216 protected boolean isViewStateAlreadyEncoded(FacesContext context)
217 {
218 ResponseStateManager responseStateManager = context.getRenderKit().getResponseStateManager();
219 if (StateCacheUtils.isMyFacesResponseStateManager(responseStateManager))
220 {
221 if (StateCacheUtils.getMyFacesResponseStateManager(responseStateManager).
222 isWriteStateAfterRenderViewRequired(context))
223 {
224 return false;
225 }
226 else
227 {
228 return true;
229 }
230 }
231 else
232 {
233 return false;
234 }
235 }
236
237 @Override
238 protected void sendSourceNotFound(FacesContext context, String message)
239 {
240 HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
241 try
242 {
243 context.responseComplete();
244 response.sendError(HttpServletResponse.SC_NOT_FOUND, message);
245 }
246 catch (IOException ioe)
247 {
248 throw new FacesException(ioe);
249 }
250 }
251
252 @Override
253 public boolean viewExists(FacesContext facesContext, String viewId)
254 {
255 if (_strategy.handles(viewId))
256 {
257 return super.viewExists(facesContext, viewId);
258 }
259 return false;
260 }
261
262 @Override
263 public Stream<String> getViews(FacesContext facesContext, String path, int maxDepth, ViewVisitOption... options)
264 {
265 Stream<String> stream = super.getViews(facesContext, path, maxDepth, options);
266 stream = stream.filter(f -> (_strategy.handles(f) && isValidJSPView(facesContext,f)));
267 if (options != null &&
268 Arrays.binarySearch(options, ViewVisitOption.RETURN_AS_MINIMAL_IMPLICIT_OUTCOME) >= 0)
269 {
270 stream = stream.map(f -> _strategy.getMinimalImplicitOutcome(f));
271 }
272 return stream;
273 }
274
275 private boolean isValidJSPView(FacesContext facesContext, String path)
276 {
277 boolean isValid = false;
278
279
280
281 if (_suffixes == null)
282 {
283 _suffixes = JspViewDeclarationLanguageStrategy.loadSuffixes(facesContext.getExternalContext());
284 }
285
286 for (String suffix : _suffixes)
287 {
288 if (path != null && path.endsWith (suffix))
289 {
290 isValid = true;
291 break;
292 }
293 }
294
295 return isValid;
296 }
297
298 }