dev@javaserverfaces.java.net

[REVIEW] Proposed fixes for various issues

From: Ryan Lubke <Ryan.Lubke_at_Sun.COM>
Date: Tue, 03 Oct 2006 08:46:37 -0700


Fix for issues:
  388 - https://javaserverfaces.dev.java.net/issues/show_bug.cgi?id=388
  410 - https://javaserverfaces.dev.java.net/issues/show_bug.cgi?id=410
  411 - https://javaserverfaces.dev.java.net/issues/show_bug.cgi?id=411
  413 - https://javaserverfaces.dev.java.net/issues/show_bug.cgi?id=413
  415 - https://javaserverfaces.dev.java.net/issues/show_bug.cgi?id=415
  417 - https://javaserverfaces.dev.java.net/issues/show_bug.cgi?id=417


SECTION: Modified Files
----------------------------

FIX FOR 410
==============================================
M jsf-api/src/javax/faces/webapp/UIComponentClassicTagBase.java
  - modified setJspId() implementation to augment the container
    provided ID with i<include count> when we're part of a
    RequestDispatcher include. This ensures that the UNIQUE_ID_PREFIX
    is only added to IDs when we in a loop instead of either a loop
    or an include. Doing this allows the augmentID logic in HtmlBasicRenderer
    to continue to work in all cases.

M jsf-ri/systest/web/forEach03.jsp
M jsf-ri/systest/web/golden/interweaving06.txt
M jsf-ri/systest/web/golden/interweaving07.txt
M jsf-ri/systest/web/golden/subview05.txt
M jsf-ri/systest/web/golden/subview06.txt
M jsf-ri/systest/src/com/sun/faces/jsptest/IdRefTestCase.java
A jsf-ri/systest/web/forEach03Include.jsp
 - tests to ensure the following works:
   h:message in an include not within a loop
   h:message in an include within a loop
==============================================

FIX FOR 388, 411
==============================================
M jsf-ri/systest/src/com/sun/faces/systest/render/CustomResponseWriter.java
M jsf-ri/src/com/sun/faces/renderkit/html_basic/HtmlResponseWriter.java
  - reflect change in HtmlUtils.validateEncoding()

M jsf-ri/src/com/sun/faces/renderkit/RenderKitUtils.java
  - added utility method to return a boolean flagging whether
    or not the content type is XML-based

M jsf-ri/src/com/sun/faces/util/HtmlUtils.java
 - updated the implementation of validateEncoding() return
   a boolean based on the result of Charset.isSupported()
   instead of allocating a String each time this method is called
 - Added logic to ensure we don't double escape entities
   that are already escaped (i.e. &copy; -> &amp;amp;copy)
 - Updated existing logic on encoding any & in the query
   string when the content type is xml-based.

M jsf-ri/test/com/sun/faces/util/TestHtmlUtils.java
 - updated test with correct inputs/outputs

==============================================

FIX FOR 417
==============================================
M jsf-ri/src/com/sun/faces/application/ApplicationAssociate.java
 - ensure the String argument provided to getResourceBundle()
   is a known key before attempting any additional work
==============================================

FIX FOR 415
==============================================
M jsf-ri/src/com/sun/faces/application/ConverterPropertyEditorFactory.java
 - update the logic in generateClassNameFor to take array
   types into account.
==============================================

FIX FOR 413
==============================================
M jsf-ri/src/com/sun/faces/application/ViewHandlerImpl.java
 - call the appropriate ExternalContext.encode* method
   in the ViewHandler's getActionURL and
   getResourceURL to ensure the URLs are encoded with
   session info if necessary

M jsf-ri/test/com/sun/faces/application/TestViewHandlerImpl.java
 - updated associated test
==============================================



SECTION: Diffs
----------------------------
Index: jsf-api/src/javax/faces/webapp/UIComponentClassicTagBase.java
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-api/src/javax/faces/webapp/UIComponentClassicTagBase.java,v
retrieving revision 1.25
diff -u -r1.25 UIComponentClassicTagBase.java
--- jsf-api/src/javax/faces/webapp/UIComponentClassicTagBase.java 25 Aug 2006 09:50:18 -0000 1.25
+++ jsf-api/src/javax/faces/webapp/UIComponentClassicTagBase.java 3 Oct 2006 15:21:51 -0000
@@ -34,6 +34,7 @@
 import javax.faces.component.UIComponent;
 import javax.faces.component.UIOutput;
 import javax.faces.component.UIViewRoot;
+import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
 import javax.faces.render.ResponseStateManager;
 import javax.servlet.jsp.JspException;
@@ -201,6 +202,13 @@
      */
     private static final String PREVIOUS_JSP_ID_SET =
         "javax.faces.webapp.PREVIOUS_JSP_ID_SET";
