Package org.ajax4jsf.renderkit.compiler

Source Code of org.ajax4jsf.renderkit.compiler.Signature2

/**
* License Agreement.
*
* Rich Faces - Natural Ajax for Java Server Faces (JSF)
*
* Copyright (C) 2007 Exadel, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
*/

package org.ajax4jsf.renderkit.compiler;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.faces.FacesException;
import javax.faces.el.MethodNotFoundException;

import org.ajax4jsf.Messages;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.SAXException;


/**
* @author asmirnov@exadel.com (latest modification by $Author: alexsmirnov $)
* @version $Revision: 1.1.2.1 $ $Date: 2007/01/09 18:57:47 $
*
*/
public  class MethodCallElement extends ElementBase {

  public static final String UTILS_PREFIX = "utils.";
 
  static final Log _log = LogFactory.getLog(MethodCallElement.class);

  private String _name = null;
 
  private List parameters = new ArrayList();
 
  private Invoker invoker = new Invoker();
 
  private MethodCacheState state = new MethodCacheState();
 
 
  /* (non-Javadoc)
   * @see org.ajax4jsf.renderkit.compiler.CompiledXML#encode(javax.faces.render.Renderer, javax.faces.context.FacesContext, javax.faces.component.UIComponent)
   */
  public void encode(TemplateContext context ) throws IOException {
      getValue(context);
  }

  /* (non-Javadoc)
   * @see org.ajax4jsf.renderkit.compiler.ElementBase#encode(org.ajax4jsf.renderkit.compiler.TemplateContext, java.lang.String)
   */
  public void encode(TemplateContext context, String breakPoint) throws IOException {
    // Text not contain breakpoints.
    encode(context);
  }
 
 
  public Object getValue(TemplateContext context) throws FacesException {
    // prepare method params. we attempt to call 3 signatures :
    // a) name(FacesContext,UIComponent [, param0...])
    // b) name(TempalateContext [,param0...])
    // c) name([param0...])
    state.init(parameters);
    Object[] values = state.computeParameterValues(context);
   
    InvokeData data = null;
    synchronized (state) {
      state.update(context, values, invoker);
      data = invoker.invokeMethod(context, state);
    }
    return invoker.invokeMethod(data);
    // perform childrens.
    // super.encode(renderer,context,component);
  }



  public void addParameter(MethodParameterElement parameter){
    parameters.add(parameter);
  }
  /**
   * @return Returns the methodName.
   */
  public String getName() {
    return _name;
  }

  /**
   * @param methodName The methodName to set.
   */
  public void setName(String methodName) {
    if(methodName.startsWith(UTILS_PREFIX)){
      this._name = methodName.substring(UTILS_PREFIX.length());
      this.invoker = getRendererUtilsInvoker(_name);
    } else if(methodName.indexOf('.') >= 0) {
      this._name = methodName;
      this.invoker = getStaticInvoker(_name);
    } else {
      this._name = methodName;
      this.invoker = getRendererInvoker(_name);
    }
  }

  static Map staticInvokers = new HashMap();
 
  public StaticInvoker getStaticInvoker(String methodName) {
    StaticInvoker invoker = (StaticInvoker)staticInvokers.get(methodName);
    if(invoker == null) {
      invoker = new StaticInvoker(methodName);
      staticInvokers.put(methodName, invoker);
    }
    return invoker;   
  }

  static Map rendererInvokers = new HashMap();
 
  public RendererInvoker getRendererInvoker(String methodName) {
    RendererInvoker invoker = (RendererInvoker)rendererInvokers.get(methodName);
    if(invoker == null) {
      invoker = new RendererInvoker(false, methodName);
      rendererInvokers.put(methodName, invoker);
    }
    return invoker;
  }
 
  static Map utilsInvokers = new HashMap();

  public RendererInvoker getRendererUtilsInvoker(String methodName) {
    RendererInvoker invoker = (RendererInvoker)utilsInvokers.get(methodName);
    if(invoker == null) {
      invoker = new RendererInvoker(true, methodName);
      utilsInvokers.put(methodName, invoker);
    }
    return invoker;
  }
 
