KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > tools > jsfext > layout > LayoutViewHandler


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23 package com.sun.enterprise.tools.jsfext.layout;
24
25 import com.sun.enterprise.tools.jsfext.layout.descriptor.LayoutComponent;
26 import com.sun.enterprise.tools.jsfext.layout.descriptor.LayoutDefinition;
27 import com.sun.enterprise.tools.jsfext.layout.descriptor.LayoutElement;
28 import com.sun.enterprise.tools.jsfext.layout.descriptor.LayoutFacet;
29 import com.sun.enterprise.tools.jsfext.layout.descriptor.Resource;
30
31 import java.io.IOException JavaDoc;
32 import java.io.OutputStreamWriter JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.Locale JavaDoc;
35
36 import javax.faces.FactoryFinder;
37 import javax.faces.application.StateManager;
38 import javax.faces.application.StateManager.SerializedView;
39 import javax.faces.application.ViewHandler;
40 import javax.faces.component.UIComponent;
41 import javax.faces.component.UIViewRoot;
42 import javax.faces.context.ExternalContext;
43 import javax.faces.context.FacesContext;
44 import javax.faces.context.ResponseWriter;
45 import javax.faces.render.RenderKit;
46 import javax.faces.render.RenderKitFactory;
47
48 import javax.servlet.ServletRequest JavaDoc;
49 import javax.servlet.ServletResponse JavaDoc;
50
51 // FIXME: Things to consider:
52
// FIXME: - What is necessary to support Portlets...
53
// FIXME: - Should I attempt to clean up old unused UIComponents?
54
// FIXME: - f:view supported setting locale, I should too...
55

56
57 /**
58  * <p> This class provides a custom <code>ViewHandler</code> that is able to
59  * create and populate a <code>UIViewRoot</code> from a
60  * {@link LayoutDefinition}. This is often defined by an XML document,
61  * the default implementation's DTD is defined in
62  * <code>layout.dtd</code>.</p>
63  *
64  * <p> Besides the default <code>ViewHandler</code> behavior, this class is
65  * responsible for instantiating a {@link LayoutViewRoot} and using the
66  * given <code>viewId</code> as the {@link LayoutDefinition} key. It
67  * will obtain the {@link LayoutDefinition}, initialize the declared
68  * {@link Resource}s, and instantiate <code>UIComponent</code> tree using
69  * the {@link LayoutDefinition}'s declared {@link LayoutComponent}
70  * structure. During rendering, it delegates to the
71  * {@link LayoutDefinition}.</p>
72  *
73  * @author Ken Paulsen (ken.paulsen@sun.com)
74  */