+
+ /**
+ * Used to store information about dynamic include
+ * sources.
+ */
+ private static final String JAVAX_FACES_INCLUDE_LIST =
+ "javax.faces.webapp.INCLUDE_LIST";
     
     // ------------------------------------------------------ Instance Variables
     /**
@@ -1394,12 +1402,12 @@
         if (null == facesJspId) {
             if (null != jspId) {
                 facesJspId = UNIQUE_ID_PREFIX + jspId;
- // if this tag happens to be nested within <c:forEach> or we're
- // the target of an include, jspId will be the same for each
- // iteration. So it is transformed into a unique "id" by
- // appending a counter which gets stored in request scope
- // with jspId as the key for use during the next iteration.
- if (isDuplicateId(facesJspId) || isIncludedOrForwarded()) {
+ // if this tag happens to be nested within <c:forEach>,
+ // jspId will be the same for each iteration. So it is
+ // transformed into a unique "id" by appending a counter which
+ // gets stored in request scope with jspId as the key for use
+ // during the next iteration.
+ if (isDuplicateId(facesJspId)) {
                     facesJspId = generateIncrementedId(facesJspId);
                 }
             } else {
@@ -1534,15 +1542,45 @@
      * <p>Defined on {_at_link JspIdConsumer}. This method is called by
      * the container before {_at_link #doStartTag}. The argument is
      * guaranteed to be unique within the page.</p>
+ *
+ * <p>IMPLEMENTATION NOTE: This method will detect where we
+ * are in an include and assign a unique ID for each include
+ * in a particular 'logical page'. This allows us to avoid
+ * possible duplicate ID situations for included pages that
+ * have components without explicit IDs.</p>
      *
      * @param id the container generated id for this tag, guaranteed to
      * be unique within the page.
      */
 
     public void setJspId(String id) {
- facesJspId = null;
- updatePreviousJspIdAndIteratorStatus(id);
- jspId = id;
+ if (isIncluded()) {
+ StringBuilder builder = new StringBuilder(id.length() + 3);
+ builder.append(id);
+ ExternalContext extContext = context.getExternalContext();
+ Map<String,Object> reqMap = extContext.getRequestMap();
+ List<String> includeList =
+ TypedCollections.dynamicallyCastList(
+ ((List) reqMap.get(JAVAX_FACES_INCLUDE_LIST)),
+ String.class);
+ if (includeList == null) {
+ includeList = new IdentityArrayList<String>(6);
+ reqMap.put(JAVAX_FACES_INCLUDE_LIST, includeList);
+ }
+ String key = (String) reqMap.get("javax.servlet.include.request_uri");
+ int idx = includeList.indexOf(key);
+ if (idx != -1) {
+ builder.append('i').append(idx);
+ } else {
+ includeList.add(key);
+ builder.append('i').append(includeList.size() - 1);
+ }
+ jspId = builder.toString();
+ } else {
+ jspId = id;
+ }
+ facesJspId = null;
+ updatePreviousJspIdAndIteratorStatus(jspId);
     }
 
     /**
@@ -1574,7 +1612,7 @@
         }
         assert(null != previousJspIdSet);
         // detect the iterator case
- if (previousJspIdSet.contains(id) && !isIncludedOrForwarded()) {
+ if (previousJspIdSet.contains(id)) {
             if (log.isLoggable(Level.FINEST)) {
                 log.log(Level.FINEST, "Id " + id +
                         " is nested within an iterating tag.");
@@ -1587,7 +1625,7 @@
         }
     }
     
- private boolean isIncludedOrForwarded() {
+ private boolean isIncluded() {
         return (getFacesContext().getExternalContext().getRequestMap().
                 containsKey("javax.servlet.include.request_uri"));
     }
@@ -1794,4 +1832,39 @@
         return null;
     }
 
+
+ // ----------------------------------------------------------- Inner Classes
+
+
+ private static class IdentityArrayList<E> extends ArrayList<E> {
+
+ IdentityArrayList() {
+ super(16);
+ }
+
+ IdentityArrayList(int initialcapacity) {
+ super(initialcapacity);
+ }
+
+
+ /**
+ * Searches for the first occurence of the given argument, testing
+ * for identity equality using the <tt>==</tt>.
+ *
+ * @param elem an object.
+ *
+ * @return the index of the first occurrence of the argument in this
+ * list; returns <tt>-1</tt> if the object is not found.
+ */
+ @Override public int indexOf(Object elem) {
+ int idx = 0;
+ for (Object o : this) {
+ if (o == elem) {
+ return idx;
+ }
+ idx++;
+ }
+ return -1;
+ }
+ }
 }