  public String getTag() {
    return HtmlCompiler.NS_PREFIX+HtmlCompiler.CALL_TAG;
  }

 
  /* (non-Javadoc)
   * @see org.ajax4jsf.renderkit.compiler.ElementBase#setParent(org.ajax4jsf.renderkit.compiler.PreparedTemplate)
   */
  public void setParent(PreparedTemplate parent) throws SAXException {   
    super.setParent(parent);
    if (getName()==null) {
      throw new SAXException(Messages.getMessage(Messages.NO_NAME_ATTRIBUTE_ERROR, getTag()));
    }
  }

 
/* (non-Javadoc)
   * @see org.ajax4jsf.renderkit.compiler.ElementBase#getString(org.ajax4jsf.renderkit.compiler.TemplateContext)
   */
  public String getString(TemplateContext context) throws FacesException {
    Object result = getValue(context);
    if (null == result || result.toString().length()==0) {
        result = "";
    }
    return result.toString();
  }

  /* (non-Javadoc)
   * @see org.ajax4jsf.renderkit.compiler.ElementBase#getAllowedClasses()
   */
  protected Class[] getAllowedClasses() {
    // TODO Auto-generated method stub
    return new Class[]{
        MethodParameterElement.class,
        ResourceElement.class
    };
  }

}

class InvokeData {
  TemplateContext context;
  Method method;
  Object object;
  Object[] arguments;
  InvokeData(TemplateContext context, Method method, Object object, Object[] arguments) {
    this.context = context;
    this.method = method;
    this.object = object;
    this.arguments = (Object[]) arguments.clone();
  }
}

class Invoker {
  String methodName;

  InvokeData invokeMethod(TemplateContext context, MethodCacheState state) {
    throw new FacesException(Messages.getMessage(Messages.RENDERER_METHOD_NOT_SET_ERROR));
  }

  void handleInvocationTargetException(TemplateContext context, InvocationTargetException e) {}
  void handleIllegalAccessException(TemplateContext context, IllegalAccessException e) {}
  void handleMethodNotFoundException(TemplateContext context) throws MethodNotFoundException {}

  InvokeData invokeMethod(TemplateContext context, Map methods, Class cls, Object object, MethodCacheState state) {
    Method method = provideMethod(methods, cls, object, state);
    return new InvokeData(context, method, object, state.current.arguments);
  }
 
  Object invokeMethod(InvokeData data) {
    if(data.method != null) {
      try {
        return data.method.invoke(data.object, data.arguments);
      } catch (InvocationTargetException e) {
        handleInvocationTargetException(data.context, e);
      } catch (IllegalAccessException e) {
        handleIllegalAccessException(data.context, e);
      }
    }
    handleMethodNotFoundException(data.context);
    return null;
  }
 
  public Class getInvokedClass(TemplateContext context) {
    return null;
  }
 
  private Method provideMethod(Map methods, Class cls, Object object, MethodCacheState state) {
    if(state.method != null) return state.method;

    if(methods.size() > 0) {
      for (int i = 0; i < state.signatures.length; i++) {
        state.method = (Method)methods.get(getClassesKey(state.signatures[i].arguments));
        if(state.method != null) {
          state.current = state.signatures[i];
          return state.method;
        }
      }
    }
   
    if(cls == null && object != null) cls = object.getClass();
    Method[] ms = cls.getMethods();
    for (int m = 0; m < ms.length; m++) {
      if(!ms[m].getName().equals(methodName)) continue;
      if(object == null && !Modifier.isStatic(ms[m].getModifiers())) continue;
      Class[] cs = ms[m].getParameterTypes();
      Signature s = getMatchingArguments(cs, state.signatures);
      if(s == null) continue;
      state.current = s;
      state.method = ms[m];
      methods.put(getClassesKey(s.arguments), ms[m]);
      return state.method;
    }

    return null;
  }

  private String getClassesKey(Object[] args) {
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < args.length; i++) {
      String dk = args[i] == null ? "null" : args[i].getClass().getName();
      sb.append(";").append(dk);
    }
    return sb.toString();
  }
 
  private Signature getMatchingArguments(Class[] cs, Signature[] sgs) {
    for (int i = 0; i < sgs.length; i++) {
      if(isMatching(cs, sgs[i].arguments)) return sgs[i];
    }
    return null;
  }

  static boolean isMatching(Class[] cs, Object[] args) {
    if(cs.length != args.length) return false;
    for (int i = 0; i < cs.length; i++) {
      if(args[i] != null && !cs[i].isAssignableFrom(args[i].getClass())) return false;
    }
    return true;
  }
}

