dev@javaserverfaces.java.net

Heads up: <ui:debug recordStateSize="true"> issue 1902

From: Edward Burns <edward.burns_at_oracle.com>
Date: Mon, 02 May 2011 15:52:44 -0400

Add view state information to ui:debug
http://java.net/jira/browse/JAVASERVERFACES-1902

usage:

   <ui:debug recordStateSize="true" />


SECTION: Modified Files
----------------------------
M jsf-ri/conf/share/facelet-dev-debug.xml

- Add place-holder section for view state information

M jsf-ri/src/main/java/com/sun/faces/facelets/tag/ui/UIDebug.java

- Add LOGGER

- add boolean property for tag attribute recordStateSize

- add UIDebug parameter to writeDebugOutput(). This is necessary
   to discover if recordStateSize is true. If it is, we take the necessary
   action to output the view state size.

M jsf-ri/src/main/java/com/sun/faces/facelets/util/DevTools.java

- new method interpolateViewState(). Knows how to insert the viewState
   into the template.

M
jsf-ri/src/main/java/com/sun/faces/application/view/StateManagementStrategyImpl.java
M jsf-ri/src/main/java/com/sun/faces/application/StateManagerImpl.java

- Partial and full state size recording

M jsf-ri/systest/src/com/sun/faces/facelets/UIRepeatTestCase.java
       jsf-ri/systest/build-tests.xml jsf-ri/systest/build.xml
A jsf-ri/systest/src/com/sun/faces/systest/model/ThousandsOfPojos.java
A jsf-ri/systest/web/facelets/uirepeat5.xhtml

- testcase fodder.