Index: jsf-ri/src/com/sun/faces/application/ApplicationAssociate.java
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/src/com/sun/faces/application/ApplicationAssociate.java,v
retrieving revision 1.34
diff -u -r1.34 ApplicationAssociate.java
--- jsf-ri/src/com/sun/faces/application/ApplicationAssociate.java 14 Sep 2006 22:38:39 -0000 1.34
+++ jsf-ri/src/com/sun/faces/application/ApplicationAssociate.java 3 Oct 2006 15:21:51 -0000
@@ -359,6 +359,9 @@
 
     public ResourceBundle getResourceBundle(FacesContext context,
                                             String var) {
+ if (!resourceBundles.containsKey(var)) {
+ return null;
+ }
         UIViewRoot root = null;
         // Start out with the default locale
         Locale locale = null, defaultLocale = Locale.getDefault();
Index: jsf-ri/src/com/sun/faces/application/ConverterPropertyEditorFactory.java
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/src/com/sun/faces/application/ConverterPropertyEditorFactory.java,v
retrieving revision 1.4
diff -u -r1.4 ConverterPropertyEditorFactory.java
--- jsf-ri/src/com/sun/faces/application/ConverterPropertyEditorFactory.java 26 Sep 2006 02:39:27 -0000 1.4
+++ jsf-ri/src/com/sun/faces/application/ConverterPropertyEditorFactory.java 3 Oct 2006 15:21:51 -0000
@@ -36,6 +36,7 @@
 import java.util.Map;
 import java.util.TreeSet;
 import java.util.WeakHashMap;
+import java.util.HashMap;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.regex.Matcher;
@@ -305,6 +306,18 @@
         public String generateClassNameFor(Class<?> targetClass,
             boolean vmFormat) {
             String name = targetClass.getName();
+ if (targetClass.isArray()) {
+ int idx = name.lastIndexOf('[');
+ int bracketCount = idx + 1;
+ if (name.indexOf(';') == -1) {
+ // primitive array
+ name = PRIM_MAP.get(name.charAt(idx + 1));
+ } else {
+ // Object array
+ name = name.substring(idx + 2, name.indexOf(';'));
+ }
+ name += "Array" + bracketCount + 'd';
+ }
             Matcher m = UnderscorePattern.matcher(name);
             // Replace existing underscores with one extra underscore.
             name = m.replaceAll("$0_");
@@ -487,6 +500,19 @@
     private ClassTemplateInfo templateInfo;
     // Cache of DisposableClassLoaders keyed on the class loader of the target.
     private Map<ClassLoader, WeakReference<DisposableClassLoader>> classLoaderCache;
+
+ private static final Map<Character,String> PRIM_MAP =
+ new HashMap<Character,String>(8, 1.0f);
+ static {
+ PRIM_MAP.put('B', "byte");
+ PRIM_MAP.put('C', "char");
+ PRIM_MAP.put('S', "short");
+ PRIM_MAP.put('I', "int");
+ PRIM_MAP.put('F', "float");
+ PRIM_MAP.put('J', "long");
+ PRIM_MAP.put('D', "double");
+ PRIM_MAP.put('Z', "boolean");
+ }
 
     /**
      * Create a <code>ConverterPropertyEditorFactory</code> that uses the
Index: jsf-ri/src/com/sun/faces/application/ViewHandlerImpl.java
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/src/com/sun/faces/application/ViewHandlerImpl.java,v
retrieving revision 1.86
diff -u -r1.86 ViewHandlerImpl.java
--- jsf-ri/src/com/sun/faces/application/ViewHandlerImpl.java 20 Sep 2006 19:37:46 -0000 1.86
+++ jsf-ri/src/com/sun/faces/application/ViewHandlerImpl.java 3 Oct 2006 15:21:51 -0000
@@ -645,45 +645,49 @@
         }
 
         // Acquire the context path, which we will prefix on all results
- String contextPath =
- context.getExternalContext().getRequestContextPath();
+ ExternalContext extContext = context.getExternalContext();
+ String contextPath = extContext.getRequestContextPath();
 
         // Acquire the mapping used to execute this request (if any)
         String mapping = Util.getFacesMapping(context);
 
         // If no mapping can be identified, just return a server-relative path
         if (mapping == null) {
- return contextPath + viewId;
+ return extContext.encodeActionURL(contextPath + viewId);
         }
 
         // Deal with prefix mapping
         if (Util.isPrefixMapped(mapping)) {
             if (mapping.equals("/*")) {
- return contextPath + viewId;
+ return extContext.encodeActionURL(contextPath + viewId);
             } else {
- return contextPath + mapping + viewId;
+ return extContext
+ .encodeActionURL(contextPath + mapping + viewId);
             }
         }
 
         // Deal with extension mapping
         int period = viewId.lastIndexOf(".");
         if (period < 0) {
- return contextPath + viewId + mapping;
+ return extContext.encodeActionURL(contextPath + viewId + mapping);
         } else if (!viewId.endsWith(mapping)) {
- return contextPath + viewId.substring(0, period) + mapping;
+ return extContext.encodeActionURL(contextPath
+ + viewId.substring(0, period)
+ + mapping);
         } else {
- return contextPath + viewId;
+ return extContext.encodeActionURL(contextPath + viewId);
         }
 
     }
 
 
     public String getResourceURL(FacesContext context, String path) {
-
+ ExternalContext extContext = context.getExternalContext();
         if (path.startsWith("/")) {
- return context.getExternalContext().getRequestContextPath() + path;
+ return extContext
+ .encodeResourceURL(extContext.getRequestContextPath() + path);
         } else {
- return (path);
+ return extContext.encodeResourceURL(path);
         }
 
     }
Index: jsf-ri/src/com/sun/faces/renderkit/RenderKitUtils.java
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/src/com/sun/faces/renderkit/RenderKitUtils.java,v
retrieving revision 1.27
diff -u -r1.27 RenderKitUtils.java
--- jsf-ri/src/com/sun/faces/renderkit/RenderKitUtils.java 15 Sep 2006 17:45:54 -0000 1.27
+++ jsf-ri/src/com/sun/faces/renderkit/RenderKitUtils.java 3 Oct 2006 15:21:51 -0000
@@ -962,6 +962,18 @@
 
 
     /**
+ * @param contentType the content type in question
+ * @return <code>true</code> if the content type is a known XML-based
+ * content type, otherwise, <code>false</code>
+ */
+ public static boolean isXml(String contentType) {
+ return (RIConstants.XHTML_CONTENT_TYPE.equals(contentType)
+ || RIConstants.APPLICATION_XML_CONTENT_TYPE.equals(contentType)
+ || RIConstants.TEXT_XML_CONTENT_TYPE.equals(contentType));
+ }
+
+
+ /**
      * <p>This is a utility method for compressing multi-lined javascript.
      * In the case of {_at_link #SUN_JSF_JS} it offers about a 47% decrease
      * in length.</p>
Index: jsf-ri/src/com/sun/faces/renderkit/html_basic/HtmlResponseWriter.java
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/src/com/sun/faces/renderkit/html_basic/HtmlResponseWriter.java,v
retrieving revision 1.31
diff -u -r1.31 HtmlResponseWriter.java
--- jsf-ri/src/com/sun/faces/renderkit/html_basic/HtmlResponseWriter.java 1 Sep 2006 17:30:54 -0000 1.31
+++ jsf-ri/src/com/sun/faces/renderkit/html_basic/HtmlResponseWriter.java 3 Oct 2006 15:21:51 -0000
@@ -34,7 +34,6 @@
 import javax.faces.context.ResponseWriter;
 
 import java.io.IOException;
-import java.io.UnsupportedEncodingException;
 import java.io.Writer;
 
 import com.sun.faces.util.HtmlUtils;
@@ -106,13 +105,10 @@
         this.encoding = encoding;
 
         // Check the character encoding
- try {
- HtmlUtils.validateEncoding(encoding);
- } catch (UnsupportedEncodingException e) {
+ if (!HtmlUtils.validateEncoding(encoding)) {
             throw new IllegalArgumentException(MessageUtils.getExceptionMessageString(
- MessageUtils.ENCODING_ERROR_MESSAGE_ID));
- }
-
+ MessageUtils.ENCODING_ERROR_MESSAGE_ID));
+ }
     }
 
     // -------------------------------------------------- Methods From Closeable
Index: jsf-ri/src/com/sun/faces/util/HtmlUtils.java
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/src/com/sun/faces/util/HtmlUtils.java,v
retrieving revision 1.11
diff -u -r1.11 HtmlUtils.java
--- jsf-ri/src/com/sun/faces/util/HtmlUtils.java 24 Aug 2006 19:25:01 -0000 1.11
+++ jsf-ri/src/com/sun/faces/util/HtmlUtils.java 3 Oct 2006 15:21:52 -0000
@@ -35,12 +35,17 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.OutputStreamWriter;
-import java.io.StringWriter;
 import java.io.UnsupportedEncodingException;
 import java.io.Writer;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.BitSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
-import com.sun.faces.RIConstants;
+import com.sun.faces.renderkit.RenderKitUtils;
 
 /**
  * Utility class for HTML.
@@ -103,7 +108,10 @@
                 } else {
                     if (ch == '&') {
                         buffIndex = flushBuffer(out, buff, buffIndex);
-
+ if (((i + 1) < length) && isEscaped(text, i + 1)) {
+ out.write(ch);
+ continue;
+ }
                         out.write("&amp;");
                     } else {
                         buffIndex = addToBuffer(out, buff, buffIndex,
@@ -171,7 +179,10 @@
                 } else {
                     if (ch == '&') {
                         buffIndex = flushBuffer(out, buff, buffIndex);
-
+ if (((i + 1) < length) && isEscaped(text, i + 1)) {
+ out.write(ch);
+ continue;
+ }
                         out.write("&amp;");
                     } else {
                         buffIndex = addToBuffer(out, buff, buffIndex,
@@ -225,12 +236,12 @@
                     // If between "'" and ";", no escaping is needed
                     if (ch < 0x3c) {
                         buffIndex = addToBuffer(out, buff, buffIndex,
- buffLength, ch);
- // Note - "<" isn't escaped in attributes, as per
- // HTML spec
+ buffLength, ch);
+ } else if (ch == '<') {
+ buffIndex = flushBuffer(out, buff, buffIndex);
+ out.write("&lt;");
                     } else if (ch == '>') {
                         buffIndex = flushBuffer(out, buff, buffIndex);
-
                         out.write("&gt;");
                     } else {
                         buffIndex = addToBuffer(out, buff, buffIndex,
@@ -239,7 +250,10 @@
                 } else {
                     if (ch == '&') {
                         buffIndex = flushBuffer(out, buff, buffIndex);
-
+ if (((i + 1) < length) && isEscaped(text, i + 1)) {
+ out.write(ch);
+ continue;
+ }
                         // HTML 4.0, section B.7.1: ampersands followed by
                         // an open brace don't get escaped
                         if ((i + 1 < length) && (text.charAt(i + 1) == '{'))
@@ -313,10 +327,11 @@
                         // If between "'" and ";", no escaping is needed
                         buffIndex = addToBuffer(out, buff, buffIndex,
                                                 buffLength, ch);
- // Note - "<" isn't escaped in attributes, as per HTML spec
+ } else if (ch == '<') {
+ buffIndex = flushBuffer(out, buff, buffIndex);
+ out.write("&lt;");
                     } else if (ch == '>') {
                         buffIndex = flushBuffer(out, buff, buffIndex);
-
                         out.write("&gt;");
                     } else {
                         buffIndex = addToBuffer(out, buff, buffIndex,
@@ -325,7 +340,10 @@
                 } else {
                     if (ch == '&') {
                         buffIndex = flushBuffer(out, buff, buffIndex);
-
+ if (((i + 1) < length) && isEscaped(text, i + 1)) {
+ out.write(ch);
+ continue;
+ }
                         // HTML 4.0, section B.7.1: ampersands followed by
                         // an open brace don't get escaped
                         if ((i + 1 < end) && (text[i + 1] == '{'))
@@ -450,6 +468,107 @@
 
         return 0;
     }
+
+
+ private static final int MAX_ESCAPE_LENGTH = 7;
+
+ /**
+ * Check if a & is the beginning of an escape seqence or not.
+ */
+ private static boolean isEscaped(char[] buff, int offset) {
+ int idx = 0;
+ int maxLen = offset + MAX_ESCAPE_LENGTH;
+ int bufLen = buff.length;
+ if (maxLen > bufLen) {
+ maxLen = bufLen;
+ }
+ boolean found = false;
+ for (int i = offset; i < maxLen; i++, idx++) {
+ if (buff[i] == ';') {
+ found = true;
+ break;
+ }
+ // found another '&' before a ';' - not escaped
+ if (buff[i] == '&') {
+ return false;
+ }
+ }
+ if (found && idx >= 2) {
+ char[][] escapes = ISO8859_ENTITY_MAP.get(buff[offset]);
+ if (escapes != null) {
+ for (int i = 0; i < escapes.length; i++) {
+ boolean equal = true;
+ char[] ent = escapes[i];
+ if (ent == null) {
+ return false;
+ }
+ if (ent.length != idx) {
+ continue;
+ }
+ for (int j = 0; j < escapes[i].length; j++) {
+ if (buff[offset + j] != ent[j]) {
+ equal = false;
+ break;
+ }
+ }
+ if (equal) {
+ return equal;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Check if a & is the beginning of an escape seqence or not.
+ */
+ private static boolean isEscaped(String buff, int offset) {
+ int idx = 0;
+ int maxLen = offset + MAX_ESCAPE_LENGTH;
+ int bufLen = buff.length();
+ if (offset + MAX_ESCAPE_LENGTH > bufLen) {
+ maxLen = bufLen;
+ }
+ boolean found = false;
+ for (int i = offset; i < maxLen; i++, idx++) {
+ if (buff.charAt(i) == ';') {
+ found = true;
+ break;
+ }
+ // found another '&' before a ';' - not escaped
+ if (buff.charAt(i) == '&') {
+ return false;
+ }
+ }
+ if (found && idx >= 2) {
+ char[][] escapes = ISO8859_ENTITY_MAP.get(buff.charAt(offset));
+ if (escapes != null) {
+ for (int i = 0; i < escapes.length; i++) {
+ boolean equal = true;
+ char[] ent = escapes[i];
+ if (ent == null) {
+ return false;
+ }
+ if (ent.length != idx) {
+ continue;
+ }
+ for (int j = 0; j < escapes[i].length; j++) {
+ if (buff.charAt(offset + j) != ent[j]) {
+ equal = false;
+ break;
+ }
+ }
+ if (equal) {
+ return equal;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
 
 
     private HtmlUtils() {
@@ -520,27 +639,12 @@
             // as if it were in the request's character set. So use
             // the real encoding for those!
             else if (ch == '?') {
- out.write('?');
- //If the content type is an XML file use standard attribute rules.
- if (RIConstants.XHTML_CONTENT_TYPE.equals(contentType) ||
- RIConstants.APPLICATION_XML_CONTENT_TYPE.equals(contentType) ||
- RIConstants.TEXT_XML_CONTENT_TYPE.equals(contentType)) {
- String encodedURL = encodeURIString(text, queryEncoding, i + 1);
- //Convert all & to &amp; and all &amp%3B to &amp;
- char[] encodedURLArray = encodedURL.toCharArray();
- for(int loop = 0;loop < encodedURLArray.length;loop++) {
- if(encodedURLArray[loop] != '&') {
- out.write(encodedURLArray[loop]);
- } else if(loop+7 <= encodedURLArray.length && encodedURL.substring(loop, loop+7).equals("&amp%3B")) {
- out.write("&amp;");
- loop += 6;
- } else {
- out.write("&amp;");
- }
- }
- } else {
- out.write(encodeURIString(text, queryEncoding, i + 1));
- }
+ out.write('?');
+ encodeURIString(out,
+ text,
+ queryEncoding,
+ RenderKitUtils.isXml(contentType),
+ i + 1);
                 return;
             } else {
                 out.write(ch);
@@ -551,12 +655,13 @@
 
     // Encode a String into URI-encoded form. This code will
     // appear rather (ahem) similar to java.net.URLEncoder
- static private String encodeURIString(String text,
+ static private void encodeURIString(Writer out,
+ String text,
                                         String encoding,
+ boolean isXml,
                                         int start)
- throws IOException, UnsupportedEncodingException {
- Writer out = new StringWriter(text.length());
- ByteArrayOutputStream buf = null;
+ throws IOException, UnsupportedEncodingException {
+ MyByteArrayOutputStream buf = null;
         OutputStreamWriter writer = null;
         char[] charArray = null;
 
@@ -564,10 +669,18 @@
         for (int i = start; i < length; i++) {
             char ch = text.charAt(i);
             if (DONT_ENCODE_SET.get(ch)) {
- out.write(ch);
+ if (isXml && ch == '&') {
+ if (((i + 1) < length) && isEscaped(text, i + 1)) {
+ out.write(ch);
+ continue;
+ }
+ out.write(AMP_CHARS);
+ } else {
+ out.write(ch);
+ }
             } else {
                 if (buf == null) {
- buf = new ByteArrayOutputStream(MAX_BYTES_PER_CHAR);
+ buf = new MyByteArrayOutputStream(MAX_BYTES_PER_CHAR);
                     if (encoding != null) {
                         writer = new OutputStreamWriter(buf, encoding);
                     } else {
@@ -589,15 +702,14 @@
                     continue;
                 }
 
- byte[] ba = buf.toByteArray();
- for (int j = 0; j < ba.length; j++) {
+ byte[] ba = buf.getBuf();
+ for (int j = 0, size = buf.size(); j < size; j++) {
                     writeURIDoubleHex(out, ba[j] + 256);
                 }
 
                 buf.reset();
             }
- }
- return out.toString();
+ }
     }
 
 
@@ -621,7 +733,7 @@
     static private final BitSet DONT_ENCODE_SET = new BitSet(256);
 
 
- // See: http://www.ietf.org/rfc/rfc2396.txt
+ // See: http://www.ietf.org/rfc/rfc3986.txt
     // We're not fully along for that ride either, but we do encode
     // ' ' as '%20', and don't bother encoding '~' or '/'
     static {
@@ -642,6 +754,10 @@
         // Ditto for '+', which is an encoded space
         DONT_ENCODE_SET.set('+');
 
+ // Reserved characters from RFC 3986
+ // If a developer needs these to be available
+ // in the data set, they'll need to percent encode
+ // them manually
         DONT_ENCODE_SET.set('#');
         DONT_ENCODE_SET.set('&');
         DONT_ENCODE_SET.set('=');
@@ -655,6 +771,7 @@
         DONT_ENCODE_SET.set('!');
         DONT_ENCODE_SET.set('(');
         DONT_ENCODE_SET.set(')');
+ DONT_ENCODE_SET.set(';');
     }
 
 
@@ -759,24 +876,60 @@
         "thorn",
         "yuml"
     };
+
+ private static final Map<Character,char[][]> ISO8859_ENTITY_MAP =
+ new HashMap<Character,char[][]>();
+ static {
+ List<String> list = new ArrayList<String>();
+ list.add("amp");
+ list.add("gt");
+ list.add("lt");
+ list.add("quot");
+ list.addAll(Arrays.asList(sISO8859_1_Entities));
+ String[] entities = list.toArray(new String[list.size()]);
+ for (int i = 'a'; i <= 'z'; i++) {
+ List<char[]> l = new ArrayList<char[]>();
+ for (int e = 0; e < entities.length; e++) {
+ if (entities[e].charAt(0) == (char) i) {
+ l.add(entities[e].toCharArray());
+ }
+ }
+ if (l.size() > 0) {
+ ISO8859_ENTITY_MAP.put((char) i,
+ l.toArray(new char[l.size()][]));
+ }
+ }
+ for (int i = 'A'; i <= 'Z'; i++) {
+ List<char[]> l = new ArrayList<char[]>();
+ for (int e = 0; e < entities.length; e++) {
+ if (entities[e].charAt(0) == (char) i) {
+ l.add(entities[e].toCharArray());
+ }
+ }
+ if (l.size() > 0) {
+ ISO8859_ENTITY_MAP.put((char) i,
+ l.toArray(new char[l.size()][]));
+ }
+ }
+ }
+
 
 
     //----------------------------------------------------------
     // The following is used to verify encodings
     //----------------------------------------------------------
     //
- static public void validateEncoding(String encoding)
- throws UnsupportedEncodingException {
+ static public boolean validateEncoding(String encoding) {
         if (encoding != null) {
- // Try creating a string off of the default encoding
- new String(encodingTestBytes, encoding);
+ return Charset.isSupported(encoding);
         }
- }
-
 
- // Private array used simply to verify character encodings
- static private final byte[] encodingTestBytes = new byte[]{(byte) 65};
+ // return true if encoding is null to be compatible with the
+ // previous implementation
+ return true;
+ }
 
+
     //----------------------------------------------------------
     // The following is used to verify "empty" Html elements.
     // "Empty" Html elements are those that do not require an
@@ -843,7 +996,9 @@
 
     static private String[] pNames = new String[]{
         "param",
- };
+ };
+
+ private static final char[] AMP_CHARS = "&amp;".toCharArray();
 
 
     static {
@@ -865,5 +1020,29 @@
         emptyElementArr['M'] = mNames;
         emptyElementArr['p'] = pNames;
         emptyElementArr['P'] = pNames;
+ }
+
+
+ // ----------------------------------------------------------- Inner Classes
+
+
+ /**
+ * <p>Private implementation of ByteArrayOutputStream.</p>
+ */
+ private static class MyByteArrayOutputStream extends ByteArrayOutputStream {
+
+
+ public MyByteArrayOutputStream(int initialCapacity) {
+ super(initialCapacity);
+ }
+ /**
+ * Obtain access to the underlying byte array to prevent
+ * unecessary temp object creation.
+ * @return <code>buf</code>
+ */
+ public byte[] getBuf() {
+ return buf;
+ }
+
     }
 }
Index: jsf-ri/systest/src/com/sun/faces/jsptest/IdRefTestCase.java
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/systest/src/com/sun/faces/jsptest/IdRefTestCase.java,v
retrieving revision 1.1
diff -u -r1.1 IdRefTestCase.java
--- jsf-ri/systest/src/com/sun/faces/jsptest/IdRefTestCase.java 27 Jul 2006 22:03:41 -0000 1.1
+++ jsf-ri/systest/src/com/sun/faces/jsptest/IdRefTestCase.java 3 Oct 2006 15:21:52 -0000
@@ -147,5 +147,55 @@
         assertTrue("All cleared inputs have messages", messageMap.keySet()
                 .containsAll(Arrays.asList(testIds)));
     }
+
+ public void testIncludedLoopIdRefs() throws Exception {
+ HtmlPage page = getPage("/faces/forEach03.jsp");
+ Map inputTagsById = mapElementsByAttribute(page.getDocumentElement(),
+ "input", "id", "type", "text");
+ String[] testIds = {
+ "myform:inputId11",
+ "myform:inputId11j_id_1",
+ "myform:inputId11j_id_2"
+ };
+ for (int i = 0; i < testIds.length; i++) {
+ HtmlTextInput input = (HtmlTextInput) inputTagsById.get(testIds[i]);
+ input.setValueAttribute("");
+ }
+ List list = getAllElementsOfGivenClass(page, null,
+ HtmlSubmitInput.class);
+ HtmlSubmitInput button = (HtmlSubmitInput) list.get(0);
+ page = (HtmlPage) button.click();
+ Map messageMap = mapMessagesById(page.getDocumentElement());
+ assertEquals("One 'value required' message for each cleared input",
+ testIds.length, messageMap.size());
+ assertTrue("Only cleared inputs have messages", Arrays.asList(testIds)
+ .containsAll(messageMap.keySet()));
+ assertTrue("All cleared inputs have messages", messageMap.keySet()
+ .containsAll(Arrays.asList(testIds)));
+ }
+
+ public void testIncludeNoLoopIdRef() throws Exception {
+ HtmlPage page = getPage("/faces/forEach03.jsp");
+ Map inputTagsById = mapElementsByAttribute(page.getDocumentElement(),
+ "input", "id", "type", "text");
+ String[] testIds = {
+ "myform:Short11",
+ };
+ for (int i = 0; i < testIds.length; i++) {
+ HtmlTextInput input = (HtmlTextInput) inputTagsById.get(testIds[i]);
+ input.setValueAttribute("");
+ }
+ List list = getAllElementsOfGivenClass(page, null,
+ HtmlSubmitInput.class);
+ HtmlSubmitInput button = (HtmlSubmitInput) list.get(0);
+ page = (HtmlPage) button.click();
+ Map messageMap = mapMessagesById(page.getDocumentElement());
+ assertEquals("One 'value required' message for each cleared input",
+ testIds.length, messageMap.size());
+ assertTrue("Only cleared inputs have messages", Arrays.asList(testIds)
+ .containsAll(messageMap.keySet()));
+ assertTrue("All cleared inputs have messages", messageMap.keySet()
+ .containsAll(Arrays.asList(testIds)));
+ }
 
 }
Index: jsf-ri/systest/src/com/sun/faces/systest/render/CustomResponseWriter.java
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/systest/src/com/sun/faces/systest/render/CustomResponseWriter.java,v
retrieving revision 1.8
diff -u -r1.8 CustomResponseWriter.java
--- jsf-ri/systest/src/com/sun/faces/systest/render/CustomResponseWriter.java 24 Aug 2006 19:57:10 -0000 1.8
+++ jsf-ri/systest/src/com/sun/faces/systest/render/CustomResponseWriter.java 3 Oct 2006 15:21:52 -0000
@@ -29,17 +29,16 @@
 
 package com.sun.faces.systest.render;
 
-import com.sun.faces.util.HtmlUtils;
-import com.sun.faces.util.MessageUtils;
-
 import javax.faces.FacesException;
 import javax.faces.component.UIComponent;
 import javax.faces.context.ResponseWriter;
 
 import java.io.IOException;
-import java.io.UnsupportedEncodingException;
 import java.io.Writer;
 
+import com.sun.faces.util.HtmlUtils;
+import com.sun.faces.util.MessageUtils;
+
 
 /**
  * <p><strong>CustomResponseWriter</strong> is an Html specific implementation
@@ -95,12 +94,11 @@
         this.encoding = encoding;
 
         // Check the character encoding
- try {
- HtmlUtils.validateEncoding(encoding);
- } catch (UnsupportedEncodingException e) {
+ // Check the character encoding
+ if (!HtmlUtils.validateEncoding(encoding)) {
             throw new IllegalArgumentException(MessageUtils.getExceptionMessageString(
- MessageUtils.ENCODING_ERROR_MESSAGE_ID));
- }
+ MessageUtils.ENCODING_ERROR_MESSAGE_ID));
+ }
     }
 
 
@@ -283,7 +281,7 @@
             writer.write("=\"");
             
             // write the attribute value
- HtmlUtils.writeAttribute(writer, buffer, value.toString());
+ HtmlUtils.writeText(writer, buffer, value.toString());
             //PENDING (horwat) using String as a result of Tomcat char
             // writer ArrayIndexOutOfBoundsException (3584)
             writer.write("\"");
@@ -331,7 +329,7 @@
         
         // Javascript URLs should not be URL-encoded
         if (stringValue.startsWith("javascript:")) {
- HtmlUtils.writeAttribute(writer, buffer, stringValue);
+ HtmlUtils.writeText(writer, buffer, stringValue);
         } else {
             HtmlUtils.writeURL(writer, stringValue, encoding, getContentType());
         }
Index: jsf-ri/systest/web/forEach03.jsp
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/systest/web/forEach03.jsp,v
retrieving revision 1.1
diff -u -r1.1 forEach03.jsp
--- jsf-ri/systest/web/forEach03.jsp 27 Jul 2006 22:03:41 -0000 1.1
+++ jsf-ri/systest/web/forEach03.jsp 3 Oct 2006 15:21:52 -0000
@@ -130,6 +130,8 @@
                 </h:panelGrid>
             </h:panelGroup>
         </h:panelGrid>
+
+ <jsp:include page="forEach03Include.jsp" />
 
         <h:commandButton id="submit" value="Submit" />
     </h:form>
Index: jsf-ri/systest/web/golden/interweaving06.txt
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/systest/web/golden/interweaving06.txt,v
retrieving revision 1.4
diff -u -r1.4 interweaving06.txt
--- jsf-ri/systest/web/golden/interweaving06.txt 28 Aug 2006 14:17:32 -0000 1.4
+++ jsf-ri/systest/web/golden/interweaving06.txt 3 Oct 2006 15:21:52 -0000
@@ -29,19 +29,19 @@
   
     Array[0]:
     This component has no ID <br>
- <input id="j_id_id15j_id_1" type="text" name="j_id_id15j_id_1" value="This component has no ID " /><br>
+ <input id="j_id_id15i0" type="text" name="j_id_id15i0" value="This component has no ID " /><br>
   
     Array[1]:
     This component has no ID <br>
- <input id="j_id_id15j_id_2" type="text" name="j_id_id15j_id_2" value="This component has no ID " /><br>
+ <input id="j_id_id15i0j_id_1" type="text" name="j_id_id15i0j_id_1" value="This component has no ID " /><br>
   
     Array[2]:
     This component has no ID <br>
- <input id="j_id_id15j_id_3" type="text" name="j_id_id15j_id_3" value="This component has no ID " /><br>
+ <input id="j_id_id15i0j_id_2" type="text" name="j_id_id15i0j_id_2" value="This component has no ID " /><br>
   
     Array[3]:
     This component has no ID <br>
- <input id="j_id_id15j_id_4" type="text" name="j_id_id15j_id_4" value="This component has no ID " /><br>
+ <input id="j_id_id15i0j_id_3" type="text" name="j_id_id15i0j_id_3" value="This component has no ID " /><br>
   
 
 </p>
Index: jsf-ri/systest/web/golden/interweaving07.txt
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/systest/web/golden/interweaving07.txt,v
retrieving revision 1.4
diff -u -r1.4 interweaving07.txt
--- jsf-ri/systest/web/golden/interweaving07.txt 28 Aug 2006 14:17:33 -0000 1.4
+++ jsf-ri/systest/web/golden/interweaving07.txt 3 Oct 2006 15:21:52 -0000
@@ -29,19 +29,19 @@
   
     Array[0]:
     This component has no ID <br>
- <input id="j_id_id15j_id_1" type="text" name="j_id_id15j_id_1" value="This component has no ID " /><br>
+ <input id="j_id_id15i0" type="text" name="j_id_id15i0" value="This component has no ID " /><br>
   
     Array[1]:
     This component has no ID <br>
- <input id="j_id_id15j_id_2" type="text" name="j_id_id15j_id_2" value="This component has no ID " /><br>
+ <input id="j_id_id15i0j_id_1" type="text" name="j_id_id15i0j_id_1" value="This component has no ID " /><br>
   
     Array[2]:
     This component has no ID <br>
- <input id="j_id_id15j_id_3" type="text" name="j_id_id15j_id_3" value="This component has no ID " /><br>
+ <input id="j_id_id15i0j_id_2" type="text" name="j_id_id15i0j_id_2" value="This component has no ID " /><br>
   
     Array[3]:
     This component has no ID <br>
- <input id="j_id_id15j_id_4" type="text" name="j_id_id15j_id_4" value="This component has no ID " /><br>
+ <input id="j_id_id15i0j_id_3" type="text" name="j_id_id15i0j_id_3" value="This component has no ID " /><br>
   
 
 </p>
Index: jsf-ri/systest/web/golden/subview05.txt
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/systest/web/golden/subview05.txt,v
retrieving revision 1.8
diff -u -r1.8 subview05.txt
--- jsf-ri/systest/web/golden/subview05.txt 28 Aug 2006 14:17:33 -0000 1.8
+++ jsf-ri/systest/web/golden/subview05.txt 3 Oct 2006 15:21:52 -0000
@@ -30,19 +30,19 @@
   
     Array[0]:
     This component has no ID <br>
- <input id="subviewInner:j_id_id17j_id_1" type="text" name="subviewInner:j_id_id17j_id_1" value="This component has no ID " /><br>
+ <input id="subviewInner:j_id_id17i0" type="text" name="subviewInner:j_id_id17i0" value="This component has no ID " /><br>
   
     Array[1]:
     This component has no ID <br>
- <input id="subviewInner:j_id_id17j_id_2" type="text" name="subviewInner:j_id_id17j_id_2" value="This component has no ID " /><br>
+ <input id="subviewInner:j_id_id17i0j_id_1" type="text" name="subviewInner:j_id_id17i0j_id_1" value="This component has no ID " /><br>
   
     Array[2]:
     This component has no ID <br>
- <input id="subviewInner:j_id_id17j_id_3" type="text" name="subviewInner:j_id_id17j_id_3" value="This component has no ID " /><br>
+ <input id="subviewInner:j_id_id17i0j_id_2" type="text" name="subviewInner:j_id_id17i0j_id_2" value="This component has no ID " /><br>
   
     Array[3]:
     This component has no ID <br>
- <input id="subviewInner:j_id_id17j_id_4" type="text" name="subviewInner:j_id_id17j_id_4" value="This component has no ID " /><br>
+ <input id="subviewInner:j_id_id17i0j_id_3" type="text" name="subviewInner:j_id_id17i0j_id_3" value="This component has no ID " /><br>
   
 
 
Index: jsf-ri/systest/web/golden/subview06.txt
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/systest/web/golden/subview06.txt,v
retrieving revision 1.10
diff -u -r1.10 subview06.txt
--- jsf-ri/systest/web/golden/subview06.txt 28 Aug 2006 14:17:33 -0000 1.10
+++ jsf-ri/systest/web/golden/subview06.txt 3 Oct 2006 15:21:52 -0000
@@ -31,19 +31,19 @@
   
     Array[0]:
     This component has no ID <br>
- <input id="subviewOuter:subviewInner:j_id_id17j_id_1" type="text" name="subviewOuter:subviewInner:j_id_id17j_id_1" value="This component has no ID " /><br>
+ <input id="subviewOuter:subviewInner:j_id_id17i0" type="text" name="subviewOuter:subviewInner:j_id_id17i0" value="This component has no ID " /><br>
   
     Array[1]:
     This component has no ID <br>
- <input id="subviewOuter:subviewInner:j_id_id17j_id_2" type="text" name="subviewOuter:subviewInner:j_id_id17j_id_2" value="This component has no ID " /><br>
+ <input id="subviewOuter:subviewInner:j_id_id17i0j_id_1" type="text" name="subviewOuter:subviewInner:j_id_id17i0j_id_1" value="This component has no ID " /><br>
   
     Array[2]:
     This component has no ID <br>
- <input id="subviewOuter:subviewInner:j_id_id17j_id_3" type="text" name="subviewOuter:subviewInner:j_id_id17j_id_3" value="This component has no ID " /><br>
+ <input id="subviewOuter:subviewInner:j_id_id17i0j_id_2" type="text" name="subviewOuter:subviewInner:j_id_id17i0j_id_2" value="This component has no ID " /><br>
   
     Array[3]:
     This component has no ID <br>
- <input id="subviewOuter:subviewInner:j_id_id17j_id_4" type="text" name="subviewOuter:subviewInner:j_id_id17j_id_4" value="This component has no ID " /><br>
+ <input id="subviewOuter:subviewInner:j_id_id17i0j_id_3" type="text" name="subviewOuter:subviewInner:j_id_id17i0j_id_3" value="This component has no ID " /><br>
   
 
 
Index: jsf-ri/test/com/sun/faces/application/TestViewHandlerImpl.java
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/test/com/sun/faces/application/TestViewHandlerImpl.java,v
retrieving revision 1.34
diff -u -r1.34 TestViewHandlerImpl.java
--- jsf-ri/test/com/sun/faces/application/TestViewHandlerImpl.java 15 Aug 2006 17:19:05 -0000 1.34
+++ jsf-ri/test/com/sun/faces/application/TestViewHandlerImpl.java 3 Oct 2006 15:21:52 -0000
@@ -235,7 +235,7 @@
         testRequest.setAttribute("com.sun.faces.INVOCATION_PATH", null);
         String path = handler.getActionURL(facesContext, "/path/test.jsp");
         System.out.println("VIEW ID PATH 2: " + path);
- assertEquals(contextPath + "/faces/path/test.jsp", path);
+ assertEquals(contextPath + "/faces/path/test.jsp", path.substring(0, path.indexOf(";j")));
 
 
         // if getServletPath() returns a path indicating extension mapping
@@ -246,7 +246,7 @@
         testRequest.setAttribute("com.sun.faces.INVOCATION_PATH", null);
         path = handler.getActionURL(facesContext, "/path/test");
         System.out.println("VIEW ID PATH 3: " + path);
- assertEquals(contextPath + "/path/test.jsf", path);
+ assertEquals(contextPath + "/path/test.jsf", path.substring(0, path.indexOf(";j")));
 
         // if getServletPath() returns a path indicating extension mapping
         // and the viewId passed has an extension, replace the extension with
@@ -256,7 +256,7 @@
         testRequest.setAttribute("com.sun.faces.INVOCATION_PATH", null);
         path = handler.getActionURL(facesContext, "/path/t.est.jsp");
         System.out.println("VIEW ID PATH 4: " + path);
- assertEquals(contextPath + "/path/t.est.jsf", path);
+ assertEquals(contextPath + "/path/t.est.jsf", path.substring(0, path.indexOf(";j")));
 
         // if path info is null, the impl must check to see if
         // there is an exact match on the servlet path, if so, return
@@ -266,7 +266,7 @@
         testRequest.setAttribute("com.sun.faces.INVOCATION_PATH", null);
         path = handler.getActionURL(facesContext, "/path/t.est");
         System.out.println("VIEW ID PATH 5: " + path);
- assertEquals(contextPath + "/faces/path/t.est", path);
+ assertEquals(contextPath + "/faces/path/t.est", path.substring(0, path.indexOf(";j")));
 
     }
 
@@ -313,12 +313,14 @@
             new FacesContextImpl(extContext, lifecycle);
 
         // Validate correct calculations
+ String path = Util.getViewHandler(getFacesContext()).
+ getResourceURL(context, "/index.jsp");
         assertEquals(request.getContextPath() + "/index.jsp",
- Util.getViewHandler(getFacesContext()).
- getResourceURL(context, "/index.jsp"));
+ path.substring(0, path.indexOf(";j")));
+ path = Util.getViewHandler(getFacesContext()).
+ getResourceURL(context, "index.jsp");
         assertEquals("index.jsp",
- Util.getViewHandler(getFacesContext()).
- getResourceURL(context, "index.jsp"));
+ path.substring(0, path.indexOf(";j")));
 
     }
 
Index: jsf-ri/test/com/sun/faces/util/TestHtmlUtils.java
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/test/com/sun/faces/util/TestHtmlUtils.java,v
retrieving revision 1.2
diff -u -r1.2 TestHtmlUtils.java
--- jsf-ri/test/com/sun/faces/util/TestHtmlUtils.java 24 Aug 2006 19:25:01 -0000 1.2
+++ jsf-ri/test/com/sun/faces/util/TestHtmlUtils.java 3 Oct 2006 15:21:52 -0000
@@ -53,24 +53,24 @@
                 //Test URL with two params
                 testURLEncoding("http://www.google.com?joe=10&fred=20", "http://www.google.com?joe=10&fred=20", "http://www.google.com?joe=10&amp;fred=20");
                 //Test URL with & entity encoded
- testURLEncoding("/index.jsf?joe=10&amp;fred=20", "/index.jsf?joe=10&amp%3Bfred=20", "/index.jsf?joe=10&amp;fred=20");
+ testURLEncoding("/index.jsf?joe=10&amp;fred=20", "/index.jsf?joe=10&amp;fred=20", "/index.jsf?joe=10&amp;fred=20");
                 //Test URL with two params and second & close to end of string
                 testURLEncoding("/index.jsf?joe=10&f=20", "/index.jsf?joe=10&f=20", "/index.jsf?joe=10&amp;f=20");
                 //Test URL with misplaced & expected behavior but not necissarily right.
                 testURLEncoding("/index.jsf?joe=10&f=20&", "/index.jsf?joe=10&f=20&", "/index.jsf?joe=10&amp;f=20&amp;");
                 //Test URL with encoded entity at end of URL expected behavior but not necissarily right.
- testURLEncoding("/index.jsf?joe=10&f=20&amp;", "/index.jsf?joe=10&f=20&amp%3B", "/index.jsf?joe=10&amp;f=20&amp;");
+ testURLEncoding("/index.jsf?joe=10&f=20&amp;", "/index.jsf?joe=10&f=20&amp;", "/index.jsf?joe=10&amp;f=20&amp;");
         }
         
         private void testURLEncoding(String urlToEncode, String expectedHTML, String expectedXML) throws UnsupportedEncodingException, IOException {
                 char[] buffer = new char[1024];
                 StringWriter xmlWriter = new StringWriter();
                 HtmlUtils.writeURL(xmlWriter, urlToEncode, "UTF-8", RIConstants.XHTML_CONTENT_TYPE);
-// System.out.println(xmlWriter.toString());
+ System.out.println("XML: " + xmlWriter.toString());
                 assertEquals(xmlWriter.toString(), expectedXML);
                 StringWriter htmlWriter = new StringWriter();
                 HtmlUtils.writeURL(htmlWriter, urlToEncode, "UTF-8", RIConstants.HTML_CONTENT_TYPE);
-// System.out.println(htmlWriter.toString());
+ System.out.println("HTML: " +htmlWriter.toString());
                 assertEquals(htmlWriter.toString(), expectedHTML);
         }
 
Index: jsf-tools/template-src/TypedCollections.java
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-tools/template-src/TypedCollections.java,v
retrieving revision 1.1
diff -u -r1.1 TypedCollections.java
--- jsf-tools/template-src/TypedCollections.java 25 Aug 2006 09:50:19 -0000 1.1
+++ jsf-tools/template-src/TypedCollections.java 3 Oct 2006 15:21:52 -0000
@@ -48,16 +48,14 @@
      */
     @SuppressWarnings("unchecked")
     @protection@ static <E,TypedC extends Collection<E>> TypedC dynamicallyCastCollection(Collection<?> c,
- Class<E> type, Class<TypedC> collectionType) {
- if (c == null)
+ Class<E> type,
+ Class<TypedC> collectionType) {
+ if (c == null)
             return null;
         if (!collectionType.isInstance(c))
             throw new ClassCastException(c.getClass().getName());
- for (Object element : c) {
- if (element != null && !type.isInstance(element))
- throw new ClassCastException(element.getClass().getName());
- }
- return collectionType.cast(c);
+
+ return collectionType.cast(c);
     }
 
     /**
@@ -75,7 +73,7 @@
      */
     @SuppressWarnings("unchecked")
     @protection@ static <E> List<E> dynamicallyCastList(List<?> list, Class<E> type) {
- return dynamicallyCastCollection(list, type, List.class);
+ return dynamicallyCastCollection(list, type, List.class);
     }
 
     /**
@@ -92,8 +90,9 @@
      * @throws java.lang.ClassCastException
      */
     @SuppressWarnings("unchecked")
- @protection@ static <E> Set<E> dynamicallyCastSet(Set<?> set, Class<E> type) {
- return dynamicallyCastCollection(set, type, Set.class);
+ @protection@ static <E> Set<E> dynamicallyCastSet(Set<?> set,
+ Class<E> type) {
+ return dynamicallyCastCollection(set, type, Set.class);
     }
 
     /**
@@ -115,16 +114,11 @@
      */
     @SuppressWarnings("unchecked")
     @protection@ static <K, V> Map<K, V> dynamicallyCastMap(Map<?, ?> map,
- Class<K> keyType, Class<V> valueType) {
- if (map != null) {
- for (Map.Entry<?, ?> entry : map.entrySet()) {
- if (entry.getKey() != null && !keyType.isInstance(entry.getKey()))
- throw new ClassCastException(entry.getKey().getClass().getName());
- if (entry.getValue() != null
- && !valueType.isInstance(entry.getValue()))
- throw new ClassCastException(entry.getValue().getClass().getName());
- }
- }
- return (Map<K, V>) map;
+ Class<K> keyType,
+ Class<V> valueType) {
+ if (map == null) {
+ return null;
+ }
+ return (Map<K, V>) map;
     }
 }


SECTION: New Files
----------------------------
SEE ATTACHMENTS