class RendererInvoker extends Invoker {
  boolean utils = false;
  Map renderers = new HashMap();
 
  public RendererInvoker(boolean utils, String methodName) {
    this.utils = utils;
    this.methodName = methodName;
  }

  public Class getInvokedClass(TemplateContext context) {
    Object object = getInvokedObject(context);
    return (object != null) ? object.getClass() : null;
  }
 
  private Object getInvokedObject(TemplateContext context) {
    if(utils) {
      return context.getRenderer().getUtils();
    } else {
      return context.getRenderer();
    }
  }
 
  InvokeData invokeMethod(TemplateContext context, MethodCacheState state) {
    Object object = getInvokedObject(context);
    Map methods = getMethods(object);
    return invokeMethod(context, methods, null, object, state);
  }
 
  private Map getMethods(Object object) {
    if(object == null) return null;
    Map methods = (Map)renderers.get(object);
    if(methods == null) {
      methods = new HashMap();
      renderers.put(object, methods);
    }
    return methods;
  }

  void handleInvocationTargetException(TemplateContext context, InvocationTargetException e) {
    String logMessage = (utils)
      ? Messages.getMessage(Messages.METHOD_CALL_ERROR_1, methodName, context.getComponent().getId())
      : Messages.getMessage(Messages.METHOD_CALL_ERROR_1a, methodName, context.getComponent().getId());
    String excMessage = (utils)
      ? Messages.getMessage(Messages.METHOD_CALL_ERROR_2, new Object[]{methodName, context.getComponent().getId(), e.getCause().getMessage()})
      : Messages.getMessage(Messages.METHOD_CALL_ERROR_2a, new Object[]{methodName, context.getComponent().getId(), e.getCause().getMessage()});
    MethodCallElement._log.error(logMessage, e);
    throw new FacesException(excMessage, e);
  }
  void handleIllegalAccessException(TemplateContext context, IllegalAccessException e) {
    String logMessage = (utils)
      ? Messages.getMessage(Messages.getMessage(Messages.METHOD_CALL_ERROR_3, methodName, context.getComponent().getId()))
      : Messages.getMessage(Messages.getMessage(Messages.METHOD_CALL_ERROR_3a, methodName, context.getComponent().getId()));
    String excMessage = (utils)
      ? Messages.getMessage(Messages.getMessage(Messages.METHOD_CALL_ERROR_4, new Object[]{methodName, context.getComponent().getId(), e.getCause().getMessage()}))
      : Messages.getMessage(Messages.getMessage(Messages.METHOD_CALL_ERROR_4a, new Object[]{methodName, context.getComponent().getId(), e.getCause().getMessage()}));
    MethodCallElement._log.error(logMessage, e);
    throw new FacesException(excMessage, e);
  }
 
  void handleMethodNotFoundException(TemplateContext context) throws MethodNotFoundException {
    String logMessage = (utils)
      ? Messages.getMessage(Messages.getMessage(Messages.METHOD_CALL_ERROR_5, methodName, context.getComponent().getId()))
      : Messages.getMessage(Messages.getMessage(Messages.METHOD_CALL_ERROR_5a, methodName, context.getComponent().getId()));
    String excMessage = (utils)
      ? Messages.getMessage(Messages.getMessage(Messages.METHOD_CALL_ERROR_6, methodName))
      : Messages.getMessage(Messages.getMessage(Messages.METHOD_CALL_ERROR_6a, methodName));
      MethodCallElement._log.error(logMessage);
    throw new FacesException(excMessage);
  }
}

class StaticInvoker extends Invoker {
  String className;
  Class cls;
  Map methods = new HashMap();
 
  StaticInvoker(String methodName) {
    this.methodName = methodName;
    int i = methodName.lastIndexOf('.');
    className = methodName.substring(0, i);
    this.methodName = methodName.substring(i + 1);
    try {
      cls = Thread.currentThread().getContextClassLoader().loadClass(className);
    } catch (ClassNotFoundException e) {
      //ignore, throw exception when invoking
    }
  }