SECTION: Diffs
----------------------------
Index: jsf-ri/conf/share/facelet-dev-debug.xml
===================================================================
--- jsf-ri/conf/share/facelet-dev-debug.xml (revision 9000)
+++ jsf-ri/conf/share/facelet-dev-debug.xml (working copy)
@@ -69,7 +69,7 @@
  h2 a { text-decoration: none; color: #339; }
  .grayBox { padding: 8px; margin: 10px 0; border: 1px solid #CCC;
background-color: #f9f9f9; }
  #view { color: #090; font-weight: bold; font-size: medium; }
-#tree, #vars { display: none; }
+#tree, #vars, #state { display: none; }
  code { font-size: medium; }
  #tree dl { color: #006; }
  #tree dd { margin-top: 2px; margin-bottom: 2px; }
@@ -82,7 +82,7 @@
  table caption { text-align: left; padding: 10px 0; font-size: large; }
  </style>
  <style type="text/css" media="print">
-#trace, #tree, #vars { display: block; }
+#trace, #tree, #vars, #state { display: block; }
  </style>
  <script language="javascript" type="text/javascript">
  function faceletstoggle(id) {
@@ -102,10 +102,16 @@
  <body>
  <h1>Debug Output</h1>
  <div id="error" class="grayBox" style="border: 1px solid
#090;">@@message@@</div>
+
  <h2><a href="#" onclick="faceletstoggle('tree'); return false;"><span
id="treeOff">+</span><span id="treeOn" style="display: none;">-</span>
Component Tree</a></h2>
  <div id="tree" class="grayBox"><code>@@tree@@</code></div>
+
  <h2><a href="#" onclick="faceletstoggle('vars'); return false;"><span
id="varsOff">+</span><span id="varsOn" style="display: none;">-</span>
Scoped Variables</a></h2>
  <div id="vars">@@vars@@</div>
+
+<h2><a href="#" onclick="faceletstoggle('state'); return false;"><span
id="stateOff">+</span><span id="stateOn" style="display: none;">-</span>
View State</a></h2>
+<div id="state">^^state^^</div>
+
  <div class="grayBox" style="text-align: right; color: #666;">@@now@@ -
Generated by Mojara/Facelets</div>
  </body>
  </html>
Index: jsf-ri/src/main/java/com/sun/faces/facelets/tag/ui/UIDebug.java
===================================================================
--- jsf-ri/src/main/java/com/sun/faces/facelets/tag/ui/UIDebug.java
(revision 9000)
+++ jsf-ri/src/main/java/com/sun/faces/facelets/tag/ui/UIDebug.java
(working copy)
@@ -58,15 +58,22 @@

  package com.sun.faces.facelets.tag.ui;

+import com.sun.faces.RIConstants;
  import com.sun.faces.facelets.util.DevTools;
  import com.sun.faces.facelets.util.FastWriter;
+import java.io.OutputStream;
+import java.util.logging.Level;
+import java.util.logging.Logger;

  import javax.faces.component.UIComponentBase;
  import javax.faces.context.FacesContext;
  import javax.faces.context.ResponseWriter;
  import javax.servlet.http.HttpServletResponse;
  import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
  import java.util.ArrayList;
+import java.util.HashMap;
  import java.util.LinkedHashMap;
  import java.util.List;
  import java.util.Map;
@@ -80,9 +87,14 @@
      public final static String COMPONENT_FAMILY = "facelets";
      private static long nextId = System.currentTimeMillis();
      private final static String KEY = "facelets.ui.DebugOutput";
+ private final static String PER_VIEW_DEBUG =
RIConstants.FACES_PREFIX + ".PerViewDebug";
      public final static String DEFAULT_HOTKEY = "D";
      private String hotkey = DEFAULT_HOTKEY;
-
+ private boolean recordStateSize = false;
+
+ private static final Logger LOGGER =
Logger.getLogger("javax.faces.component",
+ "javax.faces.LogStrings");
+
      public UIDebug() {
          super();
          this.setTransient(true);
@@ -110,7 +122,7 @@

          pushComponentToEL(faces, this);
          String actionId =
faces.getApplication().getViewHandler().getActionURL(faces,
faces.getViewRoot().getViewId());
-
+
          StringBuffer sb = new StringBuffer(512);
          sb.append("//<![CDATA[\n");
          sb.append("function faceletsDebug(URL) { day = new Date(); id
= day.getTime(); eval(\"page\" + id + \" = window.open(URL, '\" + id +
\"',
'toolbar=0,scrollbars=1,location=0,statusbar=0,menubar=0,resizable=1,width=800,height=600,left
= 240,top = 212');\"); };");
@@ -119,7 +131,7 @@
          sb.append('?');
          sb.append(KEY);
          sb.append('=');
- sb.append(writeDebugOutput(faces));
+ sb.append(writeDebugOutput(faces, this));
          sb.append("'); else if (faceletsOrigKeyup)
faceletsOrigKeyup(e); };\n");
          sb.append("//]]>\n");

@@ -132,10 +144,10 @@

      }

- private static String writeDebugOutput(FacesContext faces) throws
IOException {
+ private static String writeDebugOutput(FacesContext faces, UIDebug
component) throws IOException {
          FastWriter fw = new FastWriter();
          DevTools.debugHtml(fw, faces);
-
+
          Map session = faces.getExternalContext().getSessionMap();
          Map debugs = (Map) session.get(KEY);
          if (debugs == null) {
@@ -148,16 +160,97 @@
          }
          String id = "" + nextId++;
          debugs.put(id, fw.toString());
+
+ if (component.isRecordStateSize()) {
+ faces.getAttributes().put(PER_VIEW_DEBUG, id);
+ }
+
          return id;
      }
-
+
+ public static void computeViewStateSize(FacesContext context,
+ Object [] state) throws IOException {
+
+ }
+
+
+ public static void computeViewStateSize(FacesContext context,
+ Map<String, Serializable> state) throws IOException {
+ Map<Object, Object> contextMap = context.getAttributes();
+
+ Map<String, Object> sessionMap =
context.getExternalContext().getSessionMap();
+ Map debugs = (Map) sessionMap.get(KEY);
+
+ Map<String, Long> sizes = new HashMap<String, Long>();
+ String id = contextMap.get(PER_VIEW_DEBUG).toString() + "_state";
+ debugs.put(id, sizes);
+
+ CountingOutputStream cos = new CountingOutputStream();
+ ObjectOutputStream objectOutputStream = new
ObjectOutputStream(cos);
+ long count, total = 0;
+
+ for (Map.Entry<String, Serializable> cur : state.entrySet()) {
+ cos.reset();
+ objectOutputStream.writeObject(cur.getValue());
+ count = cos.getByteCount();
+ total += count;
+ sizes.put(cur.getKey(), count );
+ }
+ sizes.put("", total);
+
+ }
+
      private static String fetchDebugOutput(FacesContext faces, String
id) {
          Map session = faces.getExternalContext().getSessionMap();
          Map debugs = (Map) session.get(KEY);
+ String result = null;
          if (debugs != null) {
- return (String) debugs.get(id);
+ result = (String) debugs.get(id);
+ if (null == result) {
+ return "Reload the view to inspect the debug information";
+ }
+ final String viewStateKey = id + "_state";
+
+ if (debugs.containsKey(viewStateKey)) {
+ try {
+ final Map<String, Long> sizes = (Map<String, Long>)
debugs.get(viewStateKey);
+ result = DevTools.interpolateViewState(result, new
ViewStateRenderer() {
+
+ public String renderViewState() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("<table>");
+ builder.append("<tr><th>Client
id</th><th>Size in bytes</th></tr>");
+ // Go through the map here and render it
out, according
+ // to the encoding in computeViewStateSize
+ for (Map.Entry<String, Long> cur :
sizes.entrySet()) {
+ if (!"".equals(cur.getKey())) {
+
builder.append("<tr><td>").append(cur.getKey()).append("</td><td>").append(cur.getValue()).append("</td></tr>");
+ }
+ }
+
builder.append("<tr><th>Total</th><th>").append(sizes.get("")).append("</th></tr>");
+ builder.append("</table>");
+
+ return builder.toString();
+ }
+
+ });
+ } catch (IOException ex) {
+ LOGGER.log(Level.SEVERE, "Unable to write view
state", ex);
+ }
+ } else {
+ try {
+ result = DevTools.interpolateViewState(result, new
ViewStateRenderer() {
+ public String renderViewState() {
+ return "No view state available. Add
recordStateSize=\"true\" to &lt;ui:debug&gt; to see view state size.";
+ }
+
+ });
+ } catch (IOException ex) {
+ LOGGER.log(Level.SEVERE, "Unable to write view
state", ex);
+ }
+ }
          }
- return null;
+ return result;
      }

      public static boolean debugRequest(FacesContext faces) {
@@ -195,4 +288,63 @@
          this.hotkey = (hotkey != null) ? hotkey.toUpperCase() : "";
      }

+ public static boolean isRecordStateSize(FacesContext context) {
+ return context.getAttributes().containsKey(PER_VIEW_DEBUG);
+ }
+
+ public boolean isRecordStateSize() {
+ return recordStateSize;
+ }
+
+ public void setRecordStateSize(boolean recordStateSize) {
+ this.recordStateSize = recordStateSize;
+ }
+
+ private static class CountingOutputStream extends OutputStream {
+
+ long bytes;
+ public Long getByteCount() {
+ return bytes;
+ }
+
+ public void reset() {
+ bytes = 0;
+ }
+
+
+ @Override
+ public void write(int b) throws IOException {
+ bytes++;
+ }
+
+ }
+
+ public interface ViewStateRenderer {
+ public String renderViewState();
+ }
+
+
  }
Index: jsf-ri/src/main/java/com/sun/faces/facelets/util/DevTools.java
===================================================================
--- jsf-ri/src/main/java/com/sun/faces/facelets/util/DevTools.java
(revision 9000)
+++ jsf-ri/src/main/java/com/sun/faces/facelets/util/DevTools.java
(working copy)
@@ -58,6 +58,7 @@

  package com.sun.faces.facelets.util;

+import com.sun.faces.facelets.tag.ui.UIDebug;
  import com.sun.faces.util.Util;

  import javax.el.Expression;
@@ -289,7 +290,24 @@

      }

+ public static String interpolateViewState(String input,
UIDebug.ViewStateRenderer renderer) throws IOException {
+ StringBuilder builder = new StringBuilder();

+ String [] parts = input.split("\\^\\^");
+
+ for (String part : parts) {
+ if ("state".equals(part)) {
+ builder.append(renderer.renderViewState());
+ } else {
+ builder.append(part);
+ }
+ }
+
+
+ return builder.toString();
+ }
+
+
      private static String[] splitTemplate(String rsc) throws IOException {

          ClassLoader loader = Util.getCurrentLoader(DevTools.class);
Index:
jsf-ri/src/main/java/com/sun/faces/application/view/StateManagementStrategyImpl.java
===================================================================
---
jsf-ri/src/main/java/com/sun/faces/application/view/StateManagementStrategyImpl.java
(revision 9000)
+++
jsf-ri/src/main/java/com/sun/faces/application/view/StateManagementStrategyImpl.java
(working copy)
@@ -55,6 +55,7 @@
  import javax.faces.render.ResponseStateManager;

  import com.sun.faces.context.StateContext;
+import com.sun.faces.facelets.tag.ui.UIDebug;
  import com.sun.faces.renderkit.RenderKitUtils;
  import com.sun.faces.util.ComponentStruct;
  import com.sun.faces.util.FacesLogger;
@@ -65,7 +66,7 @@
  import java.util.HashMap;
  import java.util.List;
  import java.io.IOException;
-import java.util.Collections;
+import java.io.Serializable;
  import javax.faces.application.StateManager;
  import javax.faces.component.ContextCallback;
  import javax.faces.component.visit.VisitCallback;
@@ -144,7 +145,7 @@
          Util.checkIdUniqueness(context,
                                 viewRoot,
                                 new
HashSet<String>(viewRoot.getChildCount() << 1));
- final Map<String,Object> stateMap = new HashMap<String,Object>();
+ final Map<String,Serializable> stateMap = new
HashMap<String,Serializable>();

          final StateContext stateContext =
StateContext.getStateContext(context);

@@ -160,7 +161,7 @@
              viewRoot.visitTree(visitContext, new VisitCallback() {
                  public VisitResult visit(VisitContext context,
UIComponent target) {
                      VisitResult result = VisitResult.ACCEPT;
- Object stateObj;
+ Serializable stateObj;
                      if (!target.isTransient()) {
                          if
(stateContext.componentAddedDynamically(target)) {
                              stateObj = new
StateHolderSaver(finalContext, target);
@@ -174,7 +175,7 @@
                              }

                          } else {
- stateObj =
target.saveState(context.getFacesContext());
+ stateObj = (Serializable)
target.saveState(context.getFacesContext());
                          }
                          if (null != stateObj) {
 
stateMap.put(target.getClientId(context.getFacesContext()), stateObj);
@@ -195,7 +196,7 @@
          // handle dynamic adds/removes
          List<String> removeList = stateContext.getDynamicRemoves();
          if (null != removeList && !removeList.isEmpty()) {
- stateMap.put(CLIENTIDS_TO_REMOVE_NAME, removeList);
+ stateMap.put(CLIENTIDS_TO_REMOVE_NAME, (Serializable)
removeList);
          }
          Map<String, ComponentStruct> addList =
stateContext.getDynamicAdds();
          if (null != addList && !addList.isEmpty()) {
@@ -205,8 +206,14 @@
              }
              stateMap.put(CLIENTIDS_TO_ADD_NAME, savedAddList.toArray());
          }
- //return stateMap;
- return new Object[] { null, stateMap };
+ if (UIDebug.isRecordStateSize(context)) {
+ try {
+ UIDebug.computeViewStateSize(context, stateMap);
+ } catch (IOException ex) {
+ LOGGER.log(Level.SEVERE, "Unable to obtain view state
size for UIDebug", ex);
+ }
+ }
+ return new Object[] { null, stateMap };

      }

Index: jsf-ri/src/main/java/com/sun/faces/application/StateManagerImpl.java
===================================================================
---
jsf-ri/src/main/java/com/sun/faces/application/StateManagerImpl.java
(revision 9000)
+++
jsf-ri/src/main/java/com/sun/faces/application/StateManagerImpl.java
(working copy)
@@ -40,7 +40,9 @@

  package com.sun.faces.application;

+import com.sun.faces.facelets.tag.ui.UIDebug;
  import com.sun.faces.renderkit.RenderKitUtils;
+import com.sun.faces.util.FacesLogger;
  import com.sun.faces.util.Util;

  import javax.faces.FacesException;
@@ -57,12 +59,16 @@
  import java.io.IOException;
  import java.io.ObjectInput;
  import java.io.ObjectOutput;
+import java.io.Serializable;
  import java.util.ArrayList;
+import java.util.HashMap;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Map.Entry;
  import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;

  /**
   * <p>
@@ -80,6 +86,8 @@

      private boolean isDevelopmentMode;
      private Map<String,Class<?>> classMap;
+ // Log instance for this class
+ private static final Logger LOGGER =
FacesLogger.APPLICATION.getLogger();


      // ------------------------------------------------------------
Constructors
@@ -143,6 +151,21 @@
                  Object[] tree = treeList.toArray();

                  result = new Object[]{tree, state};
+
+ if (UIDebug.isRecordStateSize(context)) {
+ StringBuilder idList = new StringBuilder();
+ for (TreeNode cur : treeList) {
+ idList.append(cur.id).append("<br />");
+ }
+ Map<String, Serializable> stateMap = new
HashMap<String, Serializable>();
+ stateMap.put(idList.toString(), (Serializable) state);
+ try {
+ UIDebug.computeViewStateSize(context, stateMap);
+ } catch (IOException ioe) {
+ LOGGER.log(Level.SEVERE, "Unable to obtain view
state size for UIDebug", ioe);
+ }
+ }
+
              }
          }
          finally {
Index: jsf-ri/systest/src/com/sun/faces/facelets/UIRepeatTestCase.java
===================================================================
--- jsf-ri/systest/src/com/sun/faces/facelets/UIRepeatTestCase.java
(revision 9000)
+++ jsf-ri/systest/src/com/sun/faces/facelets/UIRepeatTestCase.java
(working copy)
@@ -40,7 +40,9 @@

  package com.sun.faces.facelets;

+import com.gargoylesoftware.htmlunit.WebWindow;
  import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
+import com.gargoylesoftware.htmlunit.html.HtmlElement;
  import com.gargoylesoftware.htmlunit.html.HtmlPage;
  import com.gargoylesoftware.htmlunit.html.HtmlSpan;
  import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput;
@@ -207,4 +209,17 @@

      }

+ public void testDebugViewState() throws Exception {
+ HtmlPage page = getPage("/faces/facelets/uirepeat5.xhtml");
+ HtmlElement form = page.getElementById("form");
+ page = (HtmlPage) form.type('D', true, true, false);
+ List<WebWindow> windows = client.getWebWindows();
+ WebWindow debugWindow = windows.get(1);
+ page = (HtmlPage) debugWindow.getEnclosedPage();
+ String xml = page.asXml();
+
assertTrue(xml.matches("(?s).*<th>\\s*Total\\s*</th>\\s*<th>\\s*[0-9]*\\s*</th>.*"));
+
+
+ }
+
  }
Index: jsf-ri/systest/src/com/sun/faces/systest/model/ThousandsOfPojos.java
===================================================================
---
jsf-ri/systest/src/com/sun/faces/systest/model/ThousandsOfPojos.java
(revision 0)
+++
jsf-ri/systest/src/com/sun/faces/systest/model/ThousandsOfPojos.java
(revision 0)
@@ -0,0 +1,156 @@
+
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights
reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
+ * or packager/legal/LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice
in each
+ * file and include the License file at packager/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the
License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the
fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL
or GPL
+ * Version 2] license." If you don't indicate a single choice of
license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option
applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package com.sun.faces.systest.model;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.faces.bean.ManagedBean;
+import javax.faces.bean.SessionScoped;
+
+
+_at_ManagedBean
+_at_SessionScoped
+public class ThousandsOfPojos {
+
+ private List<Item> items;
+
+ public ThousandsOfPojos() {
+ int size = 2000;
+ items = new ArrayList<Item>(size);
+ Item cur;
+ String curStr;
+ for (int i = 0; i < size; i++) {
+ curStr = Long.toHexString(System.currentTimeMillis());
+ cur = new Item("a" + curStr, "b" + curStr, "c" + curStr);
+ items.add(cur);
+ }
+ }
+
+ public List<Item> getItems() {
+ return items;
+ }
+
+
+
+ // <editor-fold defaultstate="collapsed" desc="Inner Classes">
+
+ public class Item {
+ String a, b, c;
+ InnerItem inner;
+
+ public Item(String a, String b, String c) {
+ this.a = a;
+ this.b = b;
+ this.c = c;
+
+ inner = new InnerItem(a+b, a+c);
+ }
+
+
+
+ public String getA() {
+ return a;
+ }
+
+ public void setA(String a) {
+ this.a = a;
+ }
+
+ public String getB() {
+ return b;
+ }
+
+ public void setB(String b) {
+ this.b = b;
+ }
+
+ public String getC() {
+ return c;
+ }
+
+ public void setC(String c) {
+ this.c = c;
+ }
+
+ public InnerItem getInner() {
+ return inner;
+ }
+
+ public void setInner(InnerItem inner) {
+ this.inner = inner;
+ }
+
+
+
+ }
+
+ public class InnerItem {
+ String d, e;
+
+ public InnerItem(String d, String e) {
+ this.d = d;
+ this.e = e;
+ }
+
+
+
+ public String getD() {
+ return d;
+ }
+
+ public void setD(String d) {
+ this.d = d;
+ }
+
+ public String getE() {
+ return e;
+ }
+
+ public void setE(String e) {
+ this.e = e;
+ }
+
+ }
+
+ // </editor-fold>
+
+}
Index: jsf-ri/systest/web/facelets/uirepeat5.xhtml
===================================================================
--- jsf-ri/systest/web/facelets/uirepeat5.xhtml (revision 0)
+++ jsf-ri/systest/web/facelets/uirepeat5.xhtml (revision 0)
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights
reserved.
+
+ The contents of this file are subject to the terms of either the GNU
+ General Public License Version 2 only ("GPL") or the Common Development
+ and Distribution License("CDDL") (collectively, the "License"). You
+ may not use this file except in compliance with the License. You can
+ obtain a copy of the License at
+ https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
+ or packager/legal/LICENSE.txt. See the License for the specific
+ language governing permissions and limitations under the License.
+
+ When distributing the software, include this License Header Notice
in each
+ file and include the License file at packager/legal/LICENSE.txt.
+
+ GPL Classpath Exception:
+ Oracle designates this particular file as subject to the "Classpath"
+ exception as provided by Oracle in the GPL Version 2 section of the
License
+ file that accompanied this code.
+
+ Modifications:
+ If applicable, add the following below the License Header, with the
fields
+ enclosed by brackets [] replaced by your own identifying information:
+ "Portions Copyright [year] [name of copyright owner]"
+
+ Contributor(s):
+ If you wish your version of this file to be governed by only the
CDDL or
+ only the GPL Version 2, indicate your decision by adding "[Contributor]
+ elects to include this software in this distribution under the
[CDDL or GPL
+ Version 2] license." If you don't indicate a single choice of
license, a
+ recipient has the option to distribute your version of this file under
+ either the CDDL, the GPL Version 2 or to extend the choice of
license to
+ its licensees as provided above. However, if you add GPL Version 2
code
+ and therefore, elected the GPL Version 2 license, then the option
applies
+ only if the new code is made subject to such option by the copyright
+ holder.
+
+-->
+
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ xmlns:f="http://java.sun.com/jsf/core">
+<head>
+ <title>ui:repeat5 test</title>
+</head>
+<body>
+<h:form id="form" prependId="false">
+
+
+ <ui:repeat var="var"
+ value="#{thousandsOfPojos.items}">
+
+ <h:inputText value="#{var.a}" />
+ <h:inputText value="#{var.b}" />
+ <h:inputText value="#{var.c}" />
+
+ <h:inputText value="#{var.inner.d}" />
+ <h:inputText value="#{var.inner.e}" />
+ </ui:repeat>
+
+
+</h:form>
+<h:messages id="messages"/>
+<ui:debug recordStateSize="true" />
+</body>
+</html>