Optimization of passthrough attribute handling
SECTION: Modified Files
----------------------------
M src/com/sun/faces/util/Util.java
- Updated hasPassThroughAttributes
and the two related rendering methods
* Instead of iterating through the attribute
arrays, obtain the entrySet() from the
AttributeMap and check to see if any of those
attributes qualify as passthrough.
* When profiling guessNumber hasPassThruAttributes
and renderPassThruAttributes has cumulative times
of 26ms and 10ms respectively. With change in place
time is negligible.
SECTION: Diffs
----------------------------
Index: src/com/sun/faces/util/Util.java
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/src/com/sun/faces/util/Util.java,v
retrieving revision 1.143.6.1.2.5
diff -u -r1.143.6.1.2.5 Util.java
--- src/com/sun/faces/util/Util.java 2 Dec 2005 17:17:36 -0000 1.143.6.1.2.5
+++ src/com/sun/faces/util/Util.java 26 Jan 2006 17:53:46 -0000
@@ -11,13 +11,6 @@
package com.sun.faces.util;
-import com.sun.faces.RIConstants;
-import com.sun.faces.el.impl.ExpressionEvaluator;
-import com.sun.faces.el.impl.ExpressionEvaluatorImpl;
-import com.sun.faces.renderkit.RenderKitImpl;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
import javax.faces.FacesException;
import javax.faces.FactoryFinder;
import javax.faces.application.Application;
@@ -28,8 +21,8 @@
import javax.faces.component.UIComponent;
import javax.faces.component.UISelectItem;
import javax.faces.component.UISelectItems;
-import javax.faces.context.FacesContext;
import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
import javax.faces.context.FacesContextFactory;
import javax.faces.context.ResponseWriter;
import javax.faces.convert.Converter;
@@ -43,19 +36,28 @@
import javax.faces.render.ResponseStateManager;
import javax.servlet.ServletContext;
-import java.io.IOException;
import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.Iterator;
-import java.util.Locale;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
-import java.util.HashMap;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.sun.faces.RIConstants;
+import com.sun.faces.el.impl.ExpressionEvaluator;
+import com.sun.faces.el.impl.ExpressionEvaluatorImpl;
+import com.sun.faces.renderkit.RenderKitImpl;
/**
* <B>Util</B> is a class ...
@@ -329,10 +331,10 @@
* @see renderBooleanPassthruAttributes
*/
- private static String booleanPassthruAttributes[] = {
+ private final static String[] BOOLEAN_PASS_THROUGH_ATTRIBUTES = {
"disabled",
+ "ismap",
"readonly",
- "ismap"
};
/**
@@ -344,7 +346,7 @@
*
* @see renderPassthruAttributes
*/
- private static String passthruAttributes[] = {
+ private final static String[] PASS_THROUGH_ATTRIBUTES = {
"accept",
"accesskey",
"alt",
@@ -395,11 +397,18 @@
"usemap",
"width"
};
+ static {
+ Arrays.sort(BOOLEAN_PASS_THROUGH_ATTRIBUTES);
+ Arrays.sort(PASS_THROUGH_ATTRIBUTES);
+ }
//NOTE - "type" was deliberately skipped from the list of passthru
//attrs above All renderers that need this attribute should manually
//pass it.
+ private static final Iterator EMPTY_ITERATOR =
+ Collections.EMPTY_LIST.iterator();
+
//
@@ -445,7 +454,7 @@
*/
public static synchronized String getExceptionMessageString(String messageId,
- Object params[]) {
+ Object params[]) {
String result = null;
FacesMessage message = MessageFactory.getMessage(messageId, params);
@@ -466,7 +475,7 @@
}
public static synchronized FacesMessage getExceptionMessage(String messageId,
- Object params[]) {
+ Object params[]) {
return MessageFactory.getMessage(messageId, params);
}
@@ -578,7 +587,7 @@
Boolean.FALSE);
throw new FacesException(
Util.getExceptionMessageString(Util.MISSING_CLASS_ERROR_MESSAGE_ID,
- params),
+ params),
e);
}
applicationMap.put(RIConstants.HAS_REQUIRED_CLASSES_ATTR, Boolean.TRUE);
@@ -600,59 +609,63 @@
public static Iterator getSelectItems(FacesContext context,
UIComponent component) {
- ArrayList list = new ArrayList();
- Iterator kids = component.getChildren().iterator();
- while (kids.hasNext()) {
- UIComponent kid = (UIComponent) kids.next();
- if (kid instanceof UISelectItem) {
- Object value = ((UISelectItem) kid).getValue();
- if (value == null) {
- UISelectItem item = (UISelectItem) kid;
- list.add(new SelectItem(item.getItemValue(),
- item.getItemLabel(),
- item.getItemDescription(),
- item.isItemDisabled()));
- } else if (value instanceof SelectItem) {
- list.add(value);
- } else {
- throw new IllegalArgumentException(Util.getExceptionMessageString(
- Util.CONVERSION_ERROR_MESSAGE_ID));
- }
- } else if (kid instanceof UISelectItems && null != context) {
- Object value = ((UISelectItems) kid).getValue();
- if (value instanceof SelectItem) {
- list.add(value);
- } else if (value instanceof SelectItem[]) {
- SelectItem items[] = (SelectItem[]) value;
- for (int i = 0; i < items.length; i++) {
- list.add(items[i]);
- }
- } else if (value instanceof Collection) {
- Iterator elements = ((Collection) value).iterator();
- while (elements.hasNext()) {
- list.add(elements.next());
+ if (component.getChildCount() > 0) {
+ ArrayList list = new ArrayList();
+ Iterator kids = component.getChildren().iterator();
+ while (kids.hasNext()) {
+ UIComponent kid = (UIComponent) kids.next();
+ if (kid instanceof UISelectItem) {
+ Object value = ((UISelectItem) kid).getValue();
+ if (value == null) {
+ UISelectItem item = (UISelectItem) kid;
+ list.add(new SelectItem(item.getItemValue(),
+ item.getItemLabel(),
+ item.getItemDescription(),
+ item.isItemDisabled()));
+ } else if (value instanceof SelectItem) {
+ list.add(value);
+ } else {
+ throw new IllegalArgumentException(Util.getExceptionMessageString(
+ Util.CONVERSION_ERROR_MESSAGE_ID));
}
- } else if (value instanceof Map) {
- Iterator keys = ((Map) value).keySet().iterator();
- while (keys.hasNext()) {
- Object key = keys.next();
- if (key == null) {
- continue;
+ } else if (kid instanceof UISelectItems && null != context) {
+ Object value = ((UISelectItems) kid).getValue();
+ if (value instanceof SelectItem) {
+ list.add(value);
+ } else if (value instanceof SelectItem[]) {
+ SelectItem items[] = (SelectItem[]) value;
+ for (int i = 0; i < items.length; i++) {
+ list.add(items[i]);
+ }
+ } else if (value instanceof Collection) {
+ Iterator elements = ((Collection) value).iterator();
+ while (elements.hasNext()) {
+ list.add(elements.next());
}
- Object val = ((Map) value).get(key);
- if (val == null) {
- continue;
+ } else if (value instanceof Map) {
+ Iterator keys = ((Map) value).keySet().iterator();
+ while (keys.hasNext()) {
+ Object key = keys.next();
+ if (key == null) {
+ continue;
+ }
+ Object val = ((Map) value).get(key);
+ if (val == null) {
+ continue;
+ }
+ list.add(new SelectItem(val.toString(),
+ key.toString(),
+ null));
}
- list.add(new SelectItem(val.toString(), key.toString(),
- null));
+ } else {
+ throw new IllegalArgumentException(Util.getExceptionMessageString(
+ Util.CONVERSION_ERROR_MESSAGE_ID));
}
- } else {
- throw new IllegalArgumentException(Util.getExceptionMessageString(
- Util.CONVERSION_ERROR_MESSAGE_ID));
}
}
+ return (list.iterator());
}
- return (list.iterator());
+ return EMPTY_ITERATOR;
}
@@ -718,45 +731,31 @@
/**
* @return true if the component has any passthru attributes
- */
- // PENDING() it would be much more performant to have the tag be
- // aware of the passthru attributes and have it set a
- // "hasPassthruAttributes" attribute to true if the component has
- // any.
-
+ */
public static boolean hasPassThruAttributes(UIComponent component) {
if (null == component) {
return false;
}
-
- boolean result = false;
+
Map attrs = component.getAttributes();
- if (null == attrs) {
+ if (attrs.size() == 0) {
return false;
}
- int i = 0;
- Object attrVal;
- String empty = "";
- for (i = 0; i < passthruAttributes.length; i++) {
- if (null != (attrVal = attrs.get(passthruAttributes[i]))
- &&
- !empty.equals(attrVal)) {
- result = true;
- break;
- }
- }
- if (!result) {
- for (i = 0; i < booleanPassthruAttributes.length; i++) {
- if (null !=
- (attrVal = attrs.get(booleanPassthruAttributes[i]))
- &&
- !empty.equals(attrVal)) {
- result = true;
- break;
- }
+
+ // compare attribute map keys
+ String[] keys =
+ (String[]) attrs.keySet().toArray(new String[attrs.size()]);
+
+
+ for (int i = 0; i < keys.length; i++) {
+ if (Arrays.binarySearch(PASS_THROUGH_ATTRIBUTES, keys[i]) > -1
+ || Arrays.binarySearch(BOOLEAN_PASS_THROUGH_ATTRIBUTES, keys[i]) > -1)
+ {
+ return true;
}
}
- return result;
+
+ return false;
}
@@ -771,53 +770,37 @@
* Render any boolean "passthru" attributes.
* <P>
*
- * @see passthruAttributes
+ * @see #BOOLEAN_PASS_THROUGH_ATTRIBUTES
*/
public static void renderBooleanPassThruAttributes(ResponseWriter writer,
UIComponent component,
String[] excludes)
throws IOException {
Util.doAssert(null != writer);
- Util.doAssert(null != component);
+ Util.doAssert(null != component);
+
+ Map attrs = component.getAttributes();
+
+ if (attrs.size() == 0) {
+ return;
+ }
+
+ if (excludes != null && excludes.length != 0) {
+ Arrays.sort(excludes);
+ }
- int i = 0, len = booleanPassthruAttributes.length, j,
- jLen = (null != excludes ? excludes.length : 0);
- Object value = null;
- boolean result;
- boolean skip = false;
- for (i = 0; i < len; i++) {
- skip = false;
- if (null != excludes) {
- for (j = 0; j < jLen; j++) {
- if (null != excludes[j] &&
- excludes[j].equals(booleanPassthruAttributes[i])) {
- skip = true;
- break;
- }
- }
- }
- if (skip) {
+ for (Iterator i = attrs.entrySet().iterator(); i.hasNext();) {
+ Map.Entry entry = (Map.Entry) i.next();
+ String key = (String) entry.getKey();
+
+ if (excludes != null && Arrays.binarySearch(excludes, key) > -1) {
continue;
}
- value =
- component.getAttributes().get(booleanPassthruAttributes[i]);
- if (value != null) {
- if (value instanceof Boolean) {
- result = ((Boolean) value).booleanValue();
- } else {
- if (!(value instanceof String)) {
- value = value.toString();
- }
- result = (new Boolean((String) value)).booleanValue();
- }
- //PENDING(rogerk) will revisit "null" param soon..
- if (result) {
- // NOTE: render things like readonly="readonly" here
- writer.writeAttribute(booleanPassthruAttributes[i],
- booleanPassthruAttributes[i],
- booleanPassthruAttributes[i]);
- // NOTE: otherwise render nothing
+ if (Arrays.binarySearch(BOOLEAN_PASS_THROUGH_ATTRIBUTES, key) > -1) {
+ if (Boolean.valueOf(entry.getValue().toString()).booleanValue())
+ {
+ writer.writeAttribute(key, key, key);
}
}
}
@@ -837,7 +820,7 @@
* set of HTML4 attributes that fall into this bucket. Examples are
* all the javascript attributes, alt, rows, cols, etc. <P>
*
- * @see passthruAttributes
+ * @see #PASS_THROUGH_ATTRIBUTES
*/
public static void renderPassThruAttributes(ResponseWriter writer,
UIComponent component,
@@ -845,34 +828,30 @@
throws IOException {
Util.doAssert(null != writer);
Util.doAssert(null != component);
+
+ Map attrs = component.getAttributes();
+
+ if (attrs.size() == 0) {
+ return;
+ }
+
+ if (excludes != null && excludes.length != 0) {
+ Arrays.sort(excludes);
+ }
- int i = 0, len = passthruAttributes.length, j,
- jLen = (null != excludes ? excludes.length : 0);
- Object value = null;
- boolean skip = false;
- for (i = 0; i < len; i++) {
- skip = false;
- if (null != excludes) {
- for (j = 0; j < jLen; j++) {
- if (null != excludes[j] &&
- excludes[j].equals(passthruAttributes[i])) {
- skip = true;
- break;
- }
- }
- }
- if (skip) {
+ for (Iterator i = attrs.entrySet().iterator(); i.hasNext();) {
+ Map.Entry entry = (Map.Entry) i.next();
+ String key = (String) entry.getKey();
+
+ if (excludes != null && Arrays.binarySearch(excludes, key) > -1) {
continue;
}
- value = component.getAttributes().get(passthruAttributes[i]);
- if (value != null && shouldRenderAttribute(value)) {
- if (!(value instanceof String)) {
- value = value.toString();
+ if (Arrays.binarySearch(BOOLEAN_PASS_THROUGH_ATTRIBUTES, key) > -1) {
+ Object value = entry.getValue();
+ if (value != null && shouldRenderAttribute(value)) {
+ writer.writeAttribute(key, value.toString(), key);
}
- //PENDING(rogerk) will revisit "null" param soon..
- writer.writeAttribute(passthruAttributes[i], value,
- passthruAttributes[i]);
}
}
}
@@ -891,25 +870,25 @@
Boolean.FALSE.booleanValue()) {
return false;
} else if (attributeVal instanceof Integer &&
- ((Integer) attributeVal).intValue() == Integer.MIN_VALUE) {
+ ((Integer) attributeVal).intValue() == Integer.MIN_VALUE) {
return false;
} else if (attributeVal instanceof Double &&
- ((Double) attributeVal).doubleValue() == Double.MIN_VALUE) {
+ ((Double) attributeVal).doubleValue() == Double.MIN_VALUE) {
return false;
} else if (attributeVal instanceof Character &&
- ((Character) attributeVal).charValue() == Character.MIN_VALUE) {
+ ((Character) attributeVal).charValue() == Character.MIN_VALUE) {
return false;
} else if (attributeVal instanceof Float &&
- ((Float) attributeVal).floatValue() == Float.MIN_VALUE) {
+ ((Float) attributeVal).floatValue() == Float.MIN_VALUE) {
return false;
} else if (attributeVal instanceof Short &&
- ((Short) attributeVal).shortValue() == Short.MIN_VALUE) {
+ ((Short) attributeVal).shortValue() == Short.MIN_VALUE) {
return false;
} else if (attributeVal instanceof Byte &&
- ((Byte) attributeVal).byteValue() == Byte.MIN_VALUE) {
+ ((Byte) attributeVal).byteValue() == Byte.MIN_VALUE) {
return false;
} else if (attributeVal instanceof Long &&
- ((Long) attributeVal).longValue() == Long.MIN_VALUE) {
+ ((Long) attributeVal).longValue() == Long.MIN_VALUE) {
return false;
}
return true;
@@ -1092,10 +1071,10 @@
Map requestMap = context.getExternalContext().getRequestMap();
RenderKitFactory factory = (RenderKitFactory)
requestMap.get(RENDER_KIT_IMPL_REQ);
- if (factory != null) {
+ if (factory != null) {
renderKit = factory.getRenderKit(context, renderKitId);
- } else {
- factory = (RenderKitFactory)
+ } else {
+ factory = (RenderKitFactory)
FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
if (factory == null) {
throw new IllegalStateException();
@@ -1105,7 +1084,7 @@
renderKit = factory.getRenderKit(context, renderKitId);
}
}
-
+
return renderKit.getResponseStateManager();
}
@@ -1303,7 +1282,7 @@
}
return expression;
}
-
+
//
// General Methods
//
@@ -1352,12 +1331,12 @@
* @return the scope of the expression
*/
public static String getScope(String valueBinding,
- String [] outString) throws ReferenceSyntaxException {
+ String [] outString) throws ReferenceSyntaxException {
if (valueBinding == null || 0 == valueBinding.length()) {
return null;
}
- valueBinding = stripBracketsIfNecessary(valueBinding);
-
+ valueBinding = stripBracketsIfNecessary(valueBinding);
+
int segmentIndex = getFirstSegmentIndex(valueBinding);
//examine first segment and see if it is a scope
@@ -1365,17 +1344,17 @@
if (segmentIndex > 0) {
//get first segment designated by a "." or "["
- identifier = valueBinding.substring(0, segmentIndex);
+ identifier = valueBinding.substring(0, segmentIndex);
}
//check to see if the identifier is a named scope.
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext ec = context.getExternalContext();
-
- if (null != outString) {
- outString[0] = identifier;
- }
+
+ if (null != outString) {
+ outString[0] = identifier;
+ }
if (identifier.equalsIgnoreCase(RIConstants.REQUEST_SCOPE)) {
return RIConstants.REQUEST;
}
@@ -1386,30 +1365,30 @@
return RIConstants.APPLICATION;
}
- // handle implicit objects
+ // handle implicit objects
if (identifier.equalsIgnoreCase(RIConstants.INIT_PARAM_IMPLICIT_OBJ)) {
- return RIConstants.APPLICATION;
- }
+ return RIConstants.APPLICATION;
+ }
if (identifier.equalsIgnoreCase(RIConstants.COOKIE_IMPLICIT_OBJ)) {
- return RIConstants.REQUEST;
- }
+ return RIConstants.REQUEST;
+ }
if (identifier.equalsIgnoreCase(RIConstants.FACES_CONTEXT_IMPLICIT_OBJ)) {
- return RIConstants.REQUEST;
- }
+ return RIConstants.REQUEST;
+ }
if (identifier.equalsIgnoreCase(RIConstants.HEADER_IMPLICIT_OBJ)) {
- return RIConstants.REQUEST;
- }
+ return RIConstants.REQUEST;
+ }
if (identifier.equalsIgnoreCase(RIConstants.HEADER_VALUES_IMPLICIT_OBJ)) {
- return RIConstants.REQUEST;
+ return RIConstants.REQUEST;
}
if (identifier.equalsIgnoreCase(RIConstants.PARAM_IMPLICIT_OBJ)) {
- return RIConstants.REQUEST;
+ return RIConstants.REQUEST;
}
if (identifier.equalsIgnoreCase(RIConstants.PARAM_VALUES_IMPLICIT_OBJ)) {
- return RIConstants.REQUEST;
+ return RIConstants.REQUEST;
}
if (identifier.equalsIgnoreCase(RIConstants.VIEW_IMPLICIT_OBJ)) {
- return RIConstants.REQUEST;
+ return RIConstants.REQUEST;
}
//No scope was provided in the expression so check for the
@@ -1438,20 +1417,20 @@
*/
public static List getExpressionsFromString(String expressionString) throws ReferenceSyntaxException {
- if (null == expressionString) {
- return Collections.EMPTY_LIST;
- }
- List result = new ArrayList();
- int i, j, len = expressionString.length(), cur = 0;
- while (cur < len &&
- -1 != (i = expressionString.indexOf("#{", cur))) {
- if (-1 == (j = expressionString.indexOf("}", i + 2))) {
- throw new ReferenceSyntaxException(Util.getExceptionMessageString(Util.INVALID_EXPRESSION_ID, new Object[]{expressionString}));
- }
- cur = j + 1;
- result.add(expressionString.substring(i, cur));
- }
- return result;
+ if (null == expressionString) {
+ return Collections.EMPTY_LIST;
+ }
+ List result = new ArrayList();
+ int i, j, len = expressionString.length(), cur = 0;
+ while (cur < len &&
+ -1 != (i = expressionString.indexOf("#{", cur))) {
+ if (-1 == (j = expressionString.indexOf("}", i + 2))) {
+ throw new ReferenceSyntaxException(Util.getExceptionMessageString(Util.INVALID_EXPRESSION_ID, new Object[]{expressionString}));
+ }
+ cur = j + 1;
+ result.add(expressionString.substring(i, cur));
+ }
+ return result;
}
/**
@@ -1488,17 +1467,17 @@
* @return the String representation ofthe stack trace obtained by
* calling getStackTrace() on the passed in exception. If null is
* passed in, we return the empty String.
- */
+ */
public static String getStackTraceString(Throwable e) {
- if (null == e) {
- return "";
- }
-
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- PrintStream ps = new PrintStream(baos);
- e.printStackTrace(ps);
- return baos.toString();
+ if (null == e) {
+ return "";
+ }
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ PrintStream ps = new PrintStream(baos);
+ e.printStackTrace(ps);
+ return baos.toString();
}
} // end of class Util