  InvokeData invokeMethod(TemplateContext context, MethodCacheState state) {
    if(cls == null) throw new FacesException(className, new ClassNotFoundException(className));
    return invokeMethod(context, methods, cls, null, state);
  }

  void handleInvocationTargetException(TemplateContext context, InvocationTargetException e) {
    MethodCallElement._log.error(Messages.getMessage(Messages.METHOD_CALL_ERROR_1a, methodName, context.getComponent().getId()), e);
    throw new FacesException(Messages.getMessage(Messages.METHOD_CALL_ERROR_2a, new Object[]{methodName, context.getComponent().getId(), e.getCause().getMessage()}), e);
  }
  void handleIllegalAccessException(TemplateContext context, IllegalAccessException e) {
    MethodCallElement._log.error(Messages.getMessage(Messages.METHOD_CALL_ERROR_3a, methodName, context.getComponent().getId()), e);
    throw new FacesException(Messages.getMessage(Messages.METHOD_CALL_ERROR_4a, new Object[]{methodName, context.getComponent().getId(), e.getCause().getMessage()}), e);
  }   
  void handleMethodNotFoundException(TemplateContext context) throws MethodNotFoundException {
    MethodCallElement._log.error(Messages.getMessage(Messages.METHOD_CALL_ERROR_5a, methodName, context.getComponent().getId()));
    throw new MethodNotFoundException(Messages.getMessage(Messages.METHOD_CALL_ERROR_6a, methodName));
  }
}

class MethodCacheState {
  private MethodParameterElement[] elements;
  private Class[] parameterClasses;
  private Object[] parameterValues;
  private Class lastCallingClass = null;
  public Method method;
  public Signature current;
  public Signature[] signatures;
 
  public void init(List parameters) {
    if(elements != null) return;
    synchronized (this) {
      if(elements != null) return;
      int size = parameters.size();
      parameterClasses = new Class[size];
      parameterValues = new Object[size];
      signatures = new Signature[3];
      signatures[0] = new Signature2(size);
      signatures[1] = new Signature1(size);
      signatures[2] = new Signature0(size);   
      elements = (MethodParameterElement[])parameters.toArray(new MethodParameterElement[0]);
    }
  }
 
  public Object[] computeParameterValues(TemplateContext context) {
    Object[] ps = new Object[elements.length];
    for (int i = 0; i < elements.length; i++) {
      ps[i] = elements[i].valueGetter.getValueOrDefault(context);
    }
    return ps;
  }
 
  public void update(TemplateContext context, Object[] values, Invoker invoker) {
    boolean changed = false;
    for (int i = 0; i < elements.length; i++) {
      Object parametr = values[i];
      Class c = (parametr == null) ? null : parametr.getClass();
      if(c != parameterClasses[i]) {
        parameterClasses[i] = c;
        changed = true;
      }
      parameterValues[i] = parametr;     
    }
    if(method != null && !changed && lastCallingClass != invoker.getInvokedClass(context)) {
      lastCallingClass = invoker.getInvokedClass(context);
      changed = true;
    }
    if(changed || current == null) {
      for (int i = 0; i < signatures.length; i++) {
        signatures[i].update(context, parameterValues);
      }
      method = null;
      current = null;
    } else {
      current.update(context, parameterValues);
    }
  } 
 
}

abstract class Signature {
  Object[] arguments; 

  Signature() {}

  void update(TemplateContext context, Object[] parameters) {}
}

class Signature0 extends Signature {
  Signature0(int size) {
    arguments = new Object[size];
  }

  void update(TemplateContext context, Object[] parameters) {
    System.arraycopy(parameters, 0, arguments, 0, parameters.length);
  }
 
}

class Signature1 extends Signature {
  Signature1(int size) {
    arguments = new Object[size + 1];
  }
  void update(TemplateContext context, Object[] parameters) {
    arguments[0] = context;
    System.arraycopy(parameters, 0, arguments, 1, parameters.length);
  }
 
}

class Signature2 extends Signature {
  Signature2(int size) {
    arguments = new Object[size + 2];
  }
  void update(TemplateContext context, Object[] parameters) {
    arguments[0] = context.getFacesContext();
    arguments[1] = context.getComponent();
    System.arraycopy(parameters, 0, arguments, 2, parameters.length);
 
}
TOP

Related Classes of org.ajax4jsf.renderkit.compiler.Signature2

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.