dev@javaserverfaces.java.net

Re: [REVIEW] JSF_1_1_ROLLING - Optimize Util's passthrough attribute handling

From: Ryan Lubke <Ryan.Lubke_at_Sun.COM>
Date: Thu, 26 Jan 2006 11:13:23 -0800

Disregard this. Taking a different approach.

Ryan Lubke wrote:
>
> ------------------------------------------------------------------------
>
> 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
>
>
>
>
> ------------------------------------------------------------------------
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe_at_javaserverfaces.dev.java.net
> For additional commands, e-mail: dev-help_at_javaserverfaces.dev.java.net
>