Inefficient way to create faces ben in FacesBeanFactory
-------------------------------------------------------

                 Key: TRINIDAD-773
                 URL: https://issues.apache.org/jira/browse/TRINIDAD-773
             Project: MyFaces Trinidad
          Issue Type: Bug
            Reporter: Stevan Malesevic


It seems that the way FacesBeanFactory::createFacesBean creates faces bean is 
were inefficient. The problem is that for the case where we have deep subclass 
structure and root class defines the bean we will make a numerouse calls to 
createFacesBean before we find out the type for the bean. This will burn the 
CPU and use memory to create all the keys. One possible optimization might be 
to create a map between ownerClass|rendererType and calss for the bean at the 
top level where the createFacesBean is called. So, next call will find it right 
away. I played with the dirty prototype for this and I was able to see memory 
improvement of about 140K per request (I have not measure CPU improvement).
The prototype I had looked like (were dirty but it works):

/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you 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.trinidad.bean;

import java.io.InputStream;
import java.io.IOException;
import java.net.URL;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.myfaces.trinidad.logging.TrinidadLogger;


/**
 * Base interface for FacesBean storage.
 *
 */
public class FacesBeanFactory
{
  /**
   * Create a FacesBean for a component class.
   */
  // TODO change from ownerClass to componentFamily?
  static public FacesBean createFacesBean(
    Class<?> ownerClass,
    String   rendererType)
  {
    if (ownerClass == null)
      return null;

    String className = ownerClass.getName();
    FacesBean bean = createFacesBean(className, rendererType);

    if (bean == null && rendererType != null)
    {
      bean = createFacesBean(className, null);
      
      if(bean != null)
      {
        String typeKey = (rendererType != null)
                            ? new 
StringBuilder(className).append("|").append(rendererType).toString()
                            : className;
        _TYPES_CLASS.put(typeKey, bean.getClass());
      }
    }
    
    if (bean == null)
    {
      bean = createFacesBean(ownerClass.getSuperclass(), rendererType);
      
      if(bean != null)
      {
        String typeKey = (rendererType != null)
                            ? new 
StringBuilder(className).append("|").append(rendererType).toString()
                            : className;
        _TYPES_CLASS.put(typeKey, bean.getClass());
      }
    }

    return bean;
  }

  static public FacesBean createFacesBean(
    String beanType,
    String rendererType)
  {
    String typeKey = (rendererType != null)
                        ? new 
StringBuilder(beanType).append("|").append(rendererType).toString()
                        : beanType;
    
    Class<?> type = _TYPES_CLASS.get(typeKey);
      
    if(type == null)
    {    
      String className = (String) _TYPES_MAP.get(typeKey);
      if (className == null)
        return null;
      
      try
      {
        type = _getClassLoader().loadClass(className);
        _TYPES_CLASS.put(typeKey, type);
      }
      catch (ClassNotFoundException cnfe)
      {
        _LOG.severe("CANNOT_FIND_FACESBEAN", className);
        _LOG.severe(cnfe);
      }
    }
  
    try
    {
      return (FacesBean) type.newInstance();
    }
    catch (IllegalAccessException iae)
    {
      _LOG.severe("CANNOT_CREATE_FACESBEAN_INSTANCE", type.getName());
      _LOG.severe(iae);
    }
    catch (InstantiationException ie)
    {
      _LOG.severe("CANNOT_CREATE_FACESBEAN_INSTANCE", type.getName());
      _LOG.severe(ie);
    }

    return null;
  }

  static private void _initializeBeanTypes()
  {
    _TYPES_MAP = new HashMap<Object, Object>();

    List<URL> list = new ArrayList<URL>();
    try
    {
      Enumeration<URL> en = _getClassLoader().getResources(
                                "META-INF/faces-bean.properties");
      while (en.hasMoreElements())
      {
        list.add(en.nextElement());
      }

      Collections.reverse(list);
    }
    catch (IOException ioe)
    {
      _LOG.severe(ioe);
      return;
    }

    if (list.isEmpty())
    {
      if (_LOG.isInfo())
        _LOG.info("NO_FACES_BEAN_PROPERTIES_FILES_LOCATED");
    }

    for(URL url : list)
    {
      _initializeBeanTypes(url);
    }
  }

  static private void _initializeBeanTypes(URL url)
  {
    try
    {
      Properties properties = new Properties();
      InputStream is = url.openStream();
      try
      {
        properties.load(is);
        if (_LOG.isFine())
          _LOG.fine("Loading bean factory info from " + url);
        
        _TYPES_MAP.putAll(properties);
      }
      finally
      {
        is.close();
      }
    }
    catch (IOException ioe)
    {
      _LOG.severe("CANNOT_LOAD_URL", url);
      _LOG.severe(ioe);
    }
  }


  static private ClassLoader _getClassLoader()
  {
    ClassLoader loader = Thread.currentThread().getContextClassLoader();
    if (loader == null)
      loader = FacesBeanFactory.class.getClassLoader();
    return loader;
  }

  static private final TrinidadLogger _LOG = 
TrinidadLogger.createTrinidadLogger(FacesBeanFactory.class);
  static private       Map<Object, Object> _TYPES_MAP;
  static private       Map<String, Class<?>> _TYPES_CLASS = new HashMap<String, 
Class<?>>();
  
  static
  {
    _initializeBeanTypes();
  }
}


-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to