You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by mm...@apache.org on 2007/10/26 11:19:57 UTC
svn commit: r588578 - in /myfaces:
core/branches/1_2_1/api/src/main/java/javax/faces/component/
core/branches/1_2_1/impl/src/main/java/org/apache/myfaces/application/
core/branches/1_2_1/impl/src/main/java/org/apache/myfaces/el/unified/resolver/implici...
Author: mmarinschek
Date: Fri Oct 26 02:19:56 2007
New Revision: 588578
URL: http://svn.apache.org/viewvc?rev=588578&view=rev
Log:
https://issues.apache.org/jira/browse/MYFACES-1749 (MYFACES-1749): Performance Improvements. Thanks to Michael Kurz.
Added:
myfaces/shared/branches/3_0_1/core/src/test/java/org/apache/myfaces/shared/renderkit/
myfaces/shared/branches/3_0_1/core/src/test/java/org/apache/myfaces/shared/renderkit/html/
myfaces/shared/branches/3_0_1/core/src/test/java/org/apache/myfaces/shared/renderkit/html/util/
myfaces/shared/branches/3_0_1/core/src/test/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoderTest.java
Modified:
myfaces/core/branches/1_2_1/api/src/main/java/javax/faces/component/UIComponentBase.java
myfaces/core/branches/1_2_1/api/src/main/java/javax/faces/component/_ComponentAttributesMap.java
myfaces/core/branches/1_2_1/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java
myfaces/core/branches/1_2_1/impl/src/main/java/org/apache/myfaces/el/unified/resolver/implicitobject/ImplicitObjectResolver.java
myfaces/shared/branches/3_0_1/core/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlResponseWriterImpl.java
myfaces/shared/branches/3_0_1/core/src/main/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoder.java
myfaces/shared/branches/3_0_1/core/src/main/java/org/apache/myfaces/shared/renderkit/html/util/UnicodeEncoder.java
Modified: myfaces/core/branches/1_2_1/api/src/main/java/javax/faces/component/UIComponentBase.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/1_2_1/api/src/main/java/javax/faces/component/UIComponentBase.java?rev=588578&r1=588577&r2=588578&view=diff
==============================================================================
--- myfaces/core/branches/1_2_1/api/src/main/java/javax/faces/component/UIComponentBase.java (original)
+++ myfaces/core/branches/1_2_1/api/src/main/java/javax/faces/component/UIComponentBase.java Fri Oct 26 02:19:56 2007
@@ -1078,20 +1078,23 @@
throw new IllegalArgumentException("component identifier must not be a zero-length String");
}
- //let's look at all chars inside of the ID if it is a valid ID!
- char[] chars = string.toCharArray();
-
+ // If new id is the same as old it must be valid
+ if (string.equals(_id)) {
+ return;
+ }
+
//2. First character must be a letter or an underscore ('_').
- if(!Character.isLetter(chars[0]) && chars[0] !='_')
+ if(!Character.isLetter(string.charAt(0)) && string.charAt(0) !='_')
{
- throw new IllegalArgumentException("component identifier's first character must be a letter or an underscore ('_')! But it is \""+chars[0]+"\"");
+ throw new IllegalArgumentException("component identifier's first character must be a letter or an underscore ('_')! But it is \""+string.charAt(0)+"\"");
}
- for (int i = 1; i < chars.length; i++)
+ for (int i = 1; i < string.length(); i++)
{
+ char c = string.charAt(i);
//3. Subsequent characters must be a letter, a digit, an underscore ('_'), or a dash ('-').
- if(!Character.isDigit(chars[i]) && !Character.isLetter(chars[i]) && chars[i] !='-' && chars[i] !='_')
+ if(!Character.isLetterOrDigit(c) && c !='-' && c !='_')
{
- throw new IllegalArgumentException("Subsequent characters of component identifier must be a letter, a digit, an underscore ('_'), or a dash ('-')! But component identifier contains \""+chars[i]+"\"");
+ throw new IllegalArgumentException("Subsequent characters of component identifier must be a letter, a digit, an underscore ('_'), or a dash ('-')! But component identifier contains \""+c+"\"");
}
}
}
Modified: myfaces/core/branches/1_2_1/api/src/main/java/javax/faces/component/_ComponentAttributesMap.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/1_2_1/api/src/main/java/javax/faces/component/_ComponentAttributesMap.java?rev=588578&r1=588577&r2=588578&view=diff
==============================================================================
--- myfaces/core/branches/1_2_1/api/src/main/java/javax/faces/component/_ComponentAttributesMap.java (original)
+++ myfaces/core/branches/1_2_1/api/src/main/java/javax/faces/component/_ComponentAttributesMap.java Fri Oct 26 02:19:56 2007
@@ -26,6 +26,7 @@
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
+import java.util.WeakHashMap;
import javax.el.ValueExpression;
import javax.faces.FacesException;
@@ -70,6 +71,9 @@
// it can always be recreated when needed.
private transient Map<String, PropertyDescriptor> _propertyDescriptorMap = null;
+ // Cache for component property descriptors
+ private static Map<Class, Map<String, PropertyDescriptor>> _propertyDescriptorCache = new WeakHashMap<Class, Map<String,PropertyDescriptor>>();
+
/**
* Create a map backed by the specified component.
* <p>
@@ -330,27 +334,36 @@
{
if (_propertyDescriptorMap == null)
{
- BeanInfo beanInfo;
- try
- {
- beanInfo = Introspector.getBeanInfo(_component.getClass());
- }
- catch (IntrospectionException e)
- {
- throw new FacesException(e);
- }
- PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
- _propertyDescriptorMap = new HashMap<String, PropertyDescriptor>();
- for (int i = 0; i < propertyDescriptors.length; i++)
- {
- PropertyDescriptor propertyDescriptor = propertyDescriptors[i];
- if (propertyDescriptor.getReadMethod() != null)
+ // Try to get descriptor map from cache
+ _propertyDescriptorMap = _propertyDescriptorCache.get(_component.getClass());
+ // Cache miss: create descriptor map and put it in cache
+ if (_propertyDescriptorMap == null)
+ {
+ // Create descriptor map...
+ BeanInfo beanInfo;
+ try
{
- _propertyDescriptorMap.put(propertyDescriptor.getName(),
- propertyDescriptor);
+ beanInfo = Introspector.getBeanInfo(_component.getClass());
}
- }
- }
+ catch (IntrospectionException e)
+ {
+ throw new FacesException(e);
+ }
+ PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
+ _propertyDescriptorMap = new HashMap<String, PropertyDescriptor>();
+ for (int i = 0; i < propertyDescriptors.length; i++)
+ {
+ PropertyDescriptor propertyDescriptor = propertyDescriptors[i];
+ if (propertyDescriptor.getReadMethod() != null)
+ {
+ _propertyDescriptorMap.put(propertyDescriptor.getName(),
+ propertyDescriptor);
+ }
+ }
+ // ... and put it in cache
+ _propertyDescriptorCache.put(_component.getClass(), _propertyDescriptorMap);
+ }
+ }
return _propertyDescriptorMap.get(key);
}
Modified: myfaces/core/branches/1_2_1/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/1_2_1/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java?rev=588578&r1=588577&r2=588578&view=diff
==============================================================================
--- myfaces/core/branches/1_2_1/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java (original)
+++ myfaces/core/branches/1_2_1/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java Fri Oct 26 02:19:56 2007
@@ -19,11 +19,11 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
+import java.util.concurrent.ConcurrentHashMap;
import javax.el.CompositeELResolver;
import javax.el.ELContext;
@@ -106,14 +106,12 @@
private ArrayList<ELContextListener> _elContextListeners;
// components, converters, and validators can be added at runtime--must
- // synchronize
- private final Map<String, Class> _converterIdToClassMap = Collections.synchronizedMap(new HashMap<String, Class>());
- private final Map<Class, String> _converterClassNameToClassMap = Collections
- .synchronizedMap(new HashMap<Class, String>());
- private final Map<String, org.apache.myfaces.config.impl.digester.elements.Converter> _converterClassNameToConfigurationMap = Collections
- .synchronizedMap(new HashMap<String, org.apache.myfaces.config.impl.digester.elements.Converter>());
- private final Map<String, Class> _componentClassMap = Collections.synchronizedMap(new HashMap<String, Class>());
- private final Map<String, Class> _validatorClassMap = Collections.synchronizedMap(new HashMap<String, Class>());
+ // synchronize, uses ConcurrentHashMap to allow concurrent read of map
+ private final Map<String, Class> _converterIdToClassMap = new ConcurrentHashMap<String, Class>();
+ private final Map<Class, String> _converterClassNameToClassMap = new ConcurrentHashMap<Class, String>();
+ private final Map<String, org.apache.myfaces.config.impl.digester.elements.Converter> _converterClassNameToConfigurationMap = new ConcurrentHashMap<String, org.apache.myfaces.config.impl.digester.elements.Converter>();
+ private final Map<String, Class> _componentClassMap = new ConcurrentHashMap<String, Class>();
+ private final Map<String, Class> _validatorClassMap = new ConcurrentHashMap<String, Class>();
private final RuntimeConfig _runtimeConfig;
@@ -627,11 +625,7 @@
checkNull(componentType, "componentType");
checkEmpty(componentType, "componentType");
- Class componentClass;
- synchronized (_componentClassMap)
- {
- componentClass = _componentClassMap.get(componentType);
- }
+ Class componentClass = _componentClassMap.get(componentType);
if (componentClass == null)
{
log.error("Undefined component type " + componentType);
Modified: myfaces/core/branches/1_2_1/impl/src/main/java/org/apache/myfaces/el/unified/resolver/implicitobject/ImplicitObjectResolver.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/1_2_1/impl/src/main/java/org/apache/myfaces/el/unified/resolver/implicitobject/ImplicitObjectResolver.java?rev=588578&r1=588577&r2=588578&view=diff
==============================================================================
--- myfaces/core/branches/1_2_1/impl/src/main/java/org/apache/myfaces/el/unified/resolver/implicitobject/ImplicitObjectResolver.java (original)
+++ myfaces/core/branches/1_2_1/impl/src/main/java/org/apache/myfaces/el/unified/resolver/implicitobject/ImplicitObjectResolver.java Fri Oct 26 02:19:56 2007
@@ -19,8 +19,9 @@
import javax.el.*;
import java.beans.FeatureDescriptor;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.Iterator;
-import java.util.List;
+import java.util.Map;
/**
* See JSF 1.2 spec sections 5.6.1.1 and 5.6.2.1
@@ -29,16 +30,18 @@
*/
public class ImplicitObjectResolver extends ELResolver {
- private List<ImplicitObject> implicitObjects;
+ private Map<String, ImplicitObject> implicitObjects;
/**
* Static factory for an ELResolver for resolving implicit objects in JSPs.
* See JSF 1.2 spec section 5.6.1.1
*/
public static ELResolver makeResolverForJSP() {
- List<ImplicitObject> forJSPList = new ArrayList<ImplicitObject>(2);
- forJSPList.add(new FacesContextImplicitObject());
- forJSPList.add(new ViewImplicitObject());
+ Map<String, ImplicitObject> forJSPList = new HashMap<String, ImplicitObject>(2);
+ ImplicitObject io1 = new FacesContextImplicitObject();
+ forJSPList.put(io1.getName(), io1);
+ ImplicitObject io2 = new ViewImplicitObject();
+ forJSPList.put(io2.getName(), io2);
return new ImplicitObjectResolver(forJSPList);
}
@@ -47,32 +50,46 @@
* See JSF 1.2 spec section 5.6.1.2
*/
public static ELResolver makeResolverForFaces() {
- List<ImplicitObject> forFacesList = new ArrayList<ImplicitObject>(14);
- forFacesList.add(new ApplicationImplicitObject());
- forFacesList.add(new ApplicationScopeImplicitObject());
- forFacesList.add(new CookieImplicitObject());
- forFacesList.add(new FacesContextImplicitObject());
- forFacesList.add(new HeaderImplicitObject());
- forFacesList.add(new HeaderValuesImplicitObject());
- forFacesList.add(new InitParamImplicitObject());
- forFacesList.add(new ParamImplicitObject());
- forFacesList.add(new ParamValuesImplicitObject());
- forFacesList.add(new RequestImplicitObject());
- forFacesList.add(new RequestScopeImplicitObject());
- forFacesList.add(new SessionImplicitObject());
- forFacesList.add(new SessionScopeImplicitObject());
- forFacesList.add(new ViewImplicitObject());
+ Map<String, ImplicitObject> forFacesList = new HashMap<String, ImplicitObject>(14);
+ ImplicitObject io1 = new ApplicationImplicitObject();
+ forFacesList.put(io1.getName(), io1);
+ ImplicitObject io2 = new ApplicationScopeImplicitObject();
+ forFacesList.put(io2.getName(), io2);
+ ImplicitObject io3 = new CookieImplicitObject();
+ forFacesList.put(io3.getName(), io3);
+ ImplicitObject io4 = new FacesContextImplicitObject();
+ forFacesList.put(io4.getName(), io4);
+ ImplicitObject io5 = new HeaderImplicitObject();
+ forFacesList.put(io5.getName(), io5);
+ ImplicitObject io6 = new HeaderValuesImplicitObject();
+ forFacesList.put(io6.getName(), io6);
+ ImplicitObject io7 = new InitParamImplicitObject();
+ forFacesList.put(io7.getName(), io7);
+ ImplicitObject io8 = new ParamImplicitObject();
+ forFacesList.put(io8.getName(), io8);
+ ImplicitObject io9 = new ParamValuesImplicitObject();
+ forFacesList.put(io9.getName(), io9);
+ ImplicitObject io10 = new RequestImplicitObject();
+ forFacesList.put(io10.getName(), io10);
+ ImplicitObject io11 = new RequestScopeImplicitObject();
+ forFacesList.put(io11.getName(), io11);
+ ImplicitObject io12 = new SessionImplicitObject();
+ forFacesList.put(io12.getName(), io12);
+ ImplicitObject io13 = new SessionScopeImplicitObject();
+ forFacesList.put(io13.getName(), io13);
+ ImplicitObject io14 = new ViewImplicitObject();
+ forFacesList.put(io14.getName(), io14);
return new ImplicitObjectResolver(forFacesList);
}
private ImplicitObjectResolver() {
super();
- this.implicitObjects = new ArrayList<ImplicitObject>();
+ this.implicitObjects = new HashMap<String, ImplicitObject>();
}
/** Creates a new instance of ImplicitObjectResolverForJSP */
- private ImplicitObjectResolver(List<ImplicitObject> implicitObjects) {
+ private ImplicitObjectResolver(Map<String, ImplicitObject> implicitObjects) {
this();
this.implicitObjects = implicitObjects;
}
@@ -86,10 +103,8 @@
String strProperty = castAndIntern(property);
- for (ImplicitObject obj: implicitObjects) {
- if (strProperty.equals(obj.getName())) {
- throw new PropertyNotWritableException();
- }
+ if (implicitObjects.containsKey(strProperty)) {
+ throw new PropertyNotWritableException();
}
}
@@ -102,11 +117,9 @@
String strProperty = castAndIntern(property);
- for (ImplicitObject obj: implicitObjects) {
- if (strProperty.equals(obj.getName())) {
- context.setPropertyResolved(true);
- return true;
- }
+ if (implicitObjects.containsKey(strProperty)) {
+ context.setPropertyResolved(true);
+ return true;
}
return false;
@@ -121,11 +134,10 @@
String strProperty = castAndIntern(property);
- for (ImplicitObject obj : implicitObjects) {
- if (strProperty.equals(obj.getName())) {
- context.setPropertyResolved(true);
- return obj.getValue(context);
- }
+ ImplicitObject obj = implicitObjects.get(strProperty);
+ if (obj != null) {
+ context.setPropertyResolved(true);
+ return obj.getValue(context);
}
return null;
@@ -140,10 +152,8 @@
String strProperty = castAndIntern(property);
- for (ImplicitObject obj: implicitObjects) {
- if (strProperty.equals(obj.getName())) {
- context.setPropertyResolved(true);
- }
+ if (implicitObjects.containsKey(strProperty)) {
+ context.setPropertyResolved(true);
}
return null;
@@ -154,7 +164,7 @@
ArrayList<FeatureDescriptor> descriptors = new ArrayList<FeatureDescriptor>(implicitObjects.size());
- for (ImplicitObject obj: implicitObjects) {
+ for (ImplicitObject obj: implicitObjects.values()) {
descriptors.add(obj.getDescriptor());
}
Modified: myfaces/shared/branches/3_0_1/core/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlResponseWriterImpl.java
URL: http://svn.apache.org/viewvc/myfaces/shared/branches/3_0_1/core/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlResponseWriterImpl.java?rev=588578&r1=588577&r2=588578&view=diff
==============================================================================
--- myfaces/shared/branches/3_0_1/core/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlResponseWriterImpl.java (original)
+++ myfaces/shared/branches/3_0_1/core/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlResponseWriterImpl.java Fri Oct 26 02:19:56 2007
@@ -449,16 +449,12 @@
else if (isTextarea())
{
// For textareas we must *not* map successive spaces to   or Newlines to <br/>
- // TODO: Make HTMLEncoder support char arrays directly
- String strValue = new String(cbuf, off, len);
- _writer.write(org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder.encode(strValue, false, false, !UTF8.equals(_characterEncoding)));
+ org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder.encode(cbuf, off, len, false, false, !UTF8.equals(_characterEncoding), _writer);
}
else
{
// We map successive spaces to and Newlines to <br/>
- // TODO: Make HTMLEncoder support char arrays directly
- String strValue = new String(cbuf, off, len);
- _writer.write(org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder.encode(strValue, true, true, !UTF8.equals(_characterEncoding)));
+ org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder.encode(cbuf, off, len, true, true, !UTF8.equals(_characterEncoding), _writer);
}
}
Modified: myfaces/shared/branches/3_0_1/core/src/main/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoder.java
URL: http://svn.apache.org/viewvc/myfaces/shared/branches/3_0_1/core/src/main/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoder.java?rev=588578&r1=588577&r2=588578&view=diff
==============================================================================
--- myfaces/shared/branches/3_0_1/core/src/main/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoder.java (original)
+++ myfaces/shared/branches/3_0_1/core/src/main/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoder.java Fri Oct 26 02:19:56 2007
@@ -18,6 +18,9 @@
*/
package org.apache.myfaces.shared.renderkit.html.util;
+import java.io.IOException;
+import java.io.Writer;
+
/**
* Converts Strings so that they can be used within HTML-Code.
*/
@@ -64,68 +67,67 @@
return "";
}
- StringBuffer sb = null; //create later on demand
+ StringBuilder sb = null; //create later on demand
String app;
char c;
for (int i = 0; i < string.length (); ++i)
{
app = null;
c = string.charAt(i);
- switch (c)
+
+ // All characters before letters
+ if ((int)c < 0x41)
{
- case '"': app = """; break; //"
- case '&': app = "&"; break; //&
- case '<': app = "<"; break; //<
- case '>': app = ">"; break; //>
- case ' ':
- if (encodeSubsequentBlanksToNbsp &&
- (i == 0 || (i - 1 >= 0 && string.charAt(i - 1) == ' ')))
- {
- //Space at beginning or after another space
- app = " ";
- }
- break;
- case '\n':
- if (encodeNewline)
- {
- app = "<br/>";
- }
- break;
-
-
- default:
- if (encodeNonLatin) switch(c) {
- //german umlauts
- case '\u00E4' : app = "ä"; break;
- case '\u00C4' : app = "Ä"; break;
- case '\u00F6' : app = "ö"; break;
- case '\u00D6' : app = "Ö"; break;
- case '\u00FC' : app = "ü"; break;
- case '\u00DC' : app = "Ü"; break;
- case '\u00DF' : app = "ß"; break;
-
- //misc
- //case 0x80: app = "€"; break; sometimes euro symbol is ascii 128, should we suport it?
- case '\u20AC': app = "€"; break;
- case '\u00AB': app = "«"; break;
- case '\u00BB': app = "»"; break;
- case '\u00A0': app = " "; break;
-
- default :
- if (((int)c) >= 0x80)
- {
- //encode all non basic latin characters
- app = "&#" + ((int)c) + ";";
- }
- break;
- }
- break;
+ switch (c)
+ {
+ case '"': app = """; break; //"
+ case '&': app = "&"; break; //&
+ case '<': app = "<"; break; //<
+ case '>': app = ">"; break; //>
+ case ' ':
+ if (encodeSubsequentBlanksToNbsp &&
+ (i == 0 || (i - 1 >= 0 && string.charAt(i - 1) == ' ')))
+ {
+ //Space at beginning or after another space
+ app = " ";
+ }
+ break;
+ case '\n':
+ if (encodeNewline)
+ {
+ app = "<br/>";
+ }
+ break;
+ }
+ } else if (encodeNonLatin && (int)c > 0x80) {
+ switch(c) {
+ //german umlauts
+ case '\u00E4' : app = "ä"; break;
+ case '\u00C4' : app = "Ä"; break;
+ case '\u00F6' : app = "ö"; break;
+ case '\u00D6' : app = "Ö"; break;
+ case '\u00FC' : app = "ü"; break;
+ case '\u00DC' : app = "Ü"; break;
+ case '\u00DF' : app = "ß"; break;
+
+ //misc
+ //case 0x80: app = "€"; break; sometimes euro symbol is ascii 128, should we suport it?
+ case '\u20AC': app = "€"; break;
+ case '\u00AB': app = "«"; break;
+ case '\u00BB': app = "»"; break;
+ case '\u00A0': app = " "; break;
+
+ default :
+ //encode all non basic latin characters
+ app = "&#" + ((int)c) + ";";
+ break;
+ }
}
if (app != null)
{
if (sb == null)
{
- sb = new StringBuffer(string.substring(0, i));
+ sb = new StringBuilder(string.substring(0, i));
}
sb.append(app);
} else {
@@ -146,5 +148,130 @@
}
}
+ /**
+ * Variant of {@link #encode} where encodeNewline is false and encodeNbsp is true.
+ */
+ public static void encode (char[] string, int offset, int length, Writer writer) throws IOException
+ {
+ encode(string, offset, length, false, true, writer);
+ }
+
+ /**
+ * Variant of {@link #encode} where encodeNbsp is true.
+ */
+ public static void encode (char[] string, int offset, int length, boolean encodeNewline, Writer writer) throws IOException
+ {
+ encode(string, offset, length, encodeNewline, true, writer);
+ }
+
+ /**
+ * Variant of {@link #encode} where encodeNbsp and encodeNonLatin are true
+ */
+ public static void encode (char[] string, int offset, int length, boolean encodeNewline, boolean encodeSubsequentBlanksToNbsp, Writer writer) throws IOException
+ {
+ encode(string, offset, length, encodeNewline, encodeSubsequentBlanksToNbsp, true, writer);
+ }
+
+
+ /**
+ * Encodes the given string, so that it can be used within a html page.
+ * @param string the string to convert
+ * @param encodeNewline if true newline characters are converted to <br>'s
+ * @param encodeSubsequentBlanksToNbsp if true subsequent blanks are converted to &nbsp;'s
+ * @param encodeNonLatin if true encode non-latin characters as numeric character references
+ */
+ public static void encode (char[] string, int offset, int length,
+ boolean encodeNewline,
+ boolean encodeSubsequentBlanksToNbsp,
+ boolean encodeNonLatin, Writer writer) throws IOException
+ {
+ if (string == null || length < 0 || offset >= string.length)
+ {
+ return;
+ }
+ offset = Math.max(0, offset);
+ int realLength = Math.min(length, string.length - offset);
+
+ StringBuilder sb = null; //create later on demand
+ String app;
+ char c;
+
+ for (int i = offset; i < offset + realLength; ++i)
+ {
+ app = null;
+ c = string[i];
+
+ // All characters before letters
+ if ((int)c < 0x41)
+ {
+ switch (c)
+ {
+ case '"': app = """; break; //"
+ case '&': app = "&"; break; //&
+ case '<': app = "<"; break; //<
+ case '>': app = ">"; break; //>
+ case ' ':
+ if (encodeSubsequentBlanksToNbsp &&
+ (i == 0 || (i - 1 >= 0 && string[i - 1] == ' ')))
+ {
+ //Space at beginning or after another space
+ app = " ";
+ }
+ break;
+ case '\n':
+ if (encodeNewline)
+ {
+ app = "<br/>";
+ }
+ break;
+ }
+ } else if (encodeNonLatin && (int)c > 0x80) {
+ switch(c) {
+ //german umlauts
+ case '\u00E4' : app = "ä"; break;
+ case '\u00C4' : app = "Ä"; break;
+ case '\u00F6' : app = "ö"; break;
+ case '\u00D6' : app = "Ö"; break;
+ case '\u00FC' : app = "ü"; break;
+ case '\u00DC' : app = "Ü"; break;
+ case '\u00DF' : app = "ß"; break;
+
+ //misc
+ //case 0x80: app = "€"; break; sometimes euro symbol is ascii 128, should we suport it?
+ case '\u20AC': app = "€"; break;
+ case '\u00AB': app = "«"; break;
+ case '\u00BB': app = "»"; break;
+ case '\u00A0': app = " "; break;
+
+ default :
+ //encode all non basic latin characters
+ app = "&#" + ((int)c) + ";";
+ break;
+ }
+ }
+ if (app != null)
+ {
+ if (sb == null)
+ {
+ sb = new StringBuilder(realLength*2);
+ sb.append(string, offset, i - offset);
+ }
+ sb.append(app);
+ } else {
+ if (sb != null)
+ {
+ sb.append(c);
+ }
+ }
+ }
+ if (sb == null)
+ {
+ writer.write(string, offset, realLength);
+ }
+ else
+ {
+ writer.write(sb.toString());
+ }
+ }
}
Modified: myfaces/shared/branches/3_0_1/core/src/main/java/org/apache/myfaces/shared/renderkit/html/util/UnicodeEncoder.java
URL: http://svn.apache.org/viewvc/myfaces/shared/branches/3_0_1/core/src/main/java/org/apache/myfaces/shared/renderkit/html/util/UnicodeEncoder.java?rev=588578&r1=588577&r2=588578&view=diff
==============================================================================
--- myfaces/shared/branches/3_0_1/core/src/main/java/org/apache/myfaces/shared/renderkit/html/util/UnicodeEncoder.java (original)
+++ myfaces/shared/branches/3_0_1/core/src/main/java/org/apache/myfaces/shared/renderkit/html/util/UnicodeEncoder.java Fri Oct 26 02:19:56 2007
@@ -35,7 +35,7 @@
return "";
}
- StringBuffer sb = null;
+ StringBuilder sb = null;
char c;
for (int i = 0; i < string.length (); ++i)
{
@@ -43,11 +43,13 @@
if (((int)c) >= 0x80)
{
if( sb == null ){
- sb = new StringBuffer( string.length()+4 );
+ sb = new StringBuilder( string.length()+4 );
sb.append( string.substring(0,i) );
}
//encode all non basic latin characters
- sb.append("&#" + ((int)c) + ";");
+ sb.append("&#");
+ sb.append((int)c);
+ sb.append(";");
}
else if( sb != null )
{
Added: myfaces/shared/branches/3_0_1/core/src/test/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoderTest.java
URL: http://svn.apache.org/viewvc/myfaces/shared/branches/3_0_1/core/src/test/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoderTest.java?rev=588578&view=auto
==============================================================================
--- myfaces/shared/branches/3_0_1/core/src/test/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoderTest.java (added)
+++ myfaces/shared/branches/3_0_1/core/src/test/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoderTest.java Fri Oct 26 02:19:56 2007
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2007 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.myfaces.shared.renderkit.html.util;
+
+import java.io.CharArrayWriter;
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.shale.test.base.AbstractJsfTestCase;
+
+/**
+ * <code>HTMLEncoderTest</code> tests <code>org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder</code>.
+ *
+ * @author Michael Kurz (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ */
+public class HTMLEncoderTest extends AbstractJsfTestCase {
+ private String stringNoSpecialChars = "Hello, this is MyFaces speaking!";
+ private String stringNoSpecialCharsEncoded = "Hello, this is MyFaces speaking!";
+ private String stringNoSpecialCharsEncodedPartial = "lo, this is MyFaces speakin";
+ private String stringSpecialChars1 = "<\"Hello\", this is MyFaces speaking!>";
+ private String stringSpecialChars1Encoded = "<"Hello", this is MyFaces speaking!>";
+ private String stringSpecialChars2 = "Hello & this is MyFaces speaking!>";
+ private String stringSpecialChars2Encoded = "Hello & this is MyFaces speaking!>";
+ private String stringLineBreak = "Hell\u00F6\nthis is MyFaces speaking!>";
+ private String stringLineBreakEncoded1 = "Hellö<br/>this is MyFaces speaking!>";
+ private String stringLineBreakEncoded2 = "Hellö\nthis is MyFaces speaking!>";
+ private String stringLineBreakEncoded2Partial = "ö\nthis is MyFaces speaking!";
+ private String stringBlanks = "<Hello this is MyFaces speaking!>";
+ private String stringBlanksEncoded = "<Hello this is MyFaces speaking!>";
+
+ public HTMLEncoderTest(String name) {
+ super(name);
+ }
+
+ /**
+ * Test method for
+ * {@link org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder#encode(String)}.
+ */
+ public void testEncodeStringNoSpecialChars() {
+ String encodedStr = HTMLEncoder.encode(stringNoSpecialChars);
+ assertEquals(stringNoSpecialCharsEncoded, encodedStr);
+ }
+
+ public void testEncodeStringSpecialChars1() {
+ String encodedStr = HTMLEncoder.encode(stringSpecialChars1);
+ assertEquals(stringSpecialChars1Encoded, encodedStr);
+ }
+
+ public void testEncodeStringSpecialChars2() {
+ String encodedStr = HTMLEncoder.encode(stringSpecialChars2);
+ assertEquals(stringSpecialChars2Encoded, encodedStr);
+ }
+
+ public void testEncodeStringLineBreak1() {
+ String encodedStr = HTMLEncoder.encode(stringLineBreak, true);
+ assertEquals(stringLineBreakEncoded1, encodedStr);
+ }
+
+ public void testEncodeStringLineBreak2() {
+ String encodedStr = HTMLEncoder.encode(stringLineBreak, false);
+ assertEquals(stringLineBreakEncoded2, encodedStr);
+ }
+
+ public void testEncodeStringEmpty() {
+ String encodedStr = HTMLEncoder.encode("");
+ assertEquals("", encodedStr);
+ }
+
+ public void testEncodeStringNull() {
+ String encodedStr = HTMLEncoder.encode(null);
+ assertEquals("", encodedStr);
+ }
+
+ public void testEncodeArrayNoSpecialChars() {
+ try {
+ CharArrayWriter writer = new CharArrayWriter();
+ char[] source = stringNoSpecialChars.toCharArray();
+ HTMLEncoder.encode(source, 0, source.length, writer);
+ assertEquals(stringNoSpecialCharsEncoded.toCharArray(), writer.toCharArray());
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testEncodeArrayNoSpecialCharsPartial() {
+ try {
+ CharArrayWriter writer = new CharArrayWriter();
+ char[] source = stringNoSpecialChars.toCharArray();
+ HTMLEncoder.encode(source, 3, source.length - 5, writer);
+ assertEquals(stringNoSpecialCharsEncodedPartial.toCharArray(), writer.toCharArray());
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testEncodeArraySpecialChars1() {
+ try {
+ CharArrayWriter writer = new CharArrayWriter();
+ char[] source = stringSpecialChars1.toCharArray();
+ HTMLEncoder.encode(source, 0, source.length, writer);
+ assertEquals(stringSpecialChars1Encoded.toCharArray(), writer.toCharArray());
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testEncodeArraySpecialChars2() {
+ try {
+ CharArrayWriter writer = new CharArrayWriter();
+ char[] source = stringSpecialChars2.toCharArray();
+ HTMLEncoder.encode(source, 0, source.length, writer);
+ assertEquals(stringSpecialChars2Encoded.toCharArray(), writer.toCharArray());
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testEncodeArrayEmpty() {
+ try {
+ CharArrayWriter writer = new CharArrayWriter();
+ HTMLEncoder.encode(new char[]{}, 0, 1, writer);
+ assertEquals(new char[]{}, writer.toCharArray());
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testEncodeArrayNull() {
+ try {
+ CharArrayWriter writer = new CharArrayWriter();
+ HTMLEncoder.encode(null, 0, 0, writer);
+ assertEquals(new char[]{}, writer.toCharArray());
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testEncodeArrayWrongIndex1() {
+ try {
+ CharArrayWriter writer = new CharArrayWriter();
+ char[] source = stringSpecialChars2.toCharArray();
+ HTMLEncoder.encode(source, 0, source.length - 100, writer);
+ assertEquals(new char[]{}, writer.toCharArray());
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testEncodeArrayWrongIndex2() {
+ try {
+ CharArrayWriter writer = new CharArrayWriter();
+ char[] source = stringSpecialChars2.toCharArray();
+ HTMLEncoder.encode(source, -100, source.length, writer);
+ assertEquals(stringSpecialChars2Encoded.toCharArray(), writer.toCharArray());
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testEncodeArrayWrongIndex3() {
+ try {
+ CharArrayWriter writer = new CharArrayWriter();
+ char[] source = stringSpecialChars2.toCharArray();
+ HTMLEncoder.encode(source, 100000, source.length, writer);
+ assertEquals(new char[]{}, writer.toCharArray());
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testEncodeArrayLineBreak1() {
+ try {
+ CharArrayWriter writer = new CharArrayWriter();
+ char[] source = stringLineBreak.toCharArray();
+ HTMLEncoder.encode(source, 0, source.length, true, writer);
+ assertEquals(stringLineBreakEncoded1.toCharArray(), writer.toCharArray());
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testEncodeArrayLineBreak2() {
+ try {
+ CharArrayWriter writer = new CharArrayWriter();
+ char[] source = stringLineBreak.toCharArray();
+ HTMLEncoder.encode(source, 0, source.length, false, writer);
+ assertEquals(stringLineBreakEncoded2.toCharArray(), writer.toCharArray());
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testEncodeArrayLineBreak2WrongIndex() {
+ try {
+ CharArrayWriter writer = new CharArrayWriter();
+ char[] source = stringLineBreak.toCharArray();
+ HTMLEncoder.encode(source, 0, source.length + 5, false, writer);
+ assertEquals(stringLineBreakEncoded2.toCharArray(), writer.toCharArray());
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testEncodeArrayLineBreakPartial() {
+ try {
+ CharArrayWriter writer = new CharArrayWriter();
+ char[] source = stringLineBreak.toCharArray();
+ HTMLEncoder.encode(source, 4, source.length - 5, writer);
+ char[] expected = stringLineBreakEncoded2Partial.toCharArray();
+ assertEquals(expected, writer.toCharArray());
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ private void assertEquals(char[] expected, char[] actual) {
+ if ((expected == null ^ actual == null) || expected.length != actual.length) {
+ fail();
+ }
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals(expected[i], actual[i]);
+ }
+ }
+}
\ No newline at end of file