75 public class LayoutViewHandler extends ViewHandler {
76
77     /**
78      * <p> Constructor.</p>
79      *
80      * @param oldViewHandler The old <code>ViewHandler</code>.
81      */

82     public LayoutViewHandler(ViewHandler oldViewHandler) {
83     _oldViewHandler = oldViewHandler;
84     }
85
86     /**
87      * <p> This method is invoked when restoreView does not yield a UIViewRoot
88      * (initial requests and new pages).</p>
89      *
90      * <p> This implementation should work with both
91      * <code>LayoutDefinition<code>-based pages as well as traditional
92      * JSP pages.</p>
93      */

94     public UIViewRoot createView(FacesContext context, String JavaDoc viewId) {
95     Locale JavaDoc locale = null;
96     String JavaDoc renderKitId = null;
97
98     // use the locale from the previous view if is was one which will be
99
// the case if this is called from NavigationHandler. There wouldn't be
100
// one for the initial case.
101
if (context.getViewRoot() != null) {
102         locale = context.getViewRoot().getLocale();
103         renderKitId = context.getViewRoot().getRenderKitId();
104     }
105
106     // Create the LayoutViewRoot
107
LayoutViewRoot viewRoot = new LayoutViewRoot();
108     viewRoot.setViewId(viewId);
109     viewRoot.setLayoutDefinitionKey(viewId);
110     // FIXME: I should not set the view root here! But some LH components
111
// may require this during creation of the UIComponent tree.
112
if (context.getViewRoot() == null) {
113         context.setViewRoot(viewRoot);
114     }
115
116     // if there was no locale from the previous view, calculate the locale
117
// for this view.
118
if (locale == null) {
119         locale = calculateLocale(context);
120     }
121     viewRoot.setLocale(locale);
122
123     // set the renderkit
124
if (renderKitId == null) {
125         renderKitId = calculateRenderKitId(context);
126     }
127     viewRoot.setRenderKitId(renderKitId);
128
129     // Initialize Resources / Create Tree
130
LayoutDefinition def = viewRoot.getLayoutDefinition(context);
131     if (def != null) {
132         // Ensure that our Resources are available
133
Iterator JavaDoc it = def.getResources().iterator();
134         Resource resource = null;
135         while (it.hasNext()) {
136         resource = (Resource) it.next();
137         // Just calling getResource() puts it in the Request scope
138
resource.getFactory().getResource(context, resource);
139         }
140
141         // Get the Tree and pre-walk it
142
buildUIComponentTree(context, viewRoot, def);
143     }
144
145     // Return the populated UIViewRoot
146
return viewRoot;
147     }
148
149     /**
150      *
151      */

152     protected void buildUIComponentTree(FacesContext context, UIComponent parent, LayoutElement elt) {
153 // FIXME: Consider processing *ALL* LayoutElements so that <if> and others
154
// FIXME: have meaning when inside other components.
155
Iterator JavaDoc it = elt.getChildLayoutElements().iterator();
156     LayoutElement childElt;
157     UIComponent child = null;
158     while (it.hasNext()) {
159         childElt = (LayoutElement) it.next();
160         if (childElt instanceof LayoutFacet) {
161         if (!((LayoutFacet) childElt).isRendered()) {
162             // The contents of this should be a single UIComponent
163
buildUIComponentTree(context, parent, childElt);
164         }
165         // NOTE: LayoutFacets that aren't JSF facets aren't
166
// NOTE: meaningful in this context
167
} if (childElt instanceof LayoutComponent) {
168         try {
169             // Calling getChild will add the child UIComponent to tree
170
// BEGIN EXPERIMENTAL CODE...
171
UIComponent useParent = parent;
172             if ((EDITOR_ENABLED) && _editArea) {
173 // FIXME: Create a new component that sets the editor environment (meta-data: filename, include files, etc.)
174
useParent = createWrapperComponent(context, parent, childElt.getId(context, parent));
175             }
176 // END EXPERIMENTAL CODE...
177
child = ((LayoutComponent) childElt).
178                 getChild(context, useParent);
179
180             // Check for events
181
// NOTE: For now I am only supporting "action" and
182
// NOTE: "actionListener" event types. In the future it
183
// NOTE: may be desirable to support beforeEncode /
184
// NOTE: afterEncode as well. At this time, those events
185
// NOTE: are supported by the "Event" UIComponent. That
186
// NOTE: component can wrap non-layout-based components to
187
// NOTE: achieve this functionality (supporting that
188
// NOTE: functionality here will simply do the same thing
189
// NOTE: automatically).
190

191             if (((LayoutComponent) childElt).getOption(com.sun.enterprise.tools.jsfext.layout.xml.XMLLayoutDefinitionReader.EDITABLE) != null) {
192             _editArea = true;
193
194             // Recurse
195
buildUIComponentTree(context, child, childElt);
196
197             _editArea = false;
198             } else {
199             // Recurse
200
buildUIComponentTree(context, child, childElt);
201             }
202         } catch (IOException JavaDoc ex) {
203             throw new RuntimeException JavaDoc(ex);
204         }
205         } else {
206         buildUIComponentTree(context, parent, childElt);
207         }
208     }
209     }
210
211 // BEGIN EXPERIMENTAL CODE...
212
private UIComponent createWrapperComponent(FacesContext context, UIComponent parent, String JavaDoc id) {
213     com.sun.enterprise.tools.jsfext.component.EditorComponent wrapper = new com.sun.enterprise.tools.jsfext.component.EditorComponent();
214     wrapper.setId(id + "_editor");
215     parent.getChildren().add(wrapper);
216     return wrapper;
217     }
218 // END EXPERIMENTAL CODE...
219

220     /**
221      * <p> This implementation relies on the default behavior to reconstruct
222      * the UIViewRoot.</p>
223      *
224      * <p> ...</p>
225      */

226     public UIViewRoot restoreView(FacesContext context, String JavaDoc viewId) {
227     // Peform default behavior...
228
UIViewRoot root = _oldViewHandler.restoreView(context, viewId);
229
230     // Return the UIViewRoot (LayoutViewRoot most likely)
231
return root;
232     }
233
234     /**
235      *
236      */

237     public void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException JavaDoc {
238     // Make sure we have a def
239
LayoutDefinition def = null;
240     if (viewToRender instanceof LayoutViewRoot) {
241         def = ((LayoutViewRoot) viewToRender).getLayoutDefinition(context);
242     }
243
244     if (def == null) {
245         // No def, fall back to default behavior
246
_oldViewHandler.renderView(context, viewToRender);
247     } else {
248         // Start document
249
ResponseWriter writer = setupResponseWriter(context);
250         writer.startDocument();
251
252 // BEGIN EXPERIMENTAL CODE...
253
UIComponent target = (UIComponent) context.getExternalContext().
254             getRequestMap().get(LAVA_CHANNEL_TARGET_KEY);
255         if (target != null) {
256         renderComponent(context, target);
257         } else {
258 // END EXPERIMENTAL CODE...
259
// Render content
260
def.encode(context, viewToRender);
261         }
262
263         // End document
264
writer.endDocument();
265     }
266     }
267
268     private static void renderComponent(FacesContext context, UIComponent comp) throws IOException JavaDoc {
269     if (!comp.isRendered()) {
270         return;
271     }
272
273     comp.encodeBegin(context);
274     if (comp.getRendersChildren()) {
275         comp.encodeChildren(context);
276     } else {
277         UIComponent child = null;
278         Iterator JavaDoc it = comp.getChildren().iterator();
279         while (it.hasNext()) {
280         child = (UIComponent) it.next();
281         renderComponent(context, child);
282         }
283     }
284     comp.encodeEnd(context);
285     }
286
287     /**
288      *
289      */

290     private ResponseWriter setupResponseWriter(FacesContext context) throws IOException JavaDoc {
291     ResponseWriter writer = context.getResponseWriter();
292     if (writer != null) {
293         // It is already setup
294
return writer;
295     }
296
297     ExternalContext extCtx = context.getExternalContext();
298     ServletResponse JavaDoc response = (ServletResponse JavaDoc) extCtx.getResponse();
299
300     RenderKitFactory renderFactory = (RenderKitFactory)
301         FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
302     RenderKit renderKit =
303         renderFactory.getRenderKit(context,
304          context.getViewRoot().getRenderKitId());
305     String JavaDoc contentTypeList = (String JavaDoc) extCtx.getRequestHeaderMap().get("Accept");
306     if (!contentTypeList.toLowerCase().contains("text/html")) {
307         contentTypeList += ",text/html;q=1.0";
308     }
309     writer =
310         renderKit.createResponseWriter(
311         new OutputStreamWriter JavaDoc(response.getOutputStream()),
312         contentTypeList,
313         ((ServletRequest JavaDoc) extCtx.getRequest()).getCharacterEncoding());
314     context.setResponseWriter(writer);
315 // Not setting the contentType here results in XHTML which formats differently
316
// than text/html in Mozilla.. even though the document claim to work, it
317
// doesn't (try viewing the Tree)
318
response.setContentType("text/html");
319     return writer;
320     }
321
322     /**
323      * <p> Take any appropriate action to either immediately write out the
324      * current state information (by calling
325      * <code>StateManager.writeState</code>, or noting where state
326      * information should later be written.</p>
327      *
328      * @param context <code>FacesContext</code> for the current request
329      *
330      * @exception IOException if an input/output error occurs
331      */

332     public void writeState(FacesContext context) throws IOException JavaDoc {
333     // Check to see if we should delegate back to the legacy ViewHandler
334
UIViewRoot root = context.getViewRoot();
335     if ((root == null) || !(root instanceof LayoutViewRoot)
336         || (((LayoutViewRoot) root).
337             getLayoutDefinition(context) == null)) {
338         // Use old behavior...
339
_oldViewHandler.writeState(context);
340     } else {
341         // b/c we pre-processed the ViewTree, we can just add it...
342
StateManager stateManager =
343         context.getApplication().getStateManager();
344         SerializedView view = stateManager.saveSerializedView(context);
345
346         if (stateManager.isSavingStateInClient(context)) {
347         stateManager.writeState(context, view);
348         }
349     }
350     }
351
352     /**
353      * <p> Return a URL suitable for rendering (after optional encoding
354      * perfomed by the <code>encodeResourceURL()</code> method of
355      * <code>ExternalContext<code> that selects the specifed web
356      * application resource. If the specified path starts with a slash,
357      * it must be treated as context relative; otherwise, it must be
358      * treated as relative to the action URL of the current view.</p>
359      *
360      * @param context <code>FacesContext</code> for the current request
361      * @param path Resource path to convert to a URL
362      *
363      * @exception IllegalArgumentException If <code>viewId</code> is not
364      * valid for this <code>ViewHandler</code>.
365      */

366     public String JavaDoc getResourceURL(FacesContext context, String JavaDoc path) {
367     return _oldViewHandler.getResourceURL(context, path);
368     }
369
370     /**
371      * <p> Return a URL suitable for rendering (after optional encoding
372      * performed by the <code>encodeActionURL()</code> method of
373      * <code>ExternalContext</code> that selects the specified view
374      * identifier.</p>
375      *
376      * @param context <code>FacesContext</code> for this request
377      * @param viewId View identifier of the desired view
378      *
379      * @exception IllegalArgumentException If <code>viewId</code> is not
380      * valid for this <code>ViewHandler</code>.
381      */

382     public String JavaDoc getActionURL(FacesContext context, String JavaDoc viewId) {
383     return _oldViewHandler.getActionURL(context, viewId);
384     }
385
386     /**
387      * <p> Returns an appropriate <code>Locale</code> to use for this and
388      * subsequent requests for the current client.</p>
389      *
390      * @param context <code>FacesContext</code> for the current request
391      *
392      * @exception NullPointerException if <code>context</code> is
393      * <code>null</code>
394      */

395      public Locale JavaDoc calculateLocale(FacesContext context) {
396      return _oldViewHandler.calculateLocale(context);
397      }
398
399     /**
400      * <p>Return an appropriate <code>renderKitId</code> for this
401      * and subsequent requests from the current client.</p>
402      *
403      * <p>The default return value is
404      * <code>javax.faces.render.RenderKitFactory.HTML_BASIC_RENDER_KIT</code>.
405      * </p>
406      *
407      * @param context <code>FacesContext</code> for the current request.
408      */

409     public String JavaDoc calculateRenderKitId(FacesContext context) {
410     return _oldViewHandler.calculateRenderKitId(context);
411     }
412
413     /**
414      * <p> This is the key that may be used to identify the clientId of the
415      * UIComponent that is to be updated via a "LavaChannel" request.</p>
416      */

417     public static final String JavaDoc LAVA_CHANNEL_KEY = "lavaChannel";
418
419     private ViewHandler _oldViewHandler = null;
420     static final String JavaDoc LAVA_CHANNEL_TARGET_KEY = "_lavaChannelTarget";
421     private static final boolean EDITOR_ENABLED = true;
422     private boolean _editArea = false; // FIXME: Not safe... I'm moving this code to the Reader, though...
423
}
424
Popular